rakata_generics/
shared.rs

1//! Shared typed building blocks used across multiple GFF generic wrappers.
2//!
3//! These types reduce drift between format modules by centralizing repeated
4//! field groups (for example trap settings and common trap-related scripts).
5
6use rakata_core::ResRef;
7use rakata_formats::GffValue;
8
9/// Shared trap configuration block used by door/placeable/trap-like templates.
10#[derive(Debug, Clone, PartialEq, Eq, Default)]
11pub struct TrapSettings {
12    /// Trap-detectable flag (`TrapDetectable`).
13    pub detectable: bool,
14    /// Trap detect DC (`TrapDetectDC`).
15    pub detect_dc: u8,
16    /// Trap-disarmable flag (`TrapDisarmable`).
17    pub disarmable: bool,
18    /// Trap disarm DC (`DisarmDC`).
19    pub disarm_dc: u8,
20    /// Trap flag (`TrapFlag`).
21    pub flag: u8,
22    /// Trap one-shot flag (`TrapOneShot`).
23    pub one_shot: bool,
24    /// Trap type (`TrapType`).
25    pub trap_type: u8,
26}
27
28impl TrapSettings {
29    /// Builds trap settings from caller-provided field readers.
30    pub(crate) fn read<FBool, FU8>(mut get_bool: FBool, mut get_u8: FU8) -> Self
31    where
32        FBool: FnMut(&str) -> Option<bool>,
33        FU8: FnMut(&str) -> Option<u8>,
34    {
35        Self {
36            detectable: get_bool("TrapDetectable").unwrap_or(false),
37            detect_dc: get_u8("TrapDetectDC").unwrap_or(0),
38            disarmable: get_bool("TrapDisarmable").unwrap_or(false),
39            disarm_dc: get_u8("DisarmDC").unwrap_or(0),
40            flag: get_u8("TrapFlag").unwrap_or(0),
41            one_shot: get_bool("TrapOneShot").unwrap_or(false),
42            trap_type: get_u8("TrapType").unwrap_or(0),
43        }
44    }
45
46    /// Writes trap settings via caller-provided upsert callback.
47    pub(crate) fn write<FUpsert>(&self, mut upsert: FUpsert)
48    where
49        FUpsert: FnMut(&str, GffValue),
50    {
51        upsert("TrapDetectable", GffValue::UInt8(u8::from(self.detectable)));
52        upsert("TrapDetectDC", GffValue::UInt8(self.detect_dc));
53        upsert("TrapDisarmable", GffValue::UInt8(u8::from(self.disarmable)));
54        upsert("DisarmDC", GffValue::UInt8(self.disarm_dc));
55        upsert("TrapFlag", GffValue::UInt8(self.flag));
56        upsert("TrapOneShot", GffValue::UInt8(u8::from(self.one_shot)));
57        upsert("TrapType", GffValue::UInt8(self.trap_type));
58    }
59}
60
61/// Shared script hook bundle common to placeables and doors.
62#[derive(Debug, Clone, PartialEq, Eq, Default)]
63pub struct CommonTrapScripts {
64    /// On-closed script (`OnClosed`).
65    pub on_closed: ResRef,
66    /// On-damaged script (`OnDamaged`).
67    pub on_damaged: ResRef,
68    /// On-death script (`OnDeath`).
69    pub on_death: ResRef,
70    /// On-disarm script (`OnDisarm`).
71    pub on_disarm: ResRef,
72    /// On-heartbeat script (`OnHeartbeat`).
73    pub on_heartbeat: ResRef,
74    /// On-lock script (`OnLock`).
75    pub on_lock: ResRef,
76    /// On-melee-attacked script (`OnMeleeAttacked`).
77    pub on_melee_attacked: ResRef,
78    /// On-open script (`OnOpen`).
79    pub on_open: ResRef,
80    /// On-spell-cast-at script (`OnSpellCastAt`).
81    pub on_spell_cast_at: ResRef,
82    /// On-trap-triggered script (`OnTrapTriggered`).
83    pub on_trap_triggered: ResRef,
84    /// On-unlock script (`OnUnlock`).
85    pub on_unlock: ResRef,
86    /// On-user-defined script (`OnUserDefined`).
87    pub on_user_defined: ResRef,
88    /// On-fail-to-open script (`OnFailToOpen`).
89    pub on_fail_to_open: ResRef,
90}
91
92impl CommonTrapScripts {
93    /// Builds the shared script bundle from caller-provided field readers.
94    pub(crate) fn read<FResRef>(mut get_resref: FResRef) -> Self
95    where
96        FResRef: FnMut(&str) -> Option<ResRef>,
97    {
98        Self {
99            on_closed: get_resref("OnClosed").unwrap_or_default(),
100            on_damaged: get_resref("OnDamaged").unwrap_or_default(),
101            on_death: get_resref("OnDeath").unwrap_or_default(),
102            on_disarm: get_resref("OnDisarm").unwrap_or_default(),
103            on_heartbeat: get_resref("OnHeartbeat").unwrap_or_default(),
104            on_lock: get_resref("OnLock").unwrap_or_default(),
105            on_melee_attacked: get_resref("OnMeleeAttacked").unwrap_or_default(),
106            on_open: get_resref("OnOpen").unwrap_or_default(),
107            on_spell_cast_at: get_resref("OnSpellCastAt").unwrap_or_default(),
108            on_trap_triggered: get_resref("OnTrapTriggered").unwrap_or_default(),
109            on_unlock: get_resref("OnUnlock").unwrap_or_default(),
110            on_user_defined: get_resref("OnUserDefined").unwrap_or_default(),
111            on_fail_to_open: get_resref("OnFailToOpen").unwrap_or_default(),
112        }
113    }
114
115    /// Writes the shared script bundle via caller-provided upsert callback.
116    pub(crate) fn write<FUpsert>(&self, mut upsert: FUpsert)
117    where
118        FUpsert: FnMut(&str, GffValue),
119    {
120        upsert("OnClosed", GffValue::ResRef(self.on_closed));
121        upsert("OnDamaged", GffValue::ResRef(self.on_damaged));
122        upsert("OnDeath", GffValue::ResRef(self.on_death));
123        upsert("OnDisarm", GffValue::ResRef(self.on_disarm));
124        upsert("OnHeartbeat", GffValue::ResRef(self.on_heartbeat));
125        upsert("OnLock", GffValue::ResRef(self.on_lock));
126        upsert("OnMeleeAttacked", GffValue::ResRef(self.on_melee_attacked));
127        upsert("OnOpen", GffValue::ResRef(self.on_open));
128        upsert("OnSpellCastAt", GffValue::ResRef(self.on_spell_cast_at));
129        upsert("OnTrapTriggered", GffValue::ResRef(self.on_trap_triggered));
130        upsert("OnUnlock", GffValue::ResRef(self.on_unlock));
131        upsert("OnUserDefined", GffValue::ResRef(self.on_user_defined));
132        upsert("OnFailToOpen", GffValue::ResRef(self.on_fail_to_open));
133    }
134}
135
136/// Shared grid/repository position used by inventory list entries.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
138pub struct InventoryGridPosition {
139    /// Repository/grid X coordinate.
140    pub x: u16,
141    /// Repository/grid Y coordinate.
142    pub y: u16,
143}
144
145/// A vertex in a trigger geometry polygon (`PointX`/`PointY`/`PointZ`).
146#[derive(Debug, Clone, PartialEq, Default)]
147pub struct GitTriggerPoint {
148    /// X coordinate (`PointX`).
149    pub point_x: f32,
150    /// Y coordinate (`PointY`).
151    pub point_y: f32,
152    /// Z coordinate (`PointZ`).
153    pub point_z: f32,
154}
155
156impl GitTriggerPoint {
157    /// Builds a trigger point from a raw GFF struct.
158    pub fn from_gff_struct(s: &rakata_formats::GffStruct) -> Self {
159        use crate::gff_helpers::get_f32;
160        Self {
161            point_x: get_f32(s, "PointX").unwrap_or(0.0),
162            point_y: get_f32(s, "PointY").unwrap_or(0.0),
163            point_z: get_f32(s, "PointZ").unwrap_or(0.0),
164        }
165    }
166
167    /// Converts this trigger point to a raw GFF struct.
168    pub fn to_gff_struct(&self) -> rakata_formats::GffStruct {
169        use crate::gff_helpers::upsert_field;
170        let mut s = rakata_formats::GffStruct::new(0);
171        upsert_field(&mut s, "PointX", GffValue::Single(self.point_x));
172        upsert_field(&mut s, "PointY", GffValue::Single(self.point_y));
173        upsert_field(&mut s, "PointZ", GffValue::Single(self.point_z));
174        s
175    }
176}