From e04aef0a9ed10ce4572e9c01eddb0b9c5ed06e9b Mon Sep 17 00:00:00 2001 From: DudeMcDude Date: Fri, 10 Jun 2016 18:43:11 +0300 Subject: [PATCH] Fixes crash due to formatting objHnd with :x --- TemplePlus/critter.cpp | 19 +++ TemplePlus/critter.h | 2 + TemplePlus/d20_class.cpp | 46 ++++-- TemplePlus/d20_class.h | 12 +- TemplePlus/obj.cpp | 2 +- TemplePlus/spell.cpp | 23 ++- TemplePlus/spell.h | 4 +- TemplePlus/spell_structs.h | 3 + TemplePlus/ui/ui_char.cpp | 4 +- TemplePlus/ui/ui_char_editor.cpp | 251 ++++++++++++++++++++++++++++++- TemplePlus/ui/ui_char_editor.h | 31 +++- 11 files changed, 371 insertions(+), 26 deletions(-) diff --git a/TemplePlus/critter.cpp b/TemplePlus/critter.cpp index c594ac5b0..4f85f8145 100644 --- a/TemplePlus/critter.cpp +++ b/TemplePlus/critter.cpp @@ -1167,6 +1167,25 @@ int LegacyCritterSystem::GetSpellLvlCanCast(const objHndl& handle, SpellSourceTy return 0; } +int LegacyCritterSystem::GetSpellEnumsKnownByClass(const objHndl& handle, int spellClass, int* spellEnums, int capacity){ + // todo: PrC extension + auto obj = gameSystems->GetObj().GetObject(handle); + auto spKnown = obj->GetSpellArray(obj_f_critter_spells_known_idx); + auto n = 0; + for (auto i = 0u; i < spKnown.GetSize(); i++){ + auto &spData = spKnown[i]; + if (spData.classCode == spellClass){ + spellEnums[n++] = spData.spellEnum; + if (n >= capacity){ + logger->warn("GetSpellEnumsKnown: Too many spells known! It's over 802!"); + return n; + } + + } + } + return n; +} + int LegacyCritterSystem::GetCritterNumNaturalAttacks(objHndl obj){ auto n = 0; diff --git a/TemplePlus/critter.h b/TemplePlus/critter.h index 0154cbf66..91101244a 100644 --- a/TemplePlus/critter.h +++ b/TemplePlus/critter.h @@ -310,6 +310,8 @@ struct LegacyCritterSystem : temple::AddressTable int GetCritterAttackType(objHndl obj, int attackIdx); int GetBaseAttackBonus(const objHndl& handle, Stat classBeingLeveld = Stat::stat_strength); int GetSpellLvlCanCast(const objHndl& handle, SpellSourceType spellSourceType, SpellReadyingType spellReadyingType); + int GetSpellEnumsKnownByClass(const objHndl& handle, int spellClass, int* spellEnums, int capacity); + static int GetCritterNumNaturalAttacks(objHndl obj); bool IsWarded(objHndl obj); // checks if creature is warded from melee attacks (by stuff like Meld Into Stone, Tree Shape, Otiluke's Resislient Sphere) bool IsSummoned(objHndl obj); diff --git a/TemplePlus/d20_class.cpp b/TemplePlus/d20_class.cpp index 05013b566..42e58ea28 100644 --- a/TemplePlus/d20_class.cpp +++ b/TemplePlus/d20_class.cpp @@ -66,22 +66,21 @@ class D20ClassHooks : public TempleFix } } d20ClassHooks; -bool D20ClassSystem::isNaturalCastingClass(Stat classEnum) +bool D20ClassSystem::IsNaturalCastingClass(Stat classEnum, objHndl handle) { - if (classEnum == stat_level_bard || classEnum == stat_level_sorcerer) return 1; + if (classEnum == stat_level_bard || classEnum == stat_level_sorcerer) + return 1; return 0; } -bool D20ClassSystem::isNaturalCastingClass(uint32_t classEnum) -{ - Stat castedClassEnum = static_cast(classEnum); - if (classEnum == stat_level_bard || classEnum == stat_level_sorcerer) return 1; - return 0; +bool D20ClassSystem::IsNaturalCastingClass(uint32_t classEnum){ + return IsNaturalCastingClass((Stat)classEnum); } -bool D20ClassSystem::isVancianCastingClass(Stat classEnum) +bool D20ClassSystem::IsVancianCastingClass(Stat classEnum, objHndl handle ) { - if (classEnum == stat_level_cleric || classEnum == stat_level_druid || classEnum == stat_level_paladin || classEnum == stat_level_ranger || classEnum == stat_level_wizard) return 1; + if (classEnum == stat_level_cleric || classEnum == stat_level_druid || classEnum == stat_level_paladin || classEnum == stat_level_ranger || classEnum == stat_level_wizard) + return 1; return 0; } @@ -93,9 +92,32 @@ bool D20ClassSystem::IsCastingClass(Stat classEnum) bool D20ClassSystem::IsLateCastingClass(Stat classEnum) { - if (classEnum == stat_level_paladin || classEnum == stat_level_ranger) - return 1; - return 0; + auto classSpec = classSpecs.find(classEnum); + if (classSpec == classSpecs.end()) + return false; + + if (classSpec->second.spellListType == SpellListType::Paladin + || classSpec->second.spellListType == SpellListType::Ranger) + return true; + + /*if (classEnum == stat_level_paladin || classEnum == stat_level_ranger) + return 1;*/ + // todo: generalize for PrC's + return false; +} + +bool D20ClassSystem::IsArcaneCastingClass(Stat classCode, objHndl handle){ + auto classSpec = classSpecs.find(classCode); + if (classSpec == classSpecs.end()) + return false; + + if (classSpec->second.spellListType == SpellListType::Arcane + || classSpec->second.spellListType == SpellListType::Bardic) + return true; + + // todo handle PrC that can be either + + return false; } bool D20ClassSystem::HasDomainSpells(Stat classEnum){ diff --git a/TemplePlus/d20_class.h b/TemplePlus/d20_class.h index 3b3cdd408..14192a565 100644 --- a/TemplePlus/d20_class.h +++ b/TemplePlus/d20_class.h @@ -70,11 +70,12 @@ struct D20ClassSystem : temple::AddressTable Stat vanillaClassEnums[VANILLA_NUM_CLASSES]; std::map classEnums; const int ClassLevelMax = 20; - static bool isNaturalCastingClass(Stat classEnum); - static bool isNaturalCastingClass(uint32_t classEnum); - static bool isVancianCastingClass(Stat classEnum); - static bool IsCastingClass(Stat classEnum); - static bool IsLateCastingClass(Stat classEnum); // for classes like Ranger / Paladin that start casting on level 4 + bool IsNaturalCastingClass(Stat classEnum, objHndl handle = objHndl::null); + bool IsNaturalCastingClass(uint32_t classEnum); + bool IsVancianCastingClass(Stat classEnum, objHndl handle = objHndl::null); + bool IsCastingClass(Stat classEnum); + bool IsLateCastingClass(Stat classEnum); // for classes like Ranger / Paladin that start casting on level 4 + bool IsArcaneCastingClass(Stat stat, objHndl handle = objHndl::null); static bool HasDomainSpells(Stat classEnum); void ClassPacketAlloc(ClassPacket *classPkt); // allocates the three IdxTables within ClassPacket @@ -82,6 +83,7 @@ struct D20ClassSystem : temple::AddressTable uint32_t GetClassPacket(Stat classEnum, ClassPacket *classPkt); // fills the struct with content based on classEnum (e.g. Barbarian Feats in the featsIdxTable). Also STUB FOR PRESTIGE CLASSES! TODO int GetBaseAttackBonus(Stat classCode, uint32_t classLvl); // gets the class's BAB int GetSkillPts(Stat classEnum); + struct WildShapeSpec { int protoId; diff --git a/TemplePlus/obj.cpp b/TemplePlus/obj.cpp index 43da1d543..dd6697136 100644 --- a/TemplePlus/obj.cpp +++ b/TemplePlus/obj.cpp @@ -565,7 +565,7 @@ void Objects::Destroy(objHndl ObjHnd) { std::string name = this->GetDisplayName(ObjHnd, ObjHnd); logger->info("Destroying {}", name); if (destroyed.find(ObjHnd) != destroyed.end()) { - logger->error("Double destroying object {:x}", ObjHnd); + logger->error("Double destroying object {}", ObjHnd); } destroyed.insert(ObjHnd); diff --git a/TemplePlus/spell.cpp b/TemplePlus/spell.cpp index 5158cb7b6..26ac4bb8d 100644 --- a/TemplePlus/spell.cpp +++ b/TemplePlus/spell.cpp @@ -271,7 +271,7 @@ bool SpellPacketBody::IsVancian(){ if (spellSys.isDomainSpell(spellClass)) return true; - if (d20ClassSys.isVancianCastingClass(spellSys.GetCastingClass(spellClass))) + if (d20ClassSys.IsVancianCastingClass(spellSys.GetCastingClass(spellClass))) return true; return false; @@ -443,6 +443,14 @@ bool LegacySpellSystem::CheckAbilityScoreReqForSpell(objHndl handle, uint32_t sp return temple::GetRef(0x10075C60)(handle, spellEnum, statBeingRaised) != 0; } +int LegacySpellSystem::GetSpellClass(int classEnum, bool isDomain){ + if (isDomain){ + return classEnum; + } + + return 0x80 | classEnum; +} + const char* LegacySpellSystem::GetSpellEnumTAG(uint32_t spellEnum){ MesLine mesline; @@ -1348,7 +1356,7 @@ uint32_t LegacySpellSystem::spellCanCast(objHndl objHnd, uint32_t spellEnum, uin return 0; } - if (d20ClassSys.isNaturalCastingClass(spellClassCode & 0x7F)) + if (d20ClassSys.IsNaturalCastingClass(spellClassCode & 0x7F)) { if (numSpellsKnownTooHigh(objHnd)) return 0; @@ -1459,6 +1467,17 @@ bool LegacySpellSystem::IsSpellLike(int spellEnum){ && spellEnum <= SPELL_LIKE_ABILITY_RANGE); } +int LegacySpellSystem::GetSpellLevelBySpellClass(int spellEnum, int spellClass, objHndl handle){ + SpellEntry spEntry(spellEnum); + for (auto i = 0u; i < spEntry.spellLvlsNum; i++){ + if (spEntry.spellLvls[i].classCode == spellClass) + return spEntry.spellLvls[i].slotLevel; + } + + //todo add PrC support + return -1; +} + uint32_t LegacySpellSystem::pickerArgsFromSpellEntry(SpellEntry* spellEntry, PickerArgs * pickArgs, objHndl objHnd, uint32_t casterLvl) { return _pickerArgsFromSpellEntry(spellEntry, pickArgs, objHnd, casterLvl); diff --git a/TemplePlus/spell.h b/TemplePlus/spell.h index 20d408640..4a288d2d4 100644 --- a/TemplePlus/spell.h +++ b/TemplePlus/spell.h @@ -166,7 +166,7 @@ struct LegacySpellSystem : temple::AddressTable const char* GetSpellMesline(uint32_t line) const; bool CheckAbilityScoreReqForSpell(objHndl handle, uint32_t spellEnum, int statBeingRaised) const; - + int GetSpellClass(int classEnum, bool isDomain = false); static const char* GetSpellEnumTAG(uint32_t spellEnum); const char* GetSpellName(uint32_t spellEnum) const; @@ -194,6 +194,8 @@ struct LegacySpellSystem : temple::AddressTable bool IsArcaneSpellClass(uint32_t spellClass); static bool IsSpellLike(int spellEnum); // checks if the spell is in the Spell Like Ability range + int GetSpellLevelBySpellClass(int spellEnum, int spellClass, objHndl handle = objHndl::null); + uint32_t pickerArgsFromSpellEntry(SpellEntry * spellEntry, PickerArgs * pickArgs, objHndl objHnd, uint32_t casterLevel); uint32_t GetSpellRangeExact(SpellRangeType spellRangeType, uint32_t casterLevel, objHndl caster); diff --git a/TemplePlus/spell_structs.h b/TemplePlus/spell_structs.h index 1617bfd5f..31331a2a3 100644 --- a/TemplePlus/spell_structs.h +++ b/TemplePlus/spell_structs.h @@ -5,6 +5,9 @@ const uint32_t SPELL_ENUM_MAX_EXPANDED = 3999; #define NUM_SPELL_LEVELS 10 // spells are levels 0-9 #define MAX_SPELL_TARGETS 32 #define INV_IDX_INVALID 255 // indicates that a spell is not an item spell +#define SPELL_ENUM_LABEL_START 803 // the range of 803-812 is reserved for "spell labels" in the chargen / levelup spell UI +#define SPELL_ENUM_VACANT 802 // used for vacant spellbook slots +#define SPELL_ENUM_NEW_SLOT_START 1605 // for bard/sorc new spells; range is in 1605-1614 enum SpellStoreType : uint8_t{ spellStoreNone = 0, diff --git a/TemplePlus/ui/ui_char.cpp b/TemplePlus/ui/ui_char.cpp index f5a6352dc..9c7ef2f8b 100644 --- a/TemplePlus/ui/ui_char.cpp +++ b/TemplePlus/ui/ui_char.cpp @@ -304,7 +304,7 @@ void CharUiSystem::SpellsShow(objHndl obj) // show the first class's spellbook / spells memorized if (uiCharSpellTabsCount > 0 && !spellSys.isDomainSpell(navClassPackets[0].spellClassCode)) { auto classCode = spellSys.GetCastingClass(navClassPackets[0].spellClassCode ); - if (d20ClassSys.isVancianCastingClass(classCode)){ + if (d20ClassSys.IsVancianCastingClass(classCode)){ ui.WidgetSetHidden(charSpellPackets[0].classMemorizeWnd->widgetId, 0); } ui.WidgetSetHidden(charSpellPackets[0].classSpellbookWnd->widgetId, 0); @@ -553,7 +553,7 @@ void CharUiSystem::SpellsShow(objHndl obj) auto spellClassCode = navClassPackets[uiCharSpellsNavClassTabIdx].spellClassCode; if (!spellSys.isDomainSpell(spellClassCode)){ auto casterClassCode = spellSys.GetCastingClass(spellClassCode); - if (d20ClassSys.isNaturalCastingClass(casterClassCode)) + if (d20ClassSys.IsNaturalCastingClass(casterClassCode)) showMemSpells = false; } diff --git a/TemplePlus/ui/ui_char_editor.cpp b/TemplePlus/ui/ui_char_editor.cpp index a41a05450..f9d7a4e2c 100644 --- a/TemplePlus/ui/ui_char_editor.cpp +++ b/TemplePlus/ui/ui_char_editor.cpp @@ -12,11 +12,21 @@ #include "ui_render.h" #include #include +#include +#include +#include class UiCharEditor{ +friend class UiCharEditorHooks; + objHndl GetEditedChar(); + CharEditorSelectionPacket & GetCharEditorSelPacket(); + BOOL WidgetsInit(); BOOL SystemInit(GameSystemConf & conf); + + void SpellsActivate(); + int &GetState(); @@ -36,8 +46,31 @@ class UiCharEditor{ ColorRect classBtnShadowColor = ColorRect(0xFF000000); ColorRect classBtnColorRect = ColorRect(0xFFFFffff); TigTextStyle classBtnTextStyle; + + + CharEditorClassSystem& GetClass() const { + Expects(!!mClass); + return *mClass; + } + +private: + std::unique_ptr mClass; + //std::unique_ptr mStats; + //std::unique_ptr mFeatures; + //std::unique_ptr mSkills; + //std::unique_ptr mFeats; + //std::unique_ptr mSpells; } uiCharEditor; +objHndl UiCharEditor::GetEditedChar() +{ + return temple::GetRef(0x11E741A0); +} + +CharEditorSelectionPacket& UiCharEditor::GetCharEditorSelPacket(){ + return temple::GetRef(0x11E72F00); +} + BOOL UiCharEditor::WidgetsInit(){ static WidgetType1 classWnd(259,117, 405, 271); classWnd.widgetFlags = 1; @@ -89,6 +122,205 @@ BOOL UiCharEditor::SystemInit(GameSystemConf& conf){ return WidgetsInit(); } +void UiCharEditor::SpellsActivate(){ + //auto handle = GetEditedChar(); + //auto obj = gameSystems->GetObj().GetObject(handle); + //auto &selPkt = GetCharEditorSelPacket(); + + //// get the new caster level for the levelled class (1 indicates a newly taken class) + //auto casterLvlNew = 1; + //auto classLeveled = selPkt.classCode; + //auto lvls = obj->GetInt32Array(obj_f_critter_level_idx); + //for (auto i = 0u; i < lvls.GetSize(); i++){ + // auto classCode = static_cast(lvls[i]); + // if (classLeveled == classCode) // is the same the one being levelled + // casterLvlNew++; + //} + + + //auto &needPopulateEntries = temple::GetRef(0x10C4D4C4); + + //static auto setScrollbars = []() { + // auto sbId = temple::GetRef(0x10C737C0); + // ui.ScrollbarSetY(sbId, 0); + // auto numEntries = temple::GetRef(0x10C75A60); + // ui.ScrollbarSetYmax(sbId, max(0, numEntries - 20)); + // temple::GetRef(0x10C73C34) = 0; // scrollbarY + // ui.WidgetCopy(sbId, &temple::GetRef(0x10C736C0)); + + // auto &charEdSelPkt = uiCharEditor.GetCharEditorSelPacket(); + // auto sbAddedId = temple::GetRef(0x10C4D548); + // ui.ScrollbarSetY(sbAddedId, 0); ui.ScrollbarSetYmax(sbAddedId, max(0, charEdSelPkt.spellEnumsAddedCount - 20)); + // temple::GetRef(0x10C75BC0) = 0; // scrollbarY + // ui.WidgetCopy(sbAddedId, &temple::GetRef(0x10C75AC0)); + //}; + + //if (!needPopulateEntries) { + // setScrollbars(); + // return; + //} + + + //auto & spellFlags = temple::GetRef(0x10C72F20); + //memset(spellFlags, 0, sizeof(spellFlags)); + //selPkt.spellEnumToRemove = 0; + + + //auto isNewClass = casterLvlNew == 1; // todo: generalize for PrC's + + //// newly taken class + //if (isNewClass){ + // + // // let natural casters choose 4 cantrips + // auto count = 0; + // // todo: generalize to handle new base classes + // if (classLeveled == stat_level_bard || classLeveled == stat_level_sorcerer ){ + // selPkt.spellEnums[count++] = 803; // Spell Level 0 label + // for (int i = 1; i < 5; i++) { + // selPkt.spellEnums[count] = 802; + // spellFlags[count++] = 3; + // } + // + // selPkt.spellEnumsAddedCount = count; + // } + // + // // add 2 level 1 spells for wiz/sorc + // // todo: generalize to handle new base classes + // if (classLeveled == stat_level_wizard || classLeveled == stat_level_sorcerer){ + // selPkt.spellEnums[count++] = 804; // Spell Level 1 label + // for (int i = 0; i < 2; i++) { + // selPkt.spellEnums[count] = 802; + // spellFlags[count++] = 3; + // } + // selPkt.spellEnumsAddedCount = count; + // } + + // // bonus spells for wizards + // if (classLeveled == stat_level_wizard){ + // auto intScore = objects.StatLevelGet(handle, stat_intelligence); + // if (selPkt.statBeingRaised == stat_intelligence) + // intScore++; + // auto intScoreMod = objects.GetModFromStatLevel(intScore); + // for (auto i = 0; i < intScoreMod; i++){ + // selPkt.spellEnums[count] = 802; + // spellFlags[count++] = 3; + // } + // selPkt.spellEnumsAddedCount = count; + // } + //} + // + //// progressing with a class todo: generalize for PrC's + //else{ + // // 2 new spells for Vancians + // if (d20ClassSys.IsVancianCastingClass(classLeveled, handle) ){ + // for (int i = 0; i < 2; i++) { + // selPkt.spellEnums[selPkt.spellEnumsAddedCount] = SPELL_ENUM_VACANT; + // spellFlags[selPkt.spellEnumsAddedCount++] = 3; + // } + // } + + // // innate casters - show all known spells and add slots as necessary + // if (d20ClassSys.IsNaturalCastingClass(classLeveled, handle)){ + + // std::vector knownSpells; + // knownSpells.reserve(SPELL_ENUM_MAX_EXPANDED); + // // get all known spells for innate casters + // int numKnown = critterSys.GetSpellEnumsKnownByClass(handle, spellSys.GetSpellClass(classLeveled), &knownSpells[0], SPELL_ENUM_MAX_EXPANDED); + // selPkt.spellEnumsAddedCount = numKnown; + + // + // // get max spell level todo: extend! + // auto maxSpellLvl = casterLvlNew / 2; + // if (classLeveled == stat_level_bard) { + // maxSpellLvl = (casterLvlNew - 1) / 3 + 1; + // } + + // // add labels + // for (int spellLvl = 0u; spellLvl <= maxSpellLvl; spellLvl++) { + // //selPkt.spellEnums[selPkt.spellEnumsAddedCount++] = SPELL_ENUM_LABEL_START + spellLvl; + // knownSpells.push_back(SPELL_ENUM_LABEL_START + spellLvl); + // } + + // for (auto spellLvl = 0; spellLvl < maxSpellLvl; spellLvl++) { + // int numNewSpellsForLevel = + // d20LevelSys.GetSpellsPerLevel(handle, selPkt.classCode, spellLvl, casterLvlNew) + // - d20LevelSys.GetSpellsPerLevel(handle, selPkt.classCode, spellLvl, casterLvlNew-1); + // for (int i = 0; i < numNewSpellsForLevel; i++){ + // //selPkt.spellEnums[selPkt.spellEnumsAddedCount++] = SPELL_ENUM_NEW_SLOT_START + spellLvl ; + // knownSpells.push_back(SPELL_ENUM_NEW_SLOT_START + spellLvl); + // } + // } + // auto spellClass = spellSys.GetSpellClass(selPkt.classCode); + // std::sort(knownSpells.begin(), knownSpells.end(), [spellClass,handle](int first, int second){ + // auto firstIsLabel = (first >= SPELL_ENUM_LABEL_START) && (first < SPELL_ENUM_LABEL_START + 10); + // auto secondIsLabel = (second >= SPELL_ENUM_LABEL_START) && (second < SPELL_ENUM_LABEL_START + 10); + + // auto firstIsNewSlot = (first >= SPELL_ENUM_NEW_SLOT_START) && (first < SPELL_ENUM_NEW_SLOT_START + 10); + // auto secondIsNewSlot = (second >= SPELL_ENUM_NEW_SLOT_START) && (second < SPELL_ENUM_NEW_SLOT_START + 10); + + // auto firstSpellLvl = 0; + // if (firstIsLabel) + // firstSpellLvl = first - SPELL_ENUM_LABEL_START; + // else if (firstIsNewSlot) + // firstSpellLvl = first - SPELL_ENUM_NEW_SLOT_START; + // else + // firstSpellLvl = spellSys.GetSpellLevelBySpellClass(first, spellClass ,handle); + + // auto secondSpellLvl = 0; + // if (secondIsLabel) + // secondSpellLvl = first - SPELL_ENUM_LABEL_START; + // else if (secondIsNewSlot) + // secondSpellLvl = first - SPELL_ENUM_NEW_SLOT_START; + // else + // secondSpellLvl = spellSys.GetSpellLevelBySpellClass(second, spellClass ,handle); + + // if (firstSpellLvl != secondSpellLvl) + // return firstSpellLvl - secondSpellLvl; + + // if (firstIsLabel) + // return -1; + // if (secondIsLabel) + // return 1; + + // if (firstIsNewSlot){ + // if (secondIsNewSlot) + // return 0; + // else + // return 1; + // } + + // if (secondIsNewSlot) + // return -1; + + // return _stricmp(spellSys.GetSpellMesline(second), spellSys.GetSpellMesline(first) ); + + // }); + + // // convert the "New Spell Slot" enums to vacant enums (they were just used for sorting) + // for (auto i = 0u; i < knownSpells.size(); i++) { + // if (knownSpells[i] >= SPELL_ENUM_NEW_SLOT_START && knownSpells[i] < SPELL_ENUM_NEW_SLOT_START + 10){ + // knownSpells[i] = 802; + // spellFlags[i] = 3; + // } + // } + + // // mark old replaceable spells every 2rd level for sorcs / 3rd level for bards + + // if (numKnown > 0){ + // auto numSlots = selPkt.spellEnumsAddedCount; + + // } + // } + + + //} + + //// populate entries + + //setScrollbars(); + //needPopulateEntries = 0; // needPopulateEntries +} + int &UiCharEditor::GetState(){ return temple::GetRef(0x10BE8D34); } @@ -107,6 +339,23 @@ class UiCharEditorHooks : public TempleFix { void apply() override { - + /*replaceFunction(0x101A75F0, [](){ + uiCharEditor.SpellsActivate(); + });*/ } } uiCharEditorHooks; + + +CharEditorClassSystem::CharEditorClassSystem(const GameSystemConf& config) +{ +} + +CharEditorClassSystem::~CharEditorClassSystem() +{ +} + +const std::string& CharEditorClassSystem::GetName() const +{ + static std::string name("char_editor_class"); + return name; +} diff --git a/TemplePlus/ui/ui_char_editor.h b/TemplePlus/ui/ui_char_editor.h index 77b0ce649..e10227c16 100644 --- a/TemplePlus/ui/ui_char_editor.h +++ b/TemplePlus/ui/ui_char_editor.h @@ -2,6 +2,7 @@ #include "common.h" #include +struct UiResizeArgs; struct GameSystemConf; struct CharEditorSelectionPacket{ @@ -43,10 +44,27 @@ struct CharEditorSelectionPacket{ }; -struct CharEditorSystem{ +struct LegacyCharEditorSystem{ const char* name; BOOL(__cdecl *systemInit)(GameSystemConf *); - BOOL(__cdecl *systemReset)(void *); + BOOL(__cdecl *systemResize)(void *); + int systemReset; // unused + void(__cdecl *free)(); + void(__cdecl *hide)(); + void(__cdecl *show)(); + int(__cdecl *checkComplete)(); // checks if the char editing stage is complete (thus allowing you to move on to the next stage). This is checked at every render call. + int(__cdecl*debugMaybe)(); + void(__cdecl *reset)(CharEditorSelectionPacket & editSpec); + BOOL(__cdecl *activate)(); // inits values and sets appropriate states for buttons based on gameplay logic (e.g. stuff exclusive to certain classes etc.) +}; + + +class CharEditorSystem { +public: + virtual const std::string &GetName() const = 0; + virtual ~CharEditorSystem() = default; + //CharEditorSystem(const GameSystemConf &) = delete; + virtual BOOL Resize(const UiResizeArgs &) =0; int pad; // possibly some unused callback? void(__cdecl *free)(); void(__cdecl *hide)(); @@ -57,6 +75,15 @@ struct CharEditorSystem{ BOOL(__cdecl *activate)(); // inits values and sets appropriate states for buttons based on gameplay logic (e.g. stuff exclusive to certain classes etc.) }; + +class CharEditorClassSystem : public CharEditorSystem { +public: + static constexpr auto Name = "char_editor_class"; + CharEditorClassSystem(const GameSystemConf &config); + ~CharEditorClassSystem(); + const std::string &GetName() const override; +}; + const auto testSizeOfCharEditorSelectionPacket = sizeof(CharEditorSelectionPacket); // should be 3640 (0xE38)