1use crate::re::BGSScene;
2use crate::re::BGSStoryManagerTreeForm::{BGSStoryManagerTreeForm, BGSStoryManagerTreeFormVtbl};
3use crate::re::BGSStoryTeller::BGSStoryTeller;
4use crate::re::BSAtomic::BSReadWriteLock;
5use crate::re::BSFixedString::BSFixedString;
6use crate::re::BSPointerHandle::ObjectRefHandle;
7use crate::re::BSString::BSString;
8use crate::re::BSTArray::BSTArray;
9use crate::re::BSTHashMap::{BSTHashMap, UnkKey, UnkValue};
10use crate::re::BSTList::BSSimpleList;
11use crate::re::DialogueTypes::{DIALOGUE_TYPE, DIALOGUE_TYPE_CEnum};
12use crate::re::FormTypes::FormType;
13use crate::re::NiSmartPointer::NiPointer;
14use crate::re::QuestEvent::QuestEvent;
15use crate::re::QuestObjectiveStates::QUEST_OBJECTIVE_STATE;
16use crate::re::TESCondition::TESCondition;
17use crate::re::TESForm::{DerivedTESForm, TESForm};
18use crate::re::TESFullName::{TESFullName, TESFullNameVtbl};
19use crate::re::TESGlobal::TESGlobal;
20use crate::re::offsets_rtti::RTTI_TESQuest;
21use crate::re::offsets_vtable::VTABLE_TESQuest;
22use crate::re::{BGSBaseAlias, BGSDialogueBranch, QueuedPromoteQuestTask, TESTopic};
23use crate::rel::id::VariantID;
24
25#[commonlibsse_ng_derive_internal::to_bitflags]
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
27#[repr(u16)]
28pub enum QuestFlag {
29 StopStart = 65535, None = 0,
31 Enabled = 1 << 0,
32 Completed = 1 << 1,
33 AddIdleToHello = 1 << 2,
34 AllowRepeatStages = 1 << 3,
35 StartsEnabled = 1 << 4,
36 DisplayedInHUD = 1 << 5,
37 Failed = 1 << 6,
38 StageWait = 1 << 7,
39 RunOnce = 1 << 8,
40 ExcludeFromExport = 1 << 9,
41 WarnOnAliasFillFailure = 1 << 10,
42 Active = 1 << 11,
43 RepeatsConditions = 1 << 12,
44 KeepInstance = 1 << 13,
45 WantDormant = 1 << 14,
46 HasDialogueData = 1 << 15,
47}
48
49#[commonlibsse_ng_derive_internal::to_bitflags]
50#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
51#[repr(u32)]
52pub enum QUEST_OBJECTIVE_FLAGS {
53 None = 0,
54 ORWithPrevious = 1 << 0,
55 NoStatsTracking = 1 << 1,
56}
57
58#[repr(C)]
59#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60pub struct StringData {
61 pub aliasId: u32,
62 pub fullNameFormID: u32,
63}
64const _: () = assert!(core::mem::size_of::<StringData>() == 0x8);
65
66#[repr(C)]
67#[derive(Debug, Clone, PartialEq)]
68pub struct GlobalValueData {
69 pub global: *const TESGlobal, pub value: f32, pub pad0C: u32, }
73const _: () = assert!(core::mem::size_of::<GlobalValueData>() == 0x10);
74
75#[repr(C)]
76#[derive(Debug, Clone)]
77pub struct BGSQuestInstanceText {
78 id: u32, pad04: u32, stringData: BSTArray<StringData>, valueData: BSTArray<GlobalValueData>, journalStage: u16, journalStageItem: u8, pad3B: u8, pad3C: u32, }
87const _: () = assert!(core::mem::size_of::<BGSQuestInstanceText>() == 0x40);
88
89#[commonlibsse_ng_derive_internal::ffi_enum]
91#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
92#[repr(u8)]
93pub enum QuestType {
94 None = 0,
95 MainQuest = 1,
96 MagesGuild = 2,
97 ThievesGuild = 3,
98 DarkBrotherhood = 4,
99 CompanionsQuest = 5,
100 Miscellaneous = 6,
101 Daedric = 7,
102 SideQuest = 8,
103 CivilWar = 9,
104 DLC01Vampire = 10,
105 DLC02Dragonborn = 11,
106}
107
108#[repr(C)]
109#[derive(Debug, Clone)]
110pub struct QUEST_DATA {
111 pub questDelayTime: f32, pub flags: QuestFlag, pub priority: i8, pub questType: QuestType, }
116const _: () = assert!(core::mem::size_of::<QUEST_DATA>() == 0x8);
117
118#[commonlibsse_ng_derive_internal::to_bitflags]
119#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
120#[repr(u8)]
121pub enum QuestStageFlag {
122 #[default]
123 None = 0,
124 StartUpStage = 1 << 1,
125 ShutDownStage = 1 << 2,
126 KeepInstanceDataFromHereOn = 1 << 3,
127}
128
129#[repr(C)]
130#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
131pub struct QUEST_STAGE_DATA {
132 pub index: u16, pub flags: QuestStageFlag, pad3: u8, pad4: u32, }
137const _: () = assert!(core::mem::size_of::<QUEST_STAGE_DATA>() == 0x8);
138
139#[repr(C)]
140#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
141pub struct TESQuestStage {
142 pub data: QUEST_STAGE_DATA,
143}
144const _: () = assert!(core::mem::size_of::<TESQuestStage>() == 0x8);
145
146unsafe impl std_fork::zeroable::Zeroable for TESQuestStage {}
148
149#[commonlibsse_ng_derive_internal::to_bitflags]
150#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
151#[repr(u8)]
152pub enum TESQuestTargetFlag {
153 None = 0,
154 CompassMarkerIgnoresLocks = 1 << 0,
155}
156
157#[repr(C)]
158#[derive(Debug, PartialEq)]
159pub struct TESQuestTarget {
160 pub unk00: u64, pub conditions: TESCondition, pub alias: u8, pub unk11: u8, pub unk12: u16, pub unk14: u32, }
167const _: () = assert!(core::mem::size_of::<TESQuestTarget>() == 0x18);
168
169#[repr(C)]
170#[derive(Debug, Clone)]
171pub struct BGSQuestObjective {
172 displayText: BSFixedString, ownerQuest: *mut TESQuest, targets: *mut *mut TESQuestTarget, numTargets: u32, index: u16, initialized: bool, state: QUEST_OBJECTIVE_STATE, flags: QUEST_OBJECTIVE_FLAGS, pad24: u32, }
182const _: () = assert!(core::mem::size_of::<BGSQuestObjective>() == 0x28);
183
184#[repr(C)]
185#[derive(Debug, Clone)]
186pub struct BGSStoryEvent {
187 pub id: u32,
188 pub index: u32,
189 pub members: [u64; 6],
190}
191const _: () = assert!(core::mem::size_of::<BGSStoryEvent>() == 0x38);
192
193#[commonlibsse_ng_derive_internal::to_bitflags]
194#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
195#[repr(u32)]
196pub enum ChangeFlag {
197 QuestFlags = 1 << 1,
198 QuestScriptDelay = 1 << 2,
199 QuestAlreadyRun = 1 << 26,
200 QuestInstanceData = 1 << 27,
201 QuestRuntimeData = 1 << 28,
202 QuestObjectives = 1 << 29,
203 QuestScript = 1 << 30,
204 QuestStages = 1 << 31,
205}
206
207#[commonlibsse_ng_derive_internal::to_bitflags]
208#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
209#[repr(u32)]
210pub enum RecordFlag {
211 Deleted = 1 << 5,
212 Ignored = 1 << 12,
213}
214
215const BRANCHED_TOTAL: usize = DIALOGUE_TYPE::BRANCHED_TOTAL;
216const TOPICS_SIZE: usize = DIALOGUE_TYPE_CEnum::count() - BRANCHED_TOTAL;
217
218#[repr(C)]
219#[derive(Debug)]
220pub struct TESQuest {
221 pub __base: BGSStoryManagerTreeForm, pub __base1: TESFullName, pub instanceData: BSTArray<*mut BGSQuestInstanceText>, pub currentInstanceID: u32, pub pad054: u32, pub aliases: BSTArray<*mut BGSBaseAlias>, pub refAliasMap: BSTHashMap<u32, ObjectRefHandle>, pub unk0A0: BSTHashMap<UnkKey, UnkValue>, pub aliasAccessLock: BSReadWriteLock, pub data: QUEST_DATA, pub eventID: QuestEvent, pub pad0E4: u32, pub executedStages: *mut BSSimpleList<TESQuestStage>, pub waitingStages: *mut BSSimpleList<*mut TESQuestStage>, pub objectives: BSSimpleList<*mut BGSQuestObjective>, pub objConditions: TESCondition, pub storyManagerConditions: TESCondition, pub branchedDialogue:
239 [BSTHashMap<*mut BGSDialogueBranch, *mut BSTArray<*mut TESTopic>>; BRANCHED_TOTAL], pub topics: [BSTArray<*mut TESTopic>; TOPICS_SIZE], pub scenes: BSTArray<*mut BGSScene>, pub textGlobals: *mut BSTArray<*mut TESGlobal>, pub currentStage: u16, pub alreadyRun: bool, pub pad22B: u8, pub pad22C: u32, pub formEditorID: BSString, pub startEventData: *const BGSStoryEvent, pub promoteTask: NiPointer<QueuedPromoteQuestTask>, pub promotedRefs: BSTArray<ObjectRefHandle>, }
252const _: () = assert!(core::mem::size_of::<TESQuest>() == 0x268);
253
254impl TESQuest {
255 pub const RTTI: VariantID = RTTI_TESQuest;
256 pub const VTABLE: [VariantID; 2] = VTABLE_TESQuest;
257
258 #[inline]
263 pub const fn vtable(&self) -> &TESQuestVtbl {
264 let v_ptr = self.__base.__base.__base.vtable;
265 debug_assert!(!v_ptr.is_null(), "BGSStoryTellerVtbl ptr must not be null ptr");
266 unsafe { v_ptr.cast::<TESQuestVtbl>().as_ref().unwrap() }
267 }
268
269 #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 24537, ae_id = 25066)]
270 pub fn create_ref_handle_by_alias_id(
271 handle: &ObjectRefHandle,
272 alias_id: u32,
273 ) -> *mut ObjectRefHandle {
274 }
275
276 #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 24481, ae_id = 25003)]
277 pub fn ensure_quest_started(result: &mut bool, start_now: bool) -> bool {}
278
279 #[inline]
280 pub const fn get_current_stage_id(&self) -> u16 {
281 self.currentStage
282 }
283
284 #[inline]
285 pub const fn is_active(&self) -> bool {
286 self.data.flags.contains(QuestFlag::Active)
287 }
288
289 #[inline]
290 pub const fn is_completed(&self) -> bool {
291 self.data.flags.contains(QuestFlag::Completed)
292 }
293
294 #[inline]
295 pub const fn is_enabled(&self) -> bool {
296 self.data.flags.contains(QuestFlag::Enabled)
297 }
298
299 #[inline]
300 pub fn is_running(&self) -> bool {
301 !self.is_stopping() && self.promoteTask.is_null()
302 }
303
304 #[inline]
305 pub fn is_starting(&self) -> bool {
306 self.is_enabled()
307 && (self.data.flags == QuestFlag::StopStart || !self.promoteTask.is_null())
308 }
309
310 #[inline]
311 pub const fn is_stopped(&self) -> bool {
312 !(self.data.flags.contains(QuestFlag::Enabled)
313 || self.data.flags.contains(QuestFlag::StageWait))
314 }
315
316 #[inline]
317 pub fn is_stopping(&self) -> bool {
318 !self.is_enabled() && self.data.flags == QuestFlag::StopStart
319 }
320
321 #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 24486, ae_id = 25014)]
322 pub fn reset(&mut self) {}
323
324 pub fn reset_and_update(&mut self) {
325 self.reset();
326
327 let enabled = self.is_enabled();
328 if enabled != self.starts_enabled() {
329 if let Some(story_teller) = BGSStoryTeller::get_singleton_mut() {
330 if enabled {
331 story_teller.begin_start_up_quest(self);
332 } else {
333 story_teller.begin_shut_down_quest(self);
334 }
335 }
336 }
337 }
338
339 pub fn set_enabled(&mut self, value: bool) {
340 if value {
341 self.data.flags.insert(QuestFlag::Enabled);
342 } else {
343 self.data.flags.remove(QuestFlag::Enabled);
344 }
345
346 let add_change_fn = self.__base.__base.vtable().AddChange;
347 add_change_fn(&mut self.__base.__base, ChangeFlag::QuestFlags.bits());
348 }
349
350 pub fn start(&mut self) -> bool {
351 if self.eventID != QuestEvent::None {
352 #[cfg(feature = "tracing")]
353 tracing::warn!("Attempting to start event scoped quest outside of story manager");
354 return false;
355 }
356
357 let mut result = false;
358 Self::ensure_quest_started(&mut result, true)
359 }
360
361 #[inline]
362 pub const fn starts_enabled(&self) -> bool {
363 self.data.flags.contains(QuestFlag::StartsEnabled)
364 }
365
366 #[inline]
367 pub fn stop(&mut self) {
368 if self.is_enabled() {
369 self.set_enabled(false);
370 }
371 }
372}
373
374impl DerivedTESForm for TESQuest {
375 const FORM_TYPE: FormType = FormType::Quest;
376
377 #[inline]
378 fn get_form(&self) -> &TESForm {
379 &self.__base.__base
380 }
381}
382
383#[repr(C)]
384pub struct TESQuestVtbl {
385 pub __base: BGSStoryManagerTreeFormVtbl, pub __base1: TESFullNameVtbl, }