Skip to main content

rakata_generics/git/
encounter.rs

1//! Encounter placements in a GIT, with their geometry and spawn points.
2
3use rakata_core::ResRef;
4use rakata_formats::{
5    gff_schema::{AbsentDefault, FieldLife, FieldSchema, GffType},
6    GffStruct, GffValue,
7};
8
9use super::object_id_or_invalid;
10use crate::gff_helpers::{get_f32, get_resref, upsert_field};
11use crate::shared::ObjectId;
12
13/// A vertex in an encounter geometry polygon (`X`/`Y`/`Z`).
14#[derive(Debug, Clone, PartialEq, Default)]
15pub struct GitEncounterPoint {
16    /// X coordinate (`X`).
17    pub x: f32,
18    /// Y coordinate (`Y`).
19    pub y: f32,
20    /// Z coordinate (`Z`).
21    pub z: f32,
22}
23
24impl GitEncounterPoint {
25    pub(crate) fn from_gff_struct(s: &GffStruct) -> Self {
26        Self {
27            x: get_f32(s, "X").unwrap_or(0.0),
28            y: get_f32(s, "Y").unwrap_or(0.0),
29            z: get_f32(s, "Z").unwrap_or(0.0),
30        }
31    }
32
33    pub(crate) fn to_gff_struct(&self) -> GffStruct {
34        let mut s = GffStruct::new(0);
35        upsert_field(&mut s, "X", GffValue::Single(self.x));
36        upsert_field(&mut s, "Y", GffValue::Single(self.y));
37        upsert_field(&mut s, "Z", GffValue::Single(self.z));
38        s
39    }
40}
41
42/// A spawn point within an encounter (`X`/`Y`/`Z`/`Orientation`).
43#[derive(Debug, Clone, PartialEq, Default)]
44pub struct GitSpawnPoint {
45    /// X coordinate (`X`).
46    pub x: f32,
47    /// Y coordinate (`Y`).
48    pub y: f32,
49    /// Z coordinate (`Z`).
50    pub z: f32,
51    /// Facing angle (`Orientation`).
52    pub orientation: f32,
53}
54
55impl GitSpawnPoint {
56    pub(crate) fn from_gff_struct(s: &GffStruct) -> Self {
57        Self {
58            x: get_f32(s, "X").unwrap_or(0.0),
59            y: get_f32(s, "Y").unwrap_or(0.0),
60            z: get_f32(s, "Z").unwrap_or(0.0),
61            orientation: get_f32(s, "Orientation").unwrap_or(0.0),
62        }
63    }
64
65    pub(crate) fn to_gff_struct(&self) -> GffStruct {
66        let mut s = GffStruct::new(0);
67        upsert_field(&mut s, "X", GffValue::Single(self.x));
68        upsert_field(&mut s, "Y", GffValue::Single(self.y));
69        upsert_field(&mut s, "Z", GffValue::Single(self.z));
70        upsert_field(&mut s, "Orientation", GffValue::Single(self.orientation));
71        s
72    }
73}
74
75/// An encounter instance placed in the area (struct type 7).
76#[derive(Debug, Clone, PartialEq, Default)]
77pub struct GitEncounter {
78    /// Template resref (`TemplateResRef`).
79    pub template_resref: ResRef,
80    /// X position (`XPosition`).
81    pub x_position: f32,
82    /// Y position (`YPosition`).
83    pub y_position: f32,
84    /// Z position (`ZPosition`).
85    pub z_position: f32,
86    /// Geometry polygon vertices (`Geometry`).
87    pub geometry: Vec<GitEncounterPoint>,
88    /// Spawn point list (`SpawnPointList`).
89    pub spawn_points: Vec<GitSpawnPoint>,
90    /// Runtime object ID (`ObjectId`). Save-game only.
91    pub object_id: ObjectId,
92}
93
94impl GitEncounter {
95    pub(crate) fn from_gff_struct(s: &GffStruct) -> Self {
96        let geometry = match s.field("Geometry") {
97            Some(GffValue::List(elements)) => elements
98                .iter()
99                .map(GitEncounterPoint::from_gff_struct)
100                .collect(),
101            _ => Vec::new(),
102        };
103
104        let spawn_points = match s.field("SpawnPointList") {
105            Some(GffValue::List(elements)) => elements
106                .iter()
107                .map(GitSpawnPoint::from_gff_struct)
108                .collect(),
109            _ => Vec::new(),
110        };
111
112        Self {
113            template_resref: get_resref(s, "TemplateResRef").unwrap_or_default(),
114            x_position: get_f32(s, "XPosition").unwrap_or(0.0),
115            y_position: get_f32(s, "YPosition").unwrap_or(0.0),
116            z_position: get_f32(s, "ZPosition").unwrap_or(0.0),
117            geometry,
118            spawn_points,
119            object_id: object_id_or_invalid(s),
120        }
121    }
122
123    pub(crate) fn to_gff_struct(&self) -> GffStruct {
124        let mut s = GffStruct::new(7);
125        upsert_field(
126            &mut s,
127            "TemplateResRef",
128            GffValue::ResRef(self.template_resref),
129        );
130        upsert_field(&mut s, "XPosition", GffValue::Single(self.x_position));
131        upsert_field(&mut s, "YPosition", GffValue::Single(self.y_position));
132        upsert_field(&mut s, "ZPosition", GffValue::Single(self.z_position));
133        let geom_structs: Vec<GffStruct> =
134            self.geometry.iter().map(|p| p.to_gff_struct()).collect();
135        upsert_field(&mut s, "Geometry", GffValue::List(geom_structs));
136        let spawn_structs: Vec<GffStruct> = self
137            .spawn_points
138            .iter()
139            .map(|sp| sp.to_gff_struct())
140            .collect();
141        upsert_field(&mut s, "SpawnPointList", GffValue::List(spawn_structs));
142        upsert_field(&mut s, "ObjectId", GffValue::UInt32(self.object_id.get()));
143        s
144    }
145}
146
147/// GIT `Encounter List` geometry entry child schema (X/Y/Z).
148pub(crate) static ENCOUNTER_GEOMETRY_CHILDREN: &[FieldSchema] = &[
149    FieldSchema {
150        label: "X",
151        expected_type: GffType::Single,
152        life: FieldLife::Live,
153        required: false,
154        absent: AbsentDefault::Unverified,
155        children: None,
156        constraint: None,
157    },
158    FieldSchema {
159        label: "Y",
160        expected_type: GffType::Single,
161        life: FieldLife::Live,
162        required: false,
163        absent: AbsentDefault::Unverified,
164        children: None,
165        constraint: None,
166    },
167    FieldSchema {
168        label: "Z",
169        expected_type: GffType::Single,
170        life: FieldLife::Live,
171        required: false,
172        absent: AbsentDefault::Unverified,
173        children: None,
174        constraint: None,
175    },
176];
177
178/// GIT `Encounter List` spawn point entry child schema (X/Y/Z/Orientation).
179pub(crate) static ENCOUNTER_SPAWN_POINT_CHILDREN: &[FieldSchema] = &[
180    FieldSchema {
181        label: "X",
182        expected_type: GffType::Single,
183        life: FieldLife::Live,
184        required: false,
185        absent: AbsentDefault::Unverified,
186        children: None,
187        constraint: None,
188    },
189    FieldSchema {
190        label: "Y",
191        expected_type: GffType::Single,
192        life: FieldLife::Live,
193        required: false,
194        absent: AbsentDefault::Unverified,
195        children: None,
196        constraint: None,
197    },
198    FieldSchema {
199        label: "Z",
200        expected_type: GffType::Single,
201        life: FieldLife::Live,
202        required: false,
203        absent: AbsentDefault::Unverified,
204        children: None,
205        constraint: None,
206    },
207    FieldSchema {
208        label: "Orientation",
209        expected_type: GffType::Single,
210        life: FieldLife::Live,
211        required: false,
212        absent: AbsentDefault::Unverified,
213        children: None,
214        constraint: None,
215    },
216];
217
218/// GIT `Encounter List` entry child schema (struct type 7).
219pub(crate) static ENCOUNTER_LIST_CHILDREN: &[FieldSchema] = &[
220    FieldSchema {
221        label: "ObjectId",
222        expected_type: GffType::UInt32,
223        life: FieldLife::Live,
224        required: false,
225        absent: AbsentDefault::Unverified,
226        children: None,
227        constraint: None,
228    },
229    FieldSchema {
230        label: "TemplateResRef",
231        expected_type: GffType::ResRef,
232        life: FieldLife::Live,
233        required: false,
234        absent: AbsentDefault::Unverified,
235        children: None,
236        constraint: None,
237    },
238    FieldSchema {
239        label: "XPosition",
240        expected_type: GffType::Single,
241        life: FieldLife::Live,
242        required: false,
243        absent: AbsentDefault::Unverified,
244        children: None,
245        constraint: None,
246    },
247    FieldSchema {
248        label: "YPosition",
249        expected_type: GffType::Single,
250        life: FieldLife::Live,
251        required: false,
252        absent: AbsentDefault::Unverified,
253        children: None,
254        constraint: None,
255    },
256    FieldSchema {
257        label: "ZPosition",
258        expected_type: GffType::Single,
259        life: FieldLife::Live,
260        required: false,
261        absent: AbsentDefault::Unverified,
262        children: None,
263        constraint: None,
264    },
265    FieldSchema {
266        label: "Geometry",
267        expected_type: GffType::List,
268        life: FieldLife::Live,
269        required: false,
270        absent: AbsentDefault::Unverified,
271        children: Some(ENCOUNTER_GEOMETRY_CHILDREN),
272        constraint: None,
273    },
274    FieldSchema {
275        label: "SpawnPointList",
276        expected_type: GffType::List,
277        life: FieldLife::Live,
278        required: false,
279        absent: AbsentDefault::Unverified,
280        children: Some(ENCOUNTER_SPAWN_POINT_CHILDREN),
281        constraint: None,
282    },
283];