1use crate::{
15 as_tbl, atomic_id,
16 coalition::Side,
17 cvt_err,
18 env::miz::{Country, GroupId, UnitId},
19 simple_enum, wrapped_table, Color, LuaEnv, LuaVec3, MizLua, String,
20};
21use anyhow::Result;
22use mlua::{prelude::*, Value};
23use serde_derive::{Deserialize, Serialize};
24use std::ops::Deref;
25
26atomic_id!(MarkId);
27
28#[derive(Debug, Clone, Copy, PartialEq)]
29pub struct Zone {
30 pub point: LuaVec3,
31 pub radius: f64,
32}
33
34impl<'lua> FromLua<'lua> for Zone {
35 fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> LuaResult<Self> {
36 match value {
37 Value::Table(tbl) => Ok(Self {
38 point: tbl.raw_get("point")?,
39 radius: tbl.raw_get("radius")?,
40 }),
41 _ => Err(cvt_err("trigger::Zone")),
42 }
43 }
44}
45
46impl<'lua> IntoLua<'lua> for Zone {
47 fn into_lua(self, lua: &'lua Lua) -> LuaResult<Value<'lua>> {
48 let table = lua.create_table()?;
49 table.raw_set("point", self.point)?;
50 table.raw_set("radius", self.radius)?;
51 Ok(Value::Table(table))
52 }
53}
54
55simple_enum!(SmokeColor, u8, [
56 Green => 0,
57 Red => 1,
58 White => 2,
59 Orange => 3,
60 Blue => 4
61]);
62
63simple_enum!(SmokePreset, u8, [
64 SmallSmokeAndFire => 1,
65 MediumSmokeAndFire => 2,
66 LargeSmokeAndFire => 3,
67 HugeSmokeAndFire => 4,
68 SmallSmoke => 5,
69 MediumSmoke => 6,
70 LargeSmoke => 7,
71 HugeSmoke => 8
72]);
73
74simple_enum!(FlareColor, u8, [
75 Green => 0,
76 Red => 1,
77 White => 2,
78 Yellow => 3
79]);
80
81simple_enum!(Modulation, u8, [
82 AM => 0,
83 FM => 1
84]);
85
86simple_enum!(SideFilter, i8, [
87 All => -1,
88 Neutral => 0,
89 Red => 1,
90 Blue => 2
91]);
92
93impl SideFilter {
94 pub fn is_match(&self, side: &Side) -> bool {
95 match (self, side) {
96 (Self::All, _) => true,
97 (Self::Neutral, Side::Neutral) => true,
98 (Self::Blue, Side::Blue) => true,
99 (Self::Red, Side::Red) => true,
100 (_, _) => false
101 }
102 }
103}
104
105impl From<Side> for SideFilter {
106 fn from(value: Side) -> Self {
107 match value {
108 Side::Blue => SideFilter::Blue,
109 Side::Red => SideFilter::Red,
110 Side::Neutral => SideFilter::Neutral,
111 }
112 }
113}
114
115simple_enum!(LineType, u8, [
116 NoLine => 0,
117 Solid => 1,
118 Dashed => 2,
119 Dotted => 3,
120 DotDash => 4,
121 LongDash => 5,
122 TwoDash => 6
123]);
124
125#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
126pub struct LineSpec {
127 pub start: LuaVec3,
128 pub end: LuaVec3,
129 pub color: Color,
130 pub line_type: LineType,
131 pub read_only: bool,
132}
133
134#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
135pub struct CircleSpec {
136 pub center: LuaVec3,
137 pub radius: f64,
138 pub color: Color,
139 pub fill_color: Color,
140 pub line_type: LineType,
141 pub read_only: bool,
142}
143
144#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
145pub struct RectSpec {
146 pub start: LuaVec3,
147 pub end: LuaVec3,
148 pub color: Color,
149 pub fill_color: Color,
150 pub line_type: LineType,
151 pub read_only: bool,
152}
153
154#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
155pub struct QuadSpec {
156 pub p0: LuaVec3,
157 pub p1: LuaVec3,
158 pub p2: LuaVec3,
159 pub p3: LuaVec3,
160 pub color: Color,
161 pub fill_color: Color,
162 pub line_type: LineType,
163 pub read_only: bool,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct TextSpec {
168 pub pos: LuaVec3,
169 pub color: Color,
170 pub fill_color: Color,
171 pub font_size: u8,
172 pub read_only: bool,
173 pub text: String,
174}
175
176#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
177pub struct ArrowSpec {
178 pub start: LuaVec3,
179 pub end: LuaVec3,
180 pub color: Color,
181 pub fill_color: Color,
182 pub line_type: LineType,
183 pub read_only: bool,
184}
185
186wrapped_table!(Action, None);
187
188impl<'lua> Action<'lua> {
189 pub fn set_user_flag<K: IntoLua<'lua>, V: IntoLua<'lua>>(
190 &self,
191 key: K,
192 value: V,
193 ) -> Result<()> {
194 Ok(self.call_function("setUserFlag", (key, value))?)
195 }
196
197 pub fn set_ai_task(&self, group: GroupId, num: i64) -> Result<()> {
198 Ok(self.call_function("setAITask", (group, num))?)
199 }
200
201 pub fn explosion(&self, position: LuaVec3, power: f32) -> Result<()> {
202 Ok(self.call_function("explosion", (position, power))?)
203 }
204
205 pub fn smoke(&self, position: LuaVec3, color: SmokeColor) -> Result<()> {
206 Ok(self.call_function("smoke", (position, color))?)
207 }
208
209 pub fn effect_smoke_big(
210 &self,
211 position: LuaVec3,
212 preset: SmokePreset,
213 density: f32,
214 name: String,
215 ) -> Result<()> {
216 Ok(self.call_function("effectSmokeBig", (position, preset, density, name))?)
217 }
218
219 pub fn effect_smoke_stop(&self, name: String) -> Result<()> {
220 Ok(self.call_function("effectSmokeStop", name)?)
221 }
222
223 pub fn illumination_bomb(&self, position: LuaVec3, power: f32) -> Result<()> {
224 Ok(self.call_function("illuminationBomb", (position, power))?)
225 }
226
227 pub fn signal_flare(&self, position: LuaVec3, color: FlareColor, azimuth: u16) -> Result<()> {
228 Ok(self.call_function("signalFlare", (position, color, azimuth))?)
229 }
230
231 pub fn radio_transmission(
232 &self,
233 file: String,
234 origin: LuaVec3,
235 modulation: Modulation,
236 repeat: bool,
237 frequency: u64,
238 power: u64,
239 name: String,
240 ) -> Result<()> {
241 Ok(self.call_function(
242 "radioTransmission",
243 (file, origin, modulation, repeat, frequency, power, name),
244 )?)
245 }
246
247 pub fn stop_transmission(&self, name: String) -> Result<()> {
248 Ok(self.call_function("stopRadioTransmission", name)?)
249 }
250
251 pub fn set_unit_internal_cargo(&self, unit_name: String, mass: i64) -> Result<()> {
252 Ok(self.call_function("setUnitInternalCargo", (unit_name, mass))?)
253 }
254
255 pub fn out_sound(&self, file: String) -> Result<()> {
256 Ok(self.call_function("outSound", file)?)
257 }
258
259 pub fn out_sound_for_coalition(&self, side: Side, file: String) -> Result<()> {
260 Ok(self.call_function("outSoundForCoalition", (side, file))?)
261 }
262
263 pub fn out_sound_for_country(&self, country: Country, file: String) -> Result<()> {
264 Ok(self.call_function("outSoundForCountry", (country, file))?)
265 }
266
267 pub fn out_sound_for_group(&self, group: GroupId, file: String) -> Result<()> {
268 Ok(self.call_function("outSoundForGroup", (group, file))?)
269 }
270
271 pub fn out_sound_for_unit(&self, unit: UnitId, file: String) -> Result<()> {
272 Ok(self.call_function("outSoundForUnit", (unit, file))?)
273 }
274
275 pub fn out_text(&self, text: String, display_time: i64, clear_view: bool) -> Result<()> {
276 Ok(self.call_function("outText", (text, display_time, clear_view))?)
277 }
278
279 pub fn out_text_for_coalition(
280 &self,
281 side: Side,
282 text: String,
283 display_time: i64,
284 clear_view: bool,
285 ) -> Result<()> {
286 Ok(self.call_function(
287 "outTextForCoalition",
288 (side, text, display_time, clear_view),
289 )?)
290 }
291
292 pub fn out_text_for_country(
293 &self,
294 country: Country,
295 text: String,
296 display_time: i64,
297 clear_view: bool,
298 ) -> Result<()> {
299 Ok(self.call_function(
300 "outTextForCountry",
301 (country, text, display_time, clear_view),
302 )?)
303 }
304
305 pub fn out_text_for_group(
306 &self,
307 group: GroupId,
308 text: String,
309 display_time: i64,
310 clear_view: bool,
311 ) -> Result<()> {
312 Ok(self.call_function("outTextForGroup", (group, text, display_time, clear_view))?)
313 }
314
315 pub fn out_text_for_unit(
316 &self,
317 unit: UnitId,
318 text: String,
319 display_time: i64,
320 clear_view: bool,
321 ) -> Result<()> {
322 Ok(self.call_function("outTextForUnit", (unit, text, display_time, clear_view))?)
323 }
324
325 pub fn mark_to_all(
326 &self,
327 id: MarkId,
328 text: String,
329 position: LuaVec3,
330 read_only: bool,
331 message: Option<String>,
332 ) -> Result<()> {
333 Ok(self.call_function("markToAll", (id, text, position, read_only, message))?)
334 }
335
336 pub fn mark_to_coalition(
337 &self,
338 id: MarkId,
339 text: String,
340 position: LuaVec3,
341 side: Side,
342 read_only: bool,
343 message: Option<String>,
344 ) -> Result<()> {
345 Ok(self.call_function(
346 "markToCoalition",
347 (id, text, position, side, read_only, message),
348 )?)
349 }
350
351 pub fn mark_to_group(
352 &self,
353 id: MarkId,
354 text: String,
355 position: LuaVec3,
356 group: GroupId,
357 read_only: bool,
358 message: Option<String>,
359 ) -> Result<()> {
360 Ok(self.call_function(
361 "markToGroup",
362 (id, text, position, group, read_only, message),
363 )?)
364 }
365
366 pub fn remove_mark(&self, id: MarkId) -> Result<()> {
367 Ok(self.call_function("removeMark", id)?)
368 }
369
370 pub fn line_to_all(
371 &self,
372 side: SideFilter,
373 id: MarkId,
374 spec: LineSpec,
375 message: Option<String>,
376 ) -> Result<()> {
377 Ok(self.call_function(
378 "lineToAll",
379 (
380 side,
381 id,
382 spec.start,
383 spec.end,
384 spec.color,
385 spec.line_type,
386 spec.read_only,
387 message,
388 ),
389 )?)
390 }
391
392 pub fn circle_to_all(
393 &self,
394 side: SideFilter,
395 id: MarkId,
396 spec: CircleSpec,
397 message: Option<String>,
398 ) -> Result<()> {
399 Ok(self.call_function(
400 "circleToAll",
401 (
402 side,
403 id,
404 spec.center,
405 spec.radius,
406 spec.color,
407 spec.fill_color,
408 spec.line_type,
409 spec.read_only,
410 message,
411 ),
412 )?)
413 }
414
415 pub fn rect_to_all(
416 &self,
417 side: SideFilter,
418 id: MarkId,
419 spec: RectSpec,
420 message: Option<String>,
421 ) -> Result<()> {
422 Ok(self.call_function(
423 "rectToAll",
424 (
425 side,
426 id,
427 spec.start,
428 spec.end,
429 spec.color,
430 spec.fill_color,
431 spec.line_type,
432 spec.read_only,
433 message,
434 ),
435 )?)
436 }
437
438 pub fn quad_to_all(
439 &self,
440 side: SideFilter,
441 id: MarkId,
442 spec: QuadSpec,
443 message: Option<String>,
444 ) -> Result<()> {
445 Ok(self.call_function(
446 "quadToAll",
447 (
448 side,
449 id,
450 spec.p0,
451 spec.p1,
452 spec.p2,
453 spec.p3,
454 spec.color,
455 spec.fill_color,
456 spec.line_type,
457 spec.read_only,
458 message,
459 ),
460 )?)
461 }
462
463 pub fn text_to_all(&self, side: SideFilter, id: MarkId, spec: TextSpec) -> Result<()> {
464 Ok(self.call_function(
465 "textToAll",
466 (
467 side,
468 id,
469 spec.pos,
470 spec.color,
471 spec.fill_color,
472 spec.font_size,
473 spec.read_only,
474 spec.text,
475 ),
476 )?)
477 }
478
479 pub fn arrow_to_all(
480 &self,
481 side: SideFilter,
482 id: MarkId,
483 spec: ArrowSpec,
484 message: Option<String>,
485 ) -> Result<()> {
486 Ok(self.call_function(
487 "arrowToAll",
488 (
489 side,
490 id,
491 spec.start,
492 spec.end,
493 spec.color,
494 spec.fill_color,
495 spec.line_type,
496 spec.read_only,
497 message,
498 ),
499 )?)
500 }
501
502 pub fn set_markup_radius(&self, id: MarkId, radius: f64) -> Result<()> {
503 Ok(self.call_function("setMarkupRadius", (id, radius))?)
504 }
505
506 pub fn set_markup_text(&self, id: MarkId, text: String) -> Result<()> {
507 Ok(self.call_function("setMarkupText", (id, text))?)
508 }
509
510 pub fn set_markup_font_size(&self, id: MarkId, font_size: u8) -> Result<()> {
511 Ok(self.call_function("setMarkupFontSize", (id, font_size))?)
512 }
513
514 pub fn set_markup_color(&self, id: MarkId, color: Color) -> Result<()> {
515 Ok(self.call_function("setMarkupColor", (id, color))?)
516 }
517
518 pub fn set_markup_fill_color(&self, id: MarkId, fill_color: Color) -> Result<()> {
519 Ok(self.call_function("setMarkupColorFill", (id, fill_color))?)
520 }
521
522 pub fn set_markup_line_type(&self, id: MarkId, line_type: LineType) -> Result<()> {
523 Ok(self.call_function("setMarkupTypeLine", (id, line_type))?)
524 }
525
526 pub fn set_markup_position_end(&self, id: MarkId, pos: LuaVec3) -> Result<()> {
527 Ok(self.call_function("setMarkupPositionEnd", (id, pos))?)
528 }
529
530 pub fn set_markup_position_start(&self, id: MarkId, pos: LuaVec3) -> Result<()> {
531 Ok(self.call_function("setMarkupPositionStart", (id, pos))?)
532 }
533}
534
535wrapped_table!(Trigger, None);
536
537impl<'lua> Trigger<'lua> {
538 pub fn singleton(lua: MizLua<'lua>) -> Result<Self> {
539 Ok(lua.inner().globals().raw_get("trigger")?)
540 }
541
542 pub fn action(&self) -> Result<Action<'lua>> {
543 Ok(self.raw_get("action")?)
544 }
545
546 pub fn get_zone(&self, name: String) -> Result<Zone> {
547 let misc: LuaTable = self.t.raw_get("misc")?;
548 Ok(misc.call_function("getZone", name)?)
549 }
550}