1use super::{as_tbl, coalition::Side, controller::Controller, cvt_err, unit::Unit, String};
15use crate::{
16 env::miz::{GroupId, GroupKind},
17 object::{DcsObject, DcsOid, Object},
18 simple_enum, wrapped_table, LuaEnv, MizLua, Sequence,
19};
20use anyhow::{Result, bail};
21use mlua::{prelude::*, Value};
22use serde_derive::{Deserialize, Serialize};
23use std::{marker::PhantomData, ops::Deref};
24
25simple_enum!(GroupCategory, u8, [
26 Airplane => 0,
27 Helicopter => 1,
28 Ground => 2,
29 Ship => 3,
30 Train => 4
31]);
32
33impl GroupCategory {
34 pub fn from_kind(k: GroupKind) -> Option<Self> {
35 match k {
36 GroupKind::Any | GroupKind::Static => None,
37 GroupKind::Plane => Some(Self::Airplane),
38 GroupKind::Helicopter => Some(Self::Helicopter),
39 GroupKind::Vehicle => Some(Self::Ground),
40 GroupKind::Ship => Some(Self::Ship),
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize)]
46pub enum Owner {
47 Contested,
48 Side(Side),
49}
50
51impl<'lua> FromLua<'lua> for Owner {
52 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> LuaResult<Self> {
53 match i64::from_lua(value.clone(), lua)? {
54 3 => Ok(Self::Contested),
55 _ => Ok(Owner::Side(Side::from_lua(value, lua)?)),
56 }
57 }
58}
59
60wrapped_table!(Group, Some("Group"));
61
62impl<'lua> Group<'lua> {
63 pub fn get_by_name(lua: MizLua<'lua>, name: &str) -> Result<Group<'lua>> {
64 let globals = lua.inner().globals();
65 let class = as_tbl("Group", None, globals.raw_get("Group")?)?;
66 let g: Group = class.call_function("getByName", name)?;
67 if g.get_size()? == 0 {
70 bail!("{} is dead", name)
71 }
72 Ok(g)
73 }
74
75 pub fn is_exist(&self) -> Result<bool> {
76 Ok(self.t.call_method("isExist", ())?)
77 }
78
79 pub fn destroy(self) -> Result<()> {
80 Ok(self.t.call_method("destroy", ())?)
81 }
82
83 pub fn activate(&self) -> Result<()> {
84 Ok(self.t.call_method("activate", ())?)
85 }
86
87 pub fn get_category(&self) -> Result<GroupCategory> {
88 Ok(self.t.call_method("getCategory", ())?)
89 }
90
91 pub fn get_coalition(&self) -> Result<Owner> {
92 Ok(self.t.call_method("getCoalition", ())?)
93 }
94
95 pub fn get_name(&self) -> Result<String> {
96 Ok(self.t.call_method("getName", ())?)
97 }
98
99 pub fn id(&self) -> Result<GroupId> {
100 Ok(self.t.call_method("getID", ())?)
101 }
102
103 pub fn get_size(&self) -> Result<i64> {
104 Ok(self.t.call_method("getSize", ())?)
105 }
106
107 pub fn get_initial_size(&self) -> Result<i64> {
108 Ok(self.t.call_method("getInitialSize", ())?)
109 }
110
111 pub fn get_unit(&self, index: usize) -> Result<Unit<'lua>> {
112 Ok(self.t.call_method("getUnit", index)?)
113 }
114
115 pub fn get_units(&self) -> Result<Sequence<'lua, Unit<'lua>>> {
116 Ok(self.t.call_method("getUnits", ())?)
117 }
118
119 pub fn get_controller(&self) -> Result<Controller<'lua>> {
120 Ok(self.t.call_method("getController", ())?)
121 }
122
123 pub fn enable_emission(&self, on: bool) -> Result<()> {
124 Ok(self.t.call_method("enableEmission", on)?)
125 }
126
127 pub fn as_object(&self) -> Result<Object<'lua>> {
128 Ok(Object::from_lua(Value::Table(self.t.clone()), self.lua)?)
129 }
130}
131
132#[derive(Debug, Clone)]
133pub struct ClassGroup;
134
135impl<'lua> DcsObject<'lua> for Group<'lua> {
136 type Class = ClassGroup;
137
138 fn get_instance(lua: MizLua<'lua>, id: &DcsOid<Self::Class>) -> Result<Self> {
139 let t = lua.inner().create_table()?;
140 t.set_metatable(Some(lua.inner().globals().raw_get(&**id.class)?));
141 t.raw_set("id_", id.id)?;
142 let t = Group {
143 t,
144 lua: lua.inner(),
145 };
146 if !t.is_exist()? {
147 bail!("{} is an invalid group", id.id)
148 }
149 if t.get_size()? == 0 {
152 bail!("{} is dead", id.id)
153 }
154 Ok(t)
155 }
156
157 fn get_instance_dyn<T>(lua: MizLua<'lua>, id: &DcsOid<T>) -> Result<Self> {
158 id.check_implements(lua, "Group")?;
159 let id = DcsOid {
160 id: id.id,
161 class: id.class.clone(),
162 t: PhantomData,
163 };
164 Self::get_instance(lua, &id)
165 }
166
167 fn change_instance(self, id: &DcsOid<Self::Class>) -> Result<Self> {
168 self.raw_set("id_", id.id)?;
169 if !self.is_exist()? {
170 bail!("{} is an invalid group", id.id)
171 }
172 if self.get_size()? == 0 {
175 bail!("{} is dead", id.id)
176 }
177 Ok(self)
178 }
179
180 fn change_instance_dyn<T>(self, id: &DcsOid<T>) -> Result<Self> {
181 id.check_implements(MizLua(self.lua), "Group")?;
182 self.t.raw_set("id_", id.id)?;
183 if !self.is_exist()? {
184 bail!("{} is an invalid group", id.id)
185 }
186 if self.get_size()? == 0 {
189 bail!("{} is dead", id.id)
190 }
191 Ok(self)
192 }
193}