From 2eca2a12ddf902394d6614e7fb461bd98a5f7377 Mon Sep 17 00:00:00 2001 From: DMD Date: Sun, 15 Apr 2018 07:23:02 +0300 Subject: [PATCH] Fix for Eldritch Knight issue (reverted changes to python methods - added functions to char_editor builtin module instead) --- TemplePlus/feat.cpp | 2 +- TemplePlus/feat.h | 2 +- TemplePlus/python/python_object.cpp | 109 ---------- TemplePlus/ui/ui_char_editor.cpp | 187 +++++++++++++++++- TemplePlus/ui/ui_char_editor.h | 22 +-- TemplePlus/ui/ui_chargen.h | 30 +++ TemplePlus/ui/ui_pc_creation.h | 17 -- tpdata/tpgamefiles.dat | Bin 3407893 -> 3408045 bytes tpdatasrc/tpgamefiles/rules/feats/craven.txt | 4 +- .../{scr => rules}/feats/deft opportunist.txt | 4 +- .../rules/feats/vexing flanker.txt | 2 +- .../tpgamefiles/scr/feats/feat - Craven.py | 6 +- .../scr/feats/feat - Divine Armor.py | 4 +- .../scr/feats/feat - Divine Shield.py | 6 +- .../scr/feats/feat - Divine Vigor.py | 4 +- .../scr/feats/feat - Extend Rage.py | 4 +- .../scr/feats/feat - Extra Music.py | 4 +- .../scr/feats/feat - Extra Rage.py | 4 +- .../scr/feats/feat - Extra Smiting.py | 8 +- .../feats/feat - Improved Favored Enemy.py | 4 +- .../scr/feats/feat - Improved Rapid Shot.py | 8 +- .../feat - Melee Weapon Mastery - Slashing.py | 2 +- .../feat - Practiced Spellcaster - Arcane.py | 4 +- .../feat - Practiced Spellcaster - Divine.py | 4 +- .../scr/feats/feat - Practiced Spellcaster.py | 4 +- .../scr/feats/feat - Rapid Metamagic.py | 4 +- 26 files changed, 262 insertions(+), 187 deletions(-) rename tpdatasrc/tpgamefiles/{scr => rules}/feats/deft opportunist.txt (62%) diff --git a/TemplePlus/feat.cpp b/TemplePlus/feat.cpp index bf7006225..42ff2b2d0 100644 --- a/TemplePlus/feat.cpp +++ b/TemplePlus/feat.cpp @@ -935,7 +935,7 @@ uint32_t LegacyFeatSystem::FeatPrereqsCheck(objHndl objHnd, feat_enums featIdx, // Class Level else if (featReqCode >= stat_level_barbarian && featReqCode <= stat_level_shadow_sun_ninja) { if (classCodeBeingLevelledUp == featReqCode) { featReqCodeArg--; } - if ((int)objects.StatLevelGet(objHnd, (Stat)featReqCode) < featReqCodeArg) { return 0; } + if (objects.StatLevelGet(objHnd, (Stat)featReqCode) < featReqCodeArg) { return 0; } } // BAB else if (featReqCode == stat_attack_bonus){ diff --git a/TemplePlus/feat.h b/TemplePlus/feat.h index 1e326ad8b..68f2d7e75 100644 --- a/TemplePlus/feat.h +++ b/TemplePlus/feat.h @@ -53,7 +53,7 @@ struct ClassFeatTable struct FeatPrereq { - int featPrereqCode; + int featPrereqCode; // see feat_requirement_codes int featPrereqCodeArg; }; diff --git a/TemplePlus/python/python_object.cpp b/TemplePlus/python/python_object.cpp index 6a2280932..5af52e858 100644 --- a/TemplePlus/python/python_object.cpp +++ b/TemplePlus/python/python_object.cpp @@ -49,15 +49,6 @@ namespace py = pybind11; -// Helper function for checking if information should be updated with chargen packet info -bool UpdateWithChargenPacketInfo(objHndl handle) { - - // Check that the query: 1) is for the character being edited, 2) is not about a new character (snice the changes - // would already be added in that case) and 3) that the feat page is up (info from the packet should only affect - // the availability of feats not which character classes are available) - return (handle == chargen.GetEditedChar() && !chargen.IsNewChar() && chargen.IsSelectingFeats()); -} - struct PyObjHandle { PyObject_HEAD; ObjectId id; @@ -634,14 +625,6 @@ static PyObject* PyObjHandle_SkillLevelGet(PyObject* obj, PyObject* args) { auto skillLevel = dispatch.dispatch1ESkillLevel(self->handle, skillId, nullptr, handle, 1); - // Add additional skill points from the character editor if necessary - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - if (skillId < skill_count) { - skillLevel += charPkt.skillPointsAdded[skillId]; - } - } - return PyInt_FromLong(skillLevel); } @@ -660,14 +643,6 @@ static PyObject* PyObjHandle_SkillRanksGet(PyObject* obj, PyObject* args) { auto skillRanks = critterSys.SkillBaseGet(self->handle, skillId); - // Add additional skill points from the character editor if necessary - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - if (skillId < skill_count) { - skillRanks += charPkt.skillPointsAdded[skillId]; - } - } - return PyInt_FromLong(skillRanks); } @@ -744,17 +719,6 @@ static PyObject* PyObjHandle_GetBaseAttackBonus(PyObject* obj, PyObject* args) { auto bab = critterSys.GetBaseAttackBonus(self->handle); - // Recalculate bab based on new class level from character editor if necessary - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - - // Subtract the current base attack bouns for that character level from the new and add to the bab - int levelupClassLevel = objects.StatLevelGet(self->handle, charPkt.classCode); - int babCur = d20ClassSys.GetBaseAttackBonus(charPkt.classCode, levelupClassLevel); - int babNext = d20ClassSys.GetBaseAttackBonus(charPkt.classCode, levelupClassLevel+1); - int babDelta = babNext - babCur; - bab += babDelta; - } return PyInt_FromLong(bab); } @@ -774,22 +738,6 @@ static PyObject* PyObjHandle_StatLevelGet(PyObject* obj, PyObject* args) { auto statLevel = objects.StatLevelGet(self->handle, stat); - // Check on raising attribute or character level - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - - // Increase character level if appropriate - if (charPkt.classCode == stat) { - statLevel++; - } - - // Report 1 higher if the stat is being raised - if (stat == charPkt.statBeingRaised) { - statLevel++; - } - - } - return PyInt_FromLong(statLevel); } @@ -2593,35 +2541,6 @@ static PyObject* PyObjHandle_GetInt(PyObject* obj, PyObject* args) { { value = objects.getInt32(self->handle, field); - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - - // If this is the first level of cleric, return the selected alignmetn choice - if (field == stat_alignment_choice) { - if (charPkt.classCode == stat_level_cleric) { - int clericLevel = objects.StatLevelGet(self->handle, charPkt.classCode); - if (clericLevel == 1) { - value = charPkt.alignmentChoice; - } - } - } - - // Check if this character is being edited, if so take that into account - if (UpdateWithChargenPacketInfo(self->handle)) { - if (charPkt.classCode == stat_level_cleric) { - int clericLevel = objects.StatLevelGet(self->handle, charPkt.classCode); - if (clericLevel == 0) { //Must be the first cleric level - if (field == obj_f_critter_domain_1) { - value = charPkt.domain1; - } - if (field == obj_f_critter_domain_2) { - value = charPkt.domain2; - } - } - } - } - } - } else if (objectFields.GetType(field) == ObjectFieldType::Float32) { value = (int) objSystem->GetObject(self->handle)->GetFloat(field); @@ -2716,36 +2635,8 @@ static PyObject* PyObjHandle_HasFeat(PyObject* obj, PyObject* args) { uint32_t domain2 = 0; uint32_t alignmentChoice = 0; - // Update domains and alignment choice with info from the character editor if appropriate - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - levelRaised = charPkt.classCode; - if (levelRaised == stat_level_cleric) { - domain1 = charPkt.domain1; - domain2 = charPkt.domain2; - alignmentChoice = charPkt.alignmentChoice; - } - } - auto result = feats.HasFeatCountByClass(self->handle, feat, levelRaised, 0, domain1, domain2, alignmentChoice); - //Incriment the feat count if the feat has been selected on the levelup interface - if (UpdateWithChargenPacketInfo(self->handle)) { - auto charPkt = chargen.GetCharEditorSelPacket(); - if (feat == charPkt.feat0) { - result++; - } - if (feat == charPkt.feat1) { - result++; - } - if (feat == charPkt.feat2) { - result++; - } - if (feat == charPkt.feat3) { - result++; - } - } - return PyInt_FromLong(result); } diff --git a/TemplePlus/ui/ui_char_editor.cpp b/TemplePlus/ui/ui_char_editor.cpp index 81df8a314..929ed6b4e 100644 --- a/TemplePlus/ui/ui_char_editor.cpp +++ b/TemplePlus/ui/ui_char_editor.cpp @@ -35,11 +35,12 @@ #include #include "ui_assets.h" #include +#include "gamesystems/deity/legacydeitysystem.h" namespace py = pybind11; Chargen chargen; - +temple::GlobalStruct lgcySystems; class UiCharEditor { friend class UiCharEditorHooks; public: @@ -93,6 +94,9 @@ class UiCharEditor { #pragma region Widget callbacks void StateTitleRender(int widId); + void MainWndRender(int widId); + + void ClassBtnRender(int widId); BOOL ClassBtnMsg(int widId, TigMsg* msg); BOOL ClassNextBtnMsg(int widId, TigMsg* msg); @@ -134,10 +138,11 @@ class UiCharEditor { eastl::vector classBtnMapping; // used as an index of choosable character classes int GetClassWndPage(); Stat GetClassCodeFromWidgetAndPage(int idx, int page); - int GetStatesComplete(); + int &GetStatesComplete(); // logic void ClassSetPermissibles(); + bool ClassSanitize(); // re-check class requirements. Returns true if re-evaluation is required. bool IsSelectingNormalFeat(); // the normal feat you get every 3rd level in 3.5ed bool IsSelectingBonusFeat(); // selecting a class bonus feat @@ -379,6 +384,114 @@ PYBIND11_EMBEDDED_MODULE(char_editor, mm) { // methods #pragma region methods mm + .def("stat_level_get", [](int statEnum, int statArg)->int{ + auto stat = (Stat)statEnum; + auto handle = chargen.GetEditedChar(); + auto &charPkt = chargen.GetCharEditorSelPacket(); + + auto statLvl = 0; + if (statArg != -1) + statLvl = objects.StatLevelGet(handle, stat, statArg); + else + statLvl = objects.StatLevelGet(handle, stat); + + // Increase character level if appropriate + if (!chargen.IsNewChar()){ + if (charPkt.classCode == stat) { + statLvl++; + } + // Report 1 higher if the stat is being raised + if (stat == charPkt.statBeingRaised) { + statLvl++; + } + } + + return statLvl; + }, py::arg("stat"), py::arg("stat_arg") = -1) + .def("skill_level_get", [](int skillEnum)->int { + auto skill = (SkillEnum)skillEnum; + auto handle = chargen.GetEditedChar(); + auto &charPkt = chargen.GetCharEditorSelPacket(); + + auto skillLevel = critterSys.SkillLevel(handle, skill); + + // Add additional skill points from the character editor if necessary + + if (!chargen.IsNewChar()) { + auto levelRaised = charPkt.classCode; + auto pointsSpent = 0; + if (skill >= 0 && skill < skill_count) { + pointsSpent += charPkt.skillPointsAdded[skill]; + } + // Check if class skill - if not, halve their contribution (TODO sucks if skillLevel itself was rounded down :( ) + auto numAdded = pointsSpent/2; + if (d20ClassSys.IsClassSkill(skill, levelRaised) || + (levelRaised == stat_level_cleric && deitySys.IsDomainSkill(handle, skill)) + || d20Sys.D20QueryPython(handle, "Is Class Skill", skill)) { + numAdded = pointsSpent; + } + + skillLevel += numAdded; + + } + return skillLevel; + }) + .def("skill_ranks_get", [](int skillEnum)->int { + auto skill = (SkillEnum)skillEnum; + auto handle = chargen.GetEditedChar(); + auto &charPkt = chargen.GetCharEditorSelPacket(); + + // Add additional skill points from the character editor if necessary + auto skillRanks = critterSys.SkillBaseGet(handle, skill); + + if (!chargen.IsNewChar()){ + if (skill < skill_count) { + skillRanks += charPkt.skillPointsAdded[skill]; + } + } + return skillRanks; + }) + .def("has_feat", [](int featEnum)->int{ + auto feat = (feat_enums)featEnum; + auto handle = chargen.GetEditedChar(); + auto &charPkt = chargen.GetCharEditorSelPacket(); + + auto levelRaised = charPkt.classCode; + if (chargen.IsNewChar()) + levelRaised = (Stat)0; + + uint32_t domain1 = Domain_None; + uint32_t domain2 = Domain_None; + uint32_t alignmentChoice = 0; + + if (!chargen.IsNewChar()){ + if (levelRaised == stat_level_cleric) { + domain1 = charPkt.domain1; + domain2 = charPkt.domain2; + alignmentChoice = charPkt.alignmentChoice; + } + } + + + auto result = feats.HasFeatCountByClass(handle, feat, levelRaised, 0, domain1, domain2, alignmentChoice); + + if (feat == charPkt.feat0) { + result++; + } + if (feat == charPkt.feat1) { + result++; + } + if (feat == charPkt.feat2) { + result++; + } + if (feat == charPkt.feat3) { + result++; + } + + return result; + + }) + .def("set_bonus_feats", [](std::vector & fti){ chargen.SetBonusFeats(fti); }) @@ -1075,13 +1188,13 @@ BOOL UiCharEditor::FeatsWidgetsResize(UiResizeArgs & args){ bool UiCharEditor::IsSelectingFeats() { - bool bRes = false; + auto result = false; if (uiManager) { - bRes = !uiManager->IsHidden(featsMainWndId); + result = !uiManager->IsHidden(featsMainWndId); } - return bRes; + return result; } BOOL UiCharEditor::FeatsShow(){ @@ -1388,6 +1501,48 @@ void UiCharEditor::StateTitleRender(int widId){ UiRenderer::PopFont(); } +void UiCharEditor::MainWndRender(int widId){ + auto &dword_10BE9970 = temple::GetRef(0x10BE9970); + if (!dword_10BE9970){ + auto statesComplete = 0; + + auto stage = 0; + auto &mStagesComplete = GetStatesComplete(); + auto &selPkt = GetCharEditorSelPacket(); + auto &mActiveStage = GetState(); + + + for (stage = 0; stage < std::min(mStagesComplete + 1, (int)CharEditorStages::CE_STAGE_COUNT); stage++) { + auto &sys = lgcySystems[stage]; + if (!sys.checkComplete) + break; + if (!sys.checkComplete()) + break; + } + + if (stage != mStagesComplete) { + mStagesComplete = stage; + if (mActiveStage > stage) + mActiveStage = stage; + + // reset the next stages + for (auto nextStage = stage + 1; nextStage < CharEditorStages::CE_STAGE_COUNT; nextStage++) { + if (lgcySystems[nextStage].reset) { + lgcySystems[nextStage].reset(selPkt); + } + } + } + } + + auto wnd = uiManager->GetWindow(widId); + RenderHooks::RenderImgFile(temple::GetRef(0x10BE9974), wnd->x, wnd->y); + + UiRenderer::DrawTextureInWidget( widId, temple::GetRef(0x10BE993C), + {406, 15, 120, 227} , { 1,1,120,227 }); + + +} + void UiCharEditor::ClassBtnRender(int widId){ auto idx = WidgetIdIndexOf(widId, &classBtnIds[0], classBtnIds.size()); if (idx == -1) @@ -1450,6 +1605,10 @@ BOOL UiCharEditor::ClassBtnMsg(int widId, TigMsg * msg){ GetCharEditorSelPacket().classCode = classCode; PrepareNextStages(); temple::GetRef(0x10143FF0)(0); // resets all the next systems in case of change + if (ClassSanitize()) { // resets the chosen class in case the user cheats (e.g. by selecting skills up ahead) + PrepareNextStages(); + temple::GetRef(0x10143FF0)(0); // resets all the next systems in case of change + } return 1; } @@ -2870,7 +3029,7 @@ Stat UiCharEditor::GetClassCodeFromWidgetAndPage(int idx, int page){ return (Stat)classBtnMapping[idx2]; } -int UiCharEditor::GetStatesComplete(){ +int& UiCharEditor::GetStatesComplete(){ return temple::GetRef(0x10BE8D38); } @@ -2908,6 +3067,18 @@ void UiCharEditor::ClassSetPermissibles(){ uiManager->SetButtonState(classNextBtn, LgcyButtonState::Disabled); } +bool UiCharEditor::ClassSanitize(){ + auto handle = GetEditedChar(); + auto &selPkt = GetCharEditorSelPacket(); + auto classCode = selPkt.classCode; + if (!d20ClassSys.ReqsMet(handle, classCode) || !pythonClassIntegration.IsAlignmentCompatible(handle, classCode)){ + selPkt.classCode = (Stat)0; + return true; + } + + return false; +} + int UiCharEditor::GetNewLvl(Stat classEnum){ // default is classEnum = stat_level i.e. get the overall new level auto handle = GetEditedChar(); @@ -2922,6 +3093,10 @@ class UiCharEditorHooks : public TempleFix { void apply() override { // general + replaceFunction(0x10148880, [](int widId){ + uiCharEditor.MainWndRender(widId); + }); + replaceFunction(0x101B0760, []() { uiCharEditor.PrepareNextStages(); }); diff --git a/TemplePlus/ui/ui_char_editor.h b/TemplePlus/ui/ui_char_editor.h index fa98e8c92..b703715ee 100644 --- a/TemplePlus/ui/ui_char_editor.h +++ b/TemplePlus/ui/ui_char_editor.h @@ -28,20 +28,16 @@ enum FeatInfoFlag }; -struct LegacyCharEditorSystem{ - const char* name; - BOOL(__cdecl *systemInit)(GameSystemConf *); - BOOL(__cdecl *systemResize)(void *); - int systemReset; // unused - void(__cdecl *free)(); - void(__cdecl *hide)(); - void(__cdecl *show)(); - BOOL(__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. - void(__cdecl *finalize)(CharEditorSelectionPacket &selPkt, objHndl &handle); //applies the configuration when clicking the "finish" button - 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.) -}; +enum CharEditorStages : int { + CE_Stage_Class = 0, + CE_Stage_Stats, + CE_Stage_Features, + CE_Stage_Skills, + CE_Stage_Feats, + CE_Stage_Spells, + CE_STAGE_COUNT +}; class CharEditorSystem { public: diff --git a/TemplePlus/ui/ui_chargen.h b/TemplePlus/ui/ui_chargen.h index ff6430da5..7b5a7a4fb 100644 --- a/TemplePlus/ui/ui_chargen.h +++ b/TemplePlus/ui/ui_chargen.h @@ -3,6 +3,7 @@ #include "widgets/widgets.h" class ChargenBigButton; +struct UiSystemConf; struct CharEditorSelectionPacket { int abilityStats[6]; @@ -118,4 +119,33 @@ class IPagedButton class ChargenPagedButton : public ChargenBigButton, public IPagedButton { +}; + +class LgcyChargenSystem { +public: + const char* name; + void(*Reset)(CharEditorSelectionPacket & charSpec); + void(*Activate)(); + BOOL(*SystemInit)(const UiSystemConf *); + void(*Free)(); + BOOL(*Resize)(UiResizeArgs &resizeArgs); + void(*Hide)(); + void(*Show)(); + BOOL(*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. + void(*Finalize)(CharEditorSelectionPacket & charSpec, objHndl & handle); + void(*ButtonExited)(); +}; + +struct LegacyCharEditorSystem { + const char* name; + BOOL(__cdecl *systemInit)(GameSystemConf *); + BOOL(__cdecl *systemResize)(void *); + int systemReset; // unused + void(__cdecl *free)(); + void(__cdecl *hide)(); + void(__cdecl *show)(); + BOOL(__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. + void(__cdecl *finalize)(CharEditorSelectionPacket &selPkt, objHndl &handle); //applies the configuration when clicking the "finish" button + 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.) }; \ No newline at end of file diff --git a/TemplePlus/ui/ui_pc_creation.h b/TemplePlus/ui/ui_pc_creation.h index 09d105e41..899f0d80b 100644 --- a/TemplePlus/ui/ui_pc_creation.h +++ b/TemplePlus/ui/ui_pc_creation.h @@ -9,7 +9,6 @@ struct UiSystemConf; class CombinedImgFile; -class LgcyChargenSystem; enum ChargenStages : int { CG_Stage_Stats = 0, @@ -456,19 +455,3 @@ class UiPcCreation { int __cdecl PcCreationFeatUiPrereqCheck(feat_enums feat); extern UiPcCreation uiPcCreation; - - -class LgcyChargenSystem { -public: - const char* name; - void(*Reset)(CharEditorSelectionPacket & charSpec); - void(*Activate)(); - BOOL(*SystemInit)(const UiSystemConf *); - void(*Free)(); - BOOL(*Resize)(UiResizeArgs &resizeArgs); - void(*Hide)(); - void(*Show)(); - BOOL(*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. - void(*Finalize)(CharEditorSelectionPacket & charSpec, objHndl & handle); - void(*ButtonExited)(); -}; diff --git a/tpdata/tpgamefiles.dat b/tpdata/tpgamefiles.dat index 7cc88e7a9a0383434fb46f52de3ee8a0c6411999..24276dcb002d9b07f4835e3c7468d8d7a8c62153 100644 GIT binary patch delta 14316 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 XNz9(@Jhsecy5nd)Trc&cJl_8S$l-6G diff --git a/tpdatasrc/tpgamefiles/rules/feats/craven.txt b/tpdatasrc/tpgamefiles/rules/feats/craven.txt index a351235e1..9c3d1bb59 100644 --- a/tpdatasrc/tpgamefiles/rules/feats/craven.txt +++ b/tpdatasrc/tpgamefiles/rules/feats/craven.txt @@ -1,5 +1,5 @@ name: Craven -flags: 8388608 +flags: 12582912 prereqs: -description: 1 extra damage per character level for sneak attacks, -2 to saving throws against fear. +description: 1 extra damage per character level for sneak attacks, -2 to saving throws against fear. prereq descr: Sneak Attack, Can't be immune to fear diff --git a/tpdatasrc/tpgamefiles/scr/feats/deft opportunist.txt b/tpdatasrc/tpgamefiles/rules/feats/deft opportunist.txt similarity index 62% rename from tpdatasrc/tpgamefiles/scr/feats/deft opportunist.txt rename to tpdatasrc/tpgamefiles/rules/feats/deft opportunist.txt index 5c3cec6fe..ea20088e8 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/deft opportunist.txt +++ b/tpdatasrc/tpgamefiles/rules/feats/deft opportunist.txt @@ -1,5 +1,5 @@ name: Deft Opportunist flags: 4194304 -prereqs: 1580 1 stat_dexterity 15 +prereqs: 1580 1 1 15 description: You get a +4 bonus on attack rolls when making attacks of opportunity. -prereq descr: Combat Reflexes, DEX 15 +prereq descr: Combat Reflexes, Dex 15 diff --git a/tpdatasrc/tpgamefiles/rules/feats/vexing flanker.txt b/tpdatasrc/tpgamefiles/rules/feats/vexing flanker.txt index 6d4550227..2775e686e 100644 --- a/tpdatasrc/tpgamefiles/rules/feats/vexing flanker.txt +++ b/tpdatasrc/tpgamefiles/rules/feats/vexing flanker.txt @@ -1,5 +1,5 @@ name: Vexing Flanker flags: 4194320 -prereqs: 1013 1 +prereqs: 1580 1 description: When you take this feat your flanking bonus becomes +4. prereq descr: Combat Reflexes diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Craven.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Craven.py index ee63501c7..b56efd8b5 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Craven.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Craven.py @@ -1,11 +1,11 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Sneak Attack Check - if not attachee.has_feat(feat_sneak_attack): + if not char_editor.has_feat(feat_sneak_attack): return 0 - if attachee.stat_level_get(stat_level_paladin) > 1: #workaround until I figure out how to check for immunity to fear + if char_editor.stat_level_get(stat_level_paladin) > 1: #workaround until I figure out how to check for immunity to fear return 0 return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Armor.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Armor.py index 2c99de26b..fc6830d16 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Armor.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Armor.py @@ -1,10 +1,10 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Req 1, turn undead feat - if not (attachee.has_feat(feat_turn_undead) or attachee.has_feat(feat_rebuke_undead)): + if not (char_editor.has_feat(feat_turn_undead) or char_editor.has_feat(feat_rebuke_undead)): return 0 #Req2, Divine Caster Level 5 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Shield.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Shield.py index 6ef084ecb..2b94ff212 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Shield.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Shield.py @@ -1,14 +1,14 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Req 1, turn undead feat - if not (attachee.has_feat(feat_turn_undead) or attachee.has_feat(feat_rebuke_undead)): + if not (char_editor.has_feat(feat_turn_undead) or char_editor.has_feat(feat_rebuke_undead)): return 0 #Req2, shield proficency - if not attachee.has_feat(feat_shield_proficiency): + if not char_editor.has_feat(feat_shield_proficiency): return 0 return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Vigor.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Vigor.py index b11eb94b7..64b0bdcee 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Vigor.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Divine Vigor.py @@ -1,10 +1,10 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Turn or rebuke undead feat - if (attachee.has_feat(feat_turn_undead) or attachee.has_feat(feat_rebuke_undead)): + if (char_editor.has_feat(feat_turn_undead) or char_editor.has_feat(feat_rebuke_undead)): return 1 return 0 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Extend Rage.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Extend Rage.py index a320033f3..9f4f23a07 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Extend Rage.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Extend Rage.py @@ -1,10 +1,10 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Barbarian Rage Check - if not attachee.has_feat(feat_barbarian_rage): + if not char_editor.has_feat(feat_barbarian_rage): return 0 return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Music.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Music.py index 2424dbc7b..7be5e46ff 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Music.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Music.py @@ -1,9 +1,9 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Bardic Music Check - if not attachee.has_feat(feat_bardic_music): + if not char_editor.has_feat(feat_bardic_music): return 0 return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Rage.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Rage.py index a320033f3..9f4f23a07 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Rage.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Rage.py @@ -1,10 +1,10 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Barbarian Rage Check - if not attachee.has_feat(feat_barbarian_rage): + if not char_editor.has_feat(feat_barbarian_rage): return 0 return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Smiting.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Smiting.py index b4bed5638..a66ccc534 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Smiting.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Extra Smiting.py @@ -1,5 +1,5 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Return zero if base attack bonus is too low @@ -7,7 +7,7 @@ def CheckPrereq(attachee, classLevelled, abilityScoreRaised): return 0 #Paladin Smite Evil Check - if attachee.has_feat(feat_smite_evil): + if char_editor.has_feat(feat_smite_evil): return 1 #Destruction Domain Check @@ -17,11 +17,11 @@ def CheckPrereq(attachee, classLevelled, abilityScoreRaised): return 1 #Blackguard Smite for level 2 or greater black guards - if attachee.stat_level_get(stat_level_blackguard) >= 2: + if char_editor.stat_level_get(stat_level_blackguard) >= 2: return 1 #Blackguard Smite for level 1 with at least one paladin level - if attachee.stat_level_get(stat_level_blackguard) == 1 and attachee.stat_level_get(stat_level_paladin) >= 1: + if char_editor.stat_level_get(stat_level_blackguard) == 1 and char_editor.stat_level_get(stat_level_paladin) >= 1: return 1 return 0 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Favored Enemy.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Favored Enemy.py index b975ad7b5..5c768291b 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Favored Enemy.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Favored Enemy.py @@ -1,5 +1,5 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): @@ -9,7 +9,7 @@ def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Check for any favored enemy feat for i in range (feat_favored_enemy_aberration , feat_favored_enemy_humanoid_human): - if attachee.has_feat(i): + if char_editor.has_feat(i): return 1 return 0 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Rapid Shot.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Rapid Shot.py index 8803e1ef6..223da01cc 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Rapid Shot.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Improved Rapid Shot.py @@ -1,12 +1,12 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Many Shot, Point Blank Shot and Rapid Shot are required either standard feats or from the ranger class - if attachee.has_feat(feat_manyshot) or attachee.has_feat(feat_ranger_manyshot): - if attachee.has_feat(feat_rapid_shot) or attachee.has_feat(feat_ranger_rapid_shot): - if attachee.has_feat(feat_point_blank_shot): + if char_editor.has_feat(feat_manyshot) or char_editor.has_feat(feat_ranger_manyshot): + if char_editor.has_feat(feat_rapid_shot) or char_editor.has_feat(feat_ranger_rapid_shot): + if char_editor.has_feat(feat_point_blank_shot): return 1 return 0 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Melee Weapon Mastery - Slashing.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Melee Weapon Mastery - Slashing.py index e323acc7b..0ea37e7b8 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Melee Weapon Mastery - Slashing.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Melee Weapon Mastery - Slashing.py @@ -1,5 +1,5 @@ from toee import * - +import char_editor featDamType = D20DT_SLASHING def CheckPrereq(attachee, classLevelled, abilityScoreRaised): diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Arcane.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Arcane.py index 0ef26e989..6c2540a9e 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Arcane.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Arcane.py @@ -1,8 +1,8 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): - spellcraft_level = attachee.skill_ranks_get(skill_spellcraft) + spellcraft_level = char_editor.skill_ranks_get(skill_spellcraft) if spellcraft_level < 4: return 0 return 1 \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Divine.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Divine.py index 0ef26e989..6c2540a9e 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Divine.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster - Divine.py @@ -1,8 +1,8 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): - spellcraft_level = attachee.skill_ranks_get(skill_spellcraft) + spellcraft_level = char_editor.skill_ranks_get(skill_spellcraft) if spellcraft_level < 4: return 0 return 1 \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster.py index 0ef26e989..6c2540a9e 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Practiced Spellcaster.py @@ -1,8 +1,8 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): - spellcraft_level = attachee.skill_ranks_get(skill_spellcraft) + spellcraft_level = char_editor.skill_ranks_get(skill_spellcraft) if spellcraft_level < 4: return 0 return 1 \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Rapid Metamagic.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Rapid Metamagic.py index 6cafd7587..1cc609ce9 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Rapid Metamagic.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Rapid Metamagic.py @@ -1,11 +1,11 @@ from toee import * - +import char_editor def CheckPrereq(attachee, classLevelled, abilityScoreRaised): spont_casting_lvl = attachee.spontaneous_spell_level_can_cast() if spont_casting_lvl <= 0: return 0 - spellcraft_level = attachee.skill_ranks_get(skill_spellcraft) + spellcraft_level = char_editor.skill_ranks_get(skill_spellcraft) if spellcraft_level < 12: return 0 return 1 \ No newline at end of file