Skip to main content

rustapi/actions/
gate_door.rs

1use crate::prelude::*;
2use rusterix::{PixelSource, Value};
3
4pub struct GateDoor {
5    id: TheId,
6    nodeui: TheNodeUI,
7}
8
9impl Action for GateDoor {
10    fn new() -> Self
11    where
12        Self: Sized,
13    {
14        let mut nodeui: TheNodeUI = TheNodeUI::default();
15
16        let item = TheNodeUIItem::FloatEditSlider(
17            "actionGateDoorInset".into(),
18            "".into(),
19            "".into(),
20            0.1,
21            0.0..=1.0,
22            false,
23        );
24        nodeui.add_item(item);
25
26        let item = TheNodeUIItem::Selector(
27            "actionGateDoorRepeatMode".into(),
28            "".into(),
29            "".into(),
30            vec!["repeat".into(), "scale".into()],
31            1,
32        );
33        nodeui.add_item(item);
34
35        nodeui.add_item(TheNodeUIItem::OpenTree("billboard".into()));
36        nodeui.add_item(TheNodeUIItem::Icons(
37            "actionBillboardTile".into(),
38            "".into(),
39            "".into(),
40            vec![(
41                TheRGBABuffer::new(TheDim::sized(36, 36)),
42                "".to_string(),
43                Uuid::nil(),
44            )],
45        ));
46        nodeui.add_item(TheNodeUIItem::Text(
47            "actionBillboardTileId".into(),
48            "".into(),
49            "".into(),
50            "".into(),
51            None,
52            false,
53        ));
54        nodeui.add_item(TheNodeUIItem::CloseTree);
55
56        let item = TheNodeUIItem::Markdown("desc".into(), "".into());
57        nodeui.add_item(item);
58
59        Self {
60            id: TheId::named(&fl!("action_gate_door")),
61            nodeui,
62        }
63    }
64
65    fn id(&self) -> TheId {
66        self.id.clone()
67    }
68
69    fn info(&self) -> String {
70        fl!("action_gate_door_desc")
71    }
72
73    fn role(&self) -> ActionRole {
74        ActionRole::Editor
75    }
76
77    fn accel(&self) -> Option<TheAccelerator> {
78        Some(TheAccelerator::new(TheAcceleratorKey::ALT, 'g'))
79    }
80
81    fn is_applicable(&self, map: &Map, _ctx: &mut TheContext, server_ctx: &ServerContext) -> bool {
82        // Only applicable if we have selected sectors and we are in 2D Profile Editing Mode
83        !map.selected_sectors.is_empty()
84            && server_ctx.editor_view_mode == EditorViewMode::D2
85            && server_ctx.editing_surface.is_some()
86    }
87
88    fn load_params(&mut self, map: &Map) {
89        if let Some(sector_id) = map.selected_sectors.first() {
90            if let Some(sector) = map.find_sector(*sector_id) {
91                self.nodeui.set_f32_value(
92                    "actionGateDoorInset",
93                    sector.properties.get_float_default("profile_inset", 0.1),
94                );
95                self.nodeui.set_i32_value(
96                    "actionGateDoorRepeatMode",
97                    sector
98                        .properties
99                        .get_int_default("billboard_repeat_mode", 1),
100                );
101            }
102        }
103    }
104
105    fn load_params_project(&mut self, project: &Project, server_ctx: &mut ServerContext) {
106        let mut cap_icon = TheRGBABuffer::new(TheDim::sized(36, 36));
107        let mut cap_id = Uuid::nil();
108
109        if let Some(map) = project.get_map(server_ctx) {
110            if let Some(sector_id) = map.selected_sectors.first() {
111                if let Some(sector) = map.find_sector(*sector_id) {
112                    if let Some(Value::Source(PixelSource::TileId(id))) =
113                        sector.properties.get("billboard_source")
114                    {
115                        if let Some(tile) = project.tiles.get(id)
116                            && !tile.is_empty()
117                        {
118                            cap_icon = tile.textures[0].to_rgba();
119                            cap_id = *id;
120                        }
121                    }
122                }
123            }
124        }
125
126        self.nodeui.set_text_value(
127            "actionBillboardTileId",
128            if cap_id == Uuid::nil() {
129                String::new()
130            } else {
131                cap_id.to_string()
132            },
133        );
134
135        if let Some(item) = self.nodeui.get_item_mut("actionBillboardTile") {
136            match item {
137                TheNodeUIItem::Icons(_, _, _, items) => {
138                    if items.len() == 1 {
139                        items[0].0 = cap_icon;
140                        items[0].2 = cap_id;
141                    }
142                }
143                _ => {}
144            }
145        }
146    }
147
148    fn apply(
149        &self,
150        map: &mut Map,
151        _ui: &mut TheUI,
152        _ctx: &mut TheContext,
153        server_ctx: &mut ServerContext,
154    ) -> Option<ProjectUndoAtom> {
155        let mut changed = false;
156        let prev = map.clone();
157
158        let inset = self
159            .nodeui
160            .get_f32_value("actionGateDoorInset")
161            .unwrap_or(0.0);
162
163        let repeat_mode = self
164            .nodeui
165            .get_i32_value("actionGateDoorRepeatMode")
166            .unwrap_or(1);
167
168        let cap = self
169            .nodeui
170            .get_tile_id("actionBillboardTile", 0)
171            .unwrap_or(Uuid::nil());
172        let cap_text = self
173            .nodeui
174            .get_text_value("actionBillboardTileId")
175            .unwrap_or_default();
176        let cap = if let Ok(id) = Uuid::parse_str(cap_text.trim()) {
177            id
178        } else {
179            cap
180        };
181
182        for sector_id in &map.selected_sectors.clone() {
183            if let Some(sector) = map.find_sector_mut(*sector_id) {
184                sector.properties.set("profile_op", Value::Int(3));
185                sector.properties.set("profile_inset", Value::Float(inset));
186                sector
187                    .properties
188                    .set("billboard_repeat_mode", Value::Int(repeat_mode));
189
190                if cap != Uuid::nil() {
191                    sector.properties.set(
192                        "billboard_source",
193                        Value::Source(rusterix::PixelSource::TileId(cap)),
194                    );
195                } else {
196                    sector.properties.remove("billboard_source");
197                }
198                changed = true;
199            }
200        }
201
202        if changed {
203            Some(ProjectUndoAtom::MapEdit(
204                server_ctx.pc,
205                Box::new(prev),
206                Box::new(map.clone()),
207            ))
208        } else {
209            None
210        }
211    }
212
213    fn params(&self) -> TheNodeUI {
214        self.nodeui.clone()
215    }
216
217    fn handle_event(
218        &mut self,
219        event: &TheEvent,
220        project: &mut Project,
221        _ui: &mut TheUI,
222        ctx: &mut TheContext,
223        _server_ctx: &mut ServerContext,
224    ) -> bool {
225        if let TheEvent::TileDropped(id, tile_id, index) = event {
226            if let Some(item) = self.nodeui.get_item_mut(&id.name) {
227                match item {
228                    TheNodeUIItem::Icons(_, _, _, items) => {
229                        if *index < items.len() {
230                            if let Some(tile) = project.tiles.get(tile_id)
231                                && !tile.is_empty()
232                            {
233                                items[*index].0 = tile.textures[0].to_rgba();
234                                items[*index].2 = *tile_id;
235                                if id.name == "actionBillboardTile" {
236                                    self.nodeui.set_text_value(
237                                        "actionBillboardTileId",
238                                        tile_id.to_string(),
239                                    );
240                                }
241                                ctx.ui.send(TheEvent::Custom(
242                                    TheId::named("Update Action List"),
243                                    TheValue::Empty,
244                                ));
245                                return true;
246                            }
247                        }
248                    }
249                    _ => {}
250                }
251            }
252        }
253        self.nodeui.handle_event(event)
254    }
255}