commonlibsse_ng\re\t/
TESCondition.rs

1mod function_id;
2pub use function_id::FunctionData;
3
4use crate::re::BSPointerHandle::ObjectRefHandle;
5use crate::re::TESGlobal::TESGlobal;
6use crate::re::TESObjectREFR::TESObjectREFR;
7use crate::re::TESQuest::TESQuest;
8use core::ffi::c_void;
9use core::ptr::NonNull;
10use core::{fmt, ptr};
11
12#[repr(u8)]
13#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum OpCode {
15    /// - EqualTo: `==`
16    #[default]
17    Eq,
18    /// - NotEqualTo: `!=`
19    Ne,
20    /// - GreaterThan: `>`
21    Gt,
22    /// - GreaterThanOrEqualTo: `>=`
23    Ge,
24    /// - LessThan: `<`
25    Lt,
26    /// - LessThanOrEqualTo: `<=`
27    Le,
28}
29
30/// Either is resolved by [`Flags`]
31#[repr(C)]
32pub union GlobalOrFloat {
33    pub g: *mut TESGlobal,
34    pub f: f32,
35}
36const _: () = assert!(std::mem::size_of::<GlobalOrFloat>() == 0x8);
37
38impl GlobalOrFloat {
39    #[inline]
40    pub const fn new() -> Self {
41        Self { g: ptr::null_mut() }
42    }
43}
44
45/// `GlobalOrFloat` after either is resolved by Flags
46#[derive(Debug)]
47pub enum ComparisonValue {
48    Global(*mut TESGlobal),
49    Float(f32),
50}
51
52impl Default for GlobalOrFloat {
53    #[inline]
54    fn default() -> Self {
55        Self { g: ptr::null_mut() }
56    }
57}
58
59bitflags::bitflags! {
60    #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
61    pub struct Flags: u8 {
62        /// 0 - false == AND, true == OR
63        const IS_OR         = 0b00000001;
64        const USES_ALIASES  = 0b00000010;
65        const GLOBAL        = 0b00000100;
66        const USE_PACK_DATA = 0b00001000;
67        const SWAP_TARGET   = 0b00010000;
68        // OpCode uses remaining 3 bits: 0b11100000
69    }
70}
71
72impl Flags {
73    #[inline]
74    pub const fn new() -> Self {
75        Self::empty()
76    }
77
78    /// Gets operation code from bits.
79    #[inline]
80    pub const fn op_code(&self) -> Option<OpCode> {
81        // Extract the 3-bit opcode from bits 5-7
82        Some(match (self.bits() >> 5) & 0b111 {
83            0 => OpCode::Eq,
84            1 => OpCode::Ne,
85            2 => OpCode::Gt,
86            3 => OpCode::Ge,
87            4 => OpCode::Lt,
88            5 => OpCode::Le,
89            _ => return None, // invalid OpCode
90        })
91    }
92}
93
94impl fmt::Debug for Flags {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        let mut flags = vec![];
97
98        if self.contains(Self::IS_OR) {
99            flags.push("IS_OR");
100        }
101        if self.contains(Self::USES_ALIASES) {
102            flags.push("USES_ALIASES");
103        }
104        if self.contains(Self::GLOBAL) {
105            flags.push("GLOBAL");
106        }
107        if self.contains(Self::USE_PACK_DATA) {
108            flags.push("USE_PACK_DATA");
109        }
110        if self.contains(Self::SWAP_TARGET) {
111            flags.push("SWAP_TARGET");
112        }
113
114        if let Some(op) = self.op_code() {
115            flags.push(match op {
116                OpCode::Eq => "Op::Eq",
117                OpCode::Ne => "Op::Ne",
118                OpCode::Gt => "Op::Gt",
119                OpCode::Ge => "Op::Ge",
120                OpCode::Lt => "Op::Lt",
121                OpCode::Le => "Op::Le",
122            });
123        } else {
124            flags.push("Op::Invalid");
125        }
126
127        f.debug_tuple("Flags").field(&flags.join(" | ")).finish()
128    }
129}
130
131#[commonlibsse_ng_derive_internal::to_bitflags]
132#[repr(u8)]
133#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub enum ConditionItemObject {
135    #[default]
136    Self_ = 0,
137    Target = 1,
138    Ref = 2,
139    CombatTarget = 3,
140    LinkedRef = 4,
141    QuestAlias = 5,
142    PackData = 6,
143    EventData = 7,
144    CommandTarget = 8,
145}
146
147#[derive(Default)]
148#[repr(C)]
149pub struct CONDITION_ITEM_DATA {
150    pub comparisonValue: GlobalOrFloat, // 0x08
151    pub runOnRef: ObjectRefHandle,      // 0x10
152    pub dataId: u32,                    // 0x14
153    pub functionData: FunctionData,     // 0x18
154    pub flags: Flags,                   // 0x30
155    pub object: ConditionItemObject,    // 0x31
156    pub pad32: u16,                     // 0x32
157    pub pad34: u32,                     // 0x34
158}
159const _: () = assert!(core::mem::size_of::<CONDITION_ITEM_DATA>() == 0x30);
160
161impl CONDITION_ITEM_DATA {
162    #[inline]
163    pub const fn new() -> Self {
164        Self {
165            comparisonValue: GlobalOrFloat::new(),
166            runOnRef: ObjectRefHandle::new(),
167            dataId: 0,
168            functionData: FunctionData::new(),
169            flags: Flags::new(),
170            object: ConditionItemObject::Self_,
171            pad32: 0,
172            pad34: 0,
173        }
174    }
175
176    /// Type convert unions that are unsafe to access to safe enums.
177    #[inline]
178    pub const fn comparison_value(&self) -> ComparisonValue {
179        unsafe {
180            if self.flags.contains(Flags::GLOBAL) {
181                ComparisonValue::Global(self.comparisonValue.g)
182            } else {
183                ComparisonValue::Float(self.comparisonValue.f)
184            }
185        }
186    }
187}
188
189impl fmt::Debug for CONDITION_ITEM_DATA {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        f.debug_struct("CONDITION_ITEM_DATA")
192            .field("comparisonValue", &self.comparison_value())
193            .field("runOnRef", &self.runOnRef)
194            .field("dataId", &self.dataId)
195            .field("functionData", &self.functionData)
196            .field("flags", &self.flags)
197            .field("object", &self.object)
198            .finish()
199    }
200}
201
202#[repr(C)]
203#[derive(Debug, PartialEq)]
204pub struct TESCondition {
205    pub head: Option<NonNull<TESConditionItem>>, // 0x00
206}
207const _: () = assert!(core::mem::size_of::<TESCondition>() == 0x8);
208
209impl TESCondition {
210    #[inline]
211    pub const fn new() -> Self {
212        Self { head: None }
213    }
214
215    /// Is the single directional link list empty?
216    #[inline]
217    pub const fn is_empty(&self) -> bool {
218        self.head.is_none()
219    }
220
221    /// Perhaps indicating the equivalence of two objects.
222    #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 29074, ae_id = 29888)]
223    pub fn is_true(&self, action_ref: *mut TESObjectREFR, target_ref: *mut TESObjectREFR) -> bool {}
224}
225
226impl Default for TESCondition {
227    #[inline]
228    fn default() -> Self {
229        Self::new()
230    }
231}
232impl Drop for TESCondition {
233    fn drop(&mut self) {
234        let mut cur = self.head;
235        while let Some(cur_ptr) = cur {
236            unsafe {
237                let next = cur_ptr.as_ref().next;
238                drop(Box::from_raw(cur_ptr.as_ptr()));
239                cur = next;
240            }
241        }
242        self.head = None;
243    }
244}
245
246#[derive(Debug)]
247#[repr(C)]
248pub struct ConditionCheckParams {
249    actionRef: *mut TESObjectREFR,            // 0x00
250    targetRef: *mut TESObjectREFR,            // 0x08
251    quest: *mut TESQuest,                     // 0x10
252    questStartEvent: *mut BGSStoryEvent,      // 0x18
253    unk20: *mut c_void,                       // 0x20
254    unk28: bool,                              // 0x28
255    packageDataList: *mut BGSPackageDataList, // 0x30
256}
257const _: () = assert!(core::mem::size_of::<ConditionCheckParams>() == 0x38);
258
259impl ConditionCheckParams {
260    #[inline]
261    pub const fn new(action_ref: *mut TESObjectREFR, target_ref: *mut TESObjectREFR) -> Self {
262        Self {
263            actionRef: action_ref,
264            targetRef: target_ref,
265            quest: ptr::null_mut(),
266            questStartEvent: ptr::null_mut(),
267            unk20: ptr::null_mut(),
268            unk28: false,
269            packageDataList: ptr::null_mut(),
270        }
271    }
272}
273
274#[derive(Debug)]
275#[repr(C)]
276pub struct TESConditionItem {
277    next: Option<NonNull<TESConditionItem>>, // 0x0
278    data: CONDITION_ITEM_DATA,               // 0x8
279}
280const _: () = assert!(core::mem::size_of::<TESConditionItem>() == 0x38);
281
282impl TESConditionItem {
283    #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 29090, ae_id = 29924)]
284    pub fn is_true(&self, solution: &mut ConditionCheckParams) -> bool {}
285}
286
287pub struct BGSPackageDataList;
288pub struct BGSStoryEvent;