commonlibsse_ng\re\b/
BGSListForm.rs

1use core::ptr::NonNull;
2
3use crate::re::BSContainer::ForEachResult;
4use crate::re::BSCoreTypes::FormID;
5use crate::re::BSTArray::BSTArray;
6use crate::re::FormTypes::FormType;
7use crate::re::TESForm::{TESForm, TESFormVtbl};
8use crate::re::offsets_rtti::RTTI_BGSListForm;
9use crate::re::offsets_vtable::VTABLE_BGSListForm;
10use crate::rel::id::VariantID;
11
12#[repr(C)]
13#[derive(Debug)]
14pub struct BGSListForm {
15    pub __base: TESForm,                             // 0x00
16    pub forms: BSTArray<*mut TESForm>,               // 0x20 - LNAM
17    pub scriptAddedTempForms: *mut BSTArray<FormID>, // 0x38
18    pub scriptAddedFormCount: u32,                   // 0x40
19    pub pad44: u32,                                  // 0x44
20}
21const _: () = assert!(core::mem::size_of::<BGSListForm>() == 0x48);
22
23impl BGSListForm {
24    pub const RTTI: VariantID = RTTI_BGSListForm;
25    pub const VTABLE: [VariantID; 1] = VTABLE_BGSListForm;
26    pub const FORM_TYPE: FormType = FormType::FormList;
27
28    pub const fn vtable(&self) -> *const BGSListFormVtbl {
29        self.__base.__base.vtable.cast()
30    }
31
32    #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 20470, ae_id = 20913)]
33    pub unsafe fn add_form(&mut self, form: *mut TESForm) {}
34
35    pub fn contains_only_type(&self, form_type: FormType) -> bool {
36        let mut result = true;
37        self.for_each_form(|form| {
38            if form.formType.to_enum() != Some(form_type) {
39                result = false;
40                return ForEachResult::Stop;
41            }
42            ForEachResult::Continue
43        });
44        result
45    }
46
47    pub fn for_each_form<F>(&self, mut f: F)
48    where
49        F: FnMut(&TESForm) -> ForEachResult,
50    {
51        // 1. LNAM forms
52        for &form in self.forms.as_slice() {
53            if let Some(form) = NonNull::new(form) {
54                if f(unsafe { form.as_ref() }) == ForEachResult::Stop {
55                    return;
56                }
57            }
58        }
59
60        // 2. Script-added forms
61        if !self.scriptAddedTempForms.is_null() {
62            let added_forms = unsafe { &*self.scriptAddedTempForms };
63            for &form_id in added_forms.as_slice() {
64                let form = TESForm::lookup_by_id(form_id);
65                if let Some(form) = form {
66                    if f(unsafe { form.as_ref() }) == ForEachResult::Stop {
67                        return;
68                    }
69                }
70            }
71        }
72    }
73
74    pub fn has_form_ptr(&self, form: NonNull<TESForm>) -> bool {
75        for &f in self.forms.as_slice() {
76            if f == form.as_ptr() {
77                return true;
78            }
79        }
80
81        if self.scriptAddedTempForms.is_null() {
82            return false;
83        }
84
85        self.has_form_id((unsafe { form.as_ref() }).formID)
86    }
87
88    pub fn has_form_id(&self, form_id: FormID) -> bool {
89        TESForm::lookup_by_id(form_id).is_some_and(|form| self.has_form_ptr(form))
90    }
91}
92
93#[repr(C)]
94#[derive(Debug)]
95pub struct BGSListFormVtbl {
96    pub base: TESFormVtbl,
97}
98
99#[commonlibsse_ng_derive_internal::to_bitflags]
100#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
101#[repr(u32)]
102pub enum ChangeFlag {
103    DAddedForm = 1 << 31,
104}
105
106#[commonlibsse_ng_derive_internal::to_bitflags]
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
108#[repr(u32)]
109pub enum RecordFlag {
110    Deleted = 1 << 5,
111    Ignored = 1 << 12,
112}