Skip to content

Commit

Permalink
Levelup Feats GUI + some bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
DMD authored and DMD committed Aug 19, 2016
1 parent 4aa0f31 commit c8da412
Show file tree
Hide file tree
Showing 15 changed files with 928 additions and 550 deletions.
16 changes: 8 additions & 8 deletions TemplePlus/bonusspells.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "temple_functions.h"
#include "obj.h"
#include "gamesystems/objects/objsystem.h"
#include <critter.h>


void removeSurplusSpells(int surplus, objHndl objHnd, uint32_t classCode, int slotLvl)
Expand Down Expand Up @@ -45,26 +46,25 @@ int getMemorizedSpells(objHndl objHnd, uint32_t classCode, int slotLvl)

int getMaxSpells(objHndl objHnd, uint32_t classCode, int slotLvl, uint32_t classLvl)
{
uint32_t maxSpells = spellSys.getBaseSpellCountByClassLvl(classCode, classLvl, slotLvl, 0);
if (maxSpells)
{
if ( spellSys.getWizSchool(objHnd) )
{
int maxSpells = spellSys.GetNumSpellsPerDay(objHnd, (Stat)classCode, slotLvl); // spellSys.getBaseSpellCountByClassLvl(classCode, classLvl, slotLvl, 0);

if (maxSpells >=0 ){
if ( spellSys.getWizSchool(objHnd) ){
maxSpells++;

}
maxSpells += spellSys.getStatModBonusSpellCount(objHnd, classCode, slotLvl);
// maxSpells += spellSys.getStatModBonusSpellCount(objHnd, classCode, slotLvl);
return maxSpells;
}
else if ( d20ClassSys.IsLateCastingClass((Stat)classCode)
/*else if ( d20ClassSys.IsLateCastingClass((Stat)classCode)
&& (classLvl >= 4 && slotLvl == 1
|| classLvl >= 8 && slotLvl == 2
|| classLvl >= 11 && slotLvl == 3
|| classLvl >= 14 && slotLvl == 4))
{
maxSpells += spellSys.getStatModBonusSpellCount(objHnd, classCode, slotLvl);
return maxSpells;
}
}*/

return 0;

Expand Down
2 changes: 1 addition & 1 deletion TemplePlus/d20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@ ActionErrorCode D20ActionCallbacks::ActionCheckCastSpell(D20Actn* d20a, TurnBase
if (d20ClassSys.IsNaturalCastingClass(classCode))
while (true) {

auto spellsPerDay = spellSys.GetSpellsPerDay(d20a->d20APerformer, classCode, spellLvl);
auto spellsPerDay = spellSys.GetNumSpellsPerDay(d20a->d20APerformer, classCode, spellLvl);
auto spellsCastNum = spellSys.NumSpellsInLevel(d20a->d20APerformer, obj_f_critter_spells_cast_idx, spellClass, spellLvl);

if (spellsCastNum < spellsPerDay) {
Expand Down
26 changes: 24 additions & 2 deletions TemplePlus/d20_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,23 @@ bool D20ClassSystem::IsArcaneCastingClass(Stat classCode, objHndl handle){
return false;
}

bool D20ClassSystem::IsDivineCastingClass(Stat classCode, objHndl handle)
{
auto classSpec = classSpecs.find(classCode);
if (classSpec == classSpecs.end())
return false;

if (classSpec->second.spellListType == SpellListType::Divine
|| classSpec->second.spellListType == SpellListType::Clerical
|| classSpec->second.spellListType == SpellListType::Druidic
|| classSpec->second.spellListType == SpellListType::Ranger
|| classSpec->second.spellListType == SpellListType::Paladin
)
return true;

return false;
}

bool D20ClassSystem::HasDomainSpells(Stat classEnum){
if (classEnum == stat_level_cleric)
return true;
Expand Down Expand Up @@ -436,8 +453,13 @@ BOOL D20ClassSystem::IsClassSkill(SkillEnum skillEnum, Stat classCode){
}

bool D20ClassSystem::LevelupSpellsCheckComplete(objHndl handle, Stat classEnum){

return pythonClassIntegration.LevelupSpellsCheckComplete(handle, classEnum);
if (objects.StatLevelGet(handle, classEnum)){
auto result = dispatch.DispatchLevelupSystemEvent(handle, classEnum, DK_LVL_Spells_Check_Complete);
return result >= 0;
}

else
return pythonClassIntegration.LevelupSpellsCheckComplete(handle, classEnum);
}

void D20ClassSystem::LevelupSpellsFinalize(objHndl handle, Stat classEnum){
Expand Down
3 changes: 2 additions & 1 deletion TemplePlus/d20_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ struct D20ClassSystem : temple::AddressTable
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);
bool IsDivineCastingClass(Stat stat, objHndl handle = objHndl::null);
static bool HasDomainSpells(Stat classEnum);
Stat GetSpellStat(Stat classEnum); // default - wisdom
int GetMaxSpellLevel(Stat classEnum, int characterLvl);
Expand Down Expand Up @@ -143,7 +144,7 @@ struct D20ClassSystem : temple::AddressTable

int ClericMaxSpellLvl(uint32_t clericLvl) const;
int NumDomainSpellsKnownFromClass(objHndl dude, Stat classCode);
int GetNumSpellsFromClass(objHndl obj, Stat classCode, int spellLvl, uint32_t classLvl, bool getFromStatMod = true);
int GetNumSpellsFromClass(objHndl obj, Stat classCode, int spellLvl, uint32_t classLvl, bool getFromStatMod = true); // returns -1 if none; must have >=0 spells per day before taking into account the stat mod

// skills
BOOL IsClassSkill(SkillEnum skillEnum, Stat classCode);
Expand Down
47 changes: 12 additions & 35 deletions TemplePlus/feat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ int LegacyFeatSystem::IsMagicFeat(feat_enums feat)

int LegacyFeatSystem::IsFeatPartOfMultiselect(feat_enums feat)
{
return ( m_featPropertiesTable[feat] & 0x100 ) != 0;
return ( m_featPropertiesTable[feat] & FPF_MULTI_SELECT_ITEM ) != 0;
}

int LegacyFeatSystem::IsFeatRacialOrClassAutomatic(feat_enums feat)
Expand Down Expand Up @@ -380,7 +380,7 @@ int LegacyFeatSystem::IsFeatPropertySet(feat_enums feat, int featProp)
}

bool LegacyFeatSystem::IsFeatMultiSelectMaster(feat_enums feat){
return IsFeatPropertySet(feat, 0x80000) != 0;
return IsFeatPropertySet(feat, FPF_MULTI_MASTER) != 0;
};

#pragma endregion
Expand Down Expand Up @@ -678,53 +678,30 @@ uint32_t _FeatPrereqsCheck(objHndl objHnd, feat_enums featIdx, feat_enums * feat
FeatPrereqRow * featPrereqs = feats.m_featPreReqTable;
const uint8_t numCasterClasses = 7;
uint32_t casterClassCodes[numCasterClasses] = { stat_level_bard, stat_level_cleric, stat_level_druid, stat_level_paladin, stat_level_ranger, stat_level_sorcerer, stat_level_wizard };

if (featProps & 2 && !(featProps & 524290))
{

if (!feats.IsFeatEnabled(featIdx) && !feats.IsFeatMultiSelectMaster(featIdx)){
return 0;
}

//return 1; // h4x :)

#pragma region checking feats in the character editor - SpellSlinger hack for special Rogue feats for level > 10
if ( ui.CharEditorIsActive() && *feats.charEditorClassCode != 0 && *feats.charEditorObjHnd)
{
auto newClassLvl = objects.StatLevelGet(*feats.charEditorObjHnd, *feats.charEditorClassCode) + 1;

if (classCodeBeingLevelledUp == stat_level_rogue)
{
if (newClassLvl == 10 || newClassLvl == 13 || newClassLvl == 16 || newClassLvl == 19)
{
if (featProps & featPropRogueFeat)
{
return 1;
}
}
// checking feats in the character editor - SpellSlinger hack for special Rogue feats for level > 10
if ( classCodeBeingLevelledUp == stat_level_rogue && objHnd && feats.IsFeatPropertySet(featIdx, FPF_ROGUE_BONUS)){
auto newClassLvl = objects.StatLevelGet(objHnd, stat_level_rogue) + 1;
if (newClassLvl == 10 || newClassLvl == 13 || newClassLvl == 16 || newClassLvl == 19){
return 1;
}
}
#pragma endregion


uint32_t initOffset = featIdx * 16;
if (featIdx == FEAT_GREATER_TWO_WEAPON_FIGHTING)
{
int bpDummy = 1;
}

if (featPrereqs[featIdx].featPrereqs[0].featPrereqCode == featReqCodeTerminator){ return 1; };


for (uint32_t i = 0; featPrereqs[featIdx].featPrereqs[i].featPrereqCode != featReqCodeTerminator; i += 1)
{
//disassm notes:
// eax is classCodeBeingLevelledUp
// esi is featReqCode
// ecx is featIdx
for (uint32_t i = 0; featPrereqs[featIdx].featPrereqs[i].featPrereqCode != featReqCodeTerminator; i += 1){

int32_t featReqCode = featPrereqs[featIdx].featPrereqs[i].featPrereqCode;
auto featReqCodeArg = featPrereqs[featIdx].featPrereqs[i].featPrereqCodeArg;
uint32_t var_2C = 0;


uint32_t var_2C = 0;

if (featReqCode == featReqCodeMinCasterLevel)
{
Expand Down
25 changes: 25 additions & 0 deletions TemplePlus/feat.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@
#define NUM_FEATS 750 // vanilla was 649 (and Moebius hack increased this to 664 I think)
#include "tig/tig_mes.h"

enum FeatPropertyFlag : uint32_t {
FPF_CAN_GAIN_MULTIPLE_TIMES = 0x1,
FPF_DISABLED = 0x2,
FPF_RACE_AUTOMATIC = 0x4,
FPF_CLASS_AUTMATIC = 0x8 ,
FPF_FIGHTER_BONUS = 0x10,
FPF_MONK_BONUS_1st = 0x20,
FPF_MONK_BONUS_2nd = 0x40,
FPF_MONK_BONUS_6th = 0x80,
FPF_MULTI_SELECT_ITEM = 0x100,
FPF_EXOTIC_WEAP_ITEM = 0x300,
FPF_IMPR_CRIT_ITEM = 0x500,
FPF_MARTIAL_WEAP_ITEM = 0x900,
FPF_SKILL_FOCUS_ITEM = 0x1100,
FPF_WEAP_FINESSE_ITEM = 0x2100,
FPF_WEAP_FOCUS_ITEM = 0x4100,
FPF_WEAP_SPEC_ITEM = 0x8100,
FPF_GREATER_WEAP_FOCUS_ITEM = 0x10100,
FPF_WIZARD_BONUS = 0x20000,
FPF_ROGUE_BONUS = 0x40000, // rogue bonus at 10th level

FPF_MULTI_MASTER = 0x80000, // head of multiselect class of feats (NEW)
FPF_GREAT_WEAP_SPEC_ITEM = 0x100100, // NEW
};


struct FeatPrereqRow;
struct ClassFeatTableEntry
Expand Down
4 changes: 3 additions & 1 deletion TemplePlus/fonts/fonts_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,12 +643,14 @@ uint32_t TextLayouter::CountLinesVanilla(uint32_t maxWidth, uint32_t maxLines, c
// Measure the length of the current word
for (; i < length; i++) {
ch = text[i];

if (ch == '’') // fix for this character that sometimes appears in vanilla
ch = '\'';
// Skip @[0-9]
if (ch == '@' && i + 1 < length && text[i + 1] >= '0' && text[i + 1] <= '9') {
i++;
continue;
}


if (isspace(ch)) {
break;
Expand Down
38 changes: 14 additions & 24 deletions TemplePlus/python/python_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,21 +821,16 @@ static PyObject* PyObjHandle_ArcaneSpellLevelCanCast(PyObject* obj, PyObject* ar

auto arcaneSpellLvlMax = 0;

auto wizLvl = objects.StatLevelGet(self->handle, stat_level_wizard);
if (wizLvl > 0){
arcaneSpellLvlMax = (1 + wizLvl) / 2;
}
critterSys.GetSpellLvlCanCast(self->handle, SpellSourceType::Arcane, SpellReadyingType::Any);

auto sorcLvl = objects.StatLevelGet(self->handle, stat_level_sorcerer);
if (sorcLvl > 0){
auto sorcSpellLvlMax = max(1, sorcLvl / 2);
if (sorcSpellLvlMax > arcaneSpellLvlMax)
arcaneSpellLvlMax = sorcSpellLvlMax;
for (auto it: d20ClassSys.classEnums){
auto classEnum = (Stat)it;
if (d20ClassSys.IsArcaneCastingClass(classEnum)){
arcaneSpellLvlMax = max(arcaneSpellLvlMax , spellSys.GetMaxSpellLevel(self->handle, classEnum, 0));
}
}


auto bardLvl = objects.StatLevelGet(self->handle, stat_level_bard);
critterSys.GetSpellLvlCanCast(self->handle, SpellSourceType::Arcane, SpellReadyingType::Any);
// todo: generalize

return PyInt_FromLong(arcaneSpellLvlMax);
}
Expand All @@ -848,20 +843,15 @@ static PyObject* PyObjHandle_DivineSpellLevelCanCast(PyObject* obj, PyObject* ar

auto divineSpellLvlMax = 0;

auto clrLvl = objects.StatLevelGet(self->handle, stat_level_cleric);
if (clrLvl > 0) {
divineSpellLvlMax = (1 + clrLvl) / 2;
}

auto drdLvl = objects.StatLevelGet(self->handle, stat_level_druid);
if (drdLvl > 0) {
if (drdLvl > clrLvl)
divineSpellLvlMax = (1 + drdLvl) / 2;
critterSys.GetSpellLvlCanCast(self->handle, SpellSourceType::Divine, SpellReadyingType::Any);

for (auto it : d20ClassSys.classEnums) {
auto classEnum = (Stat)it;
if (d20ClassSys.IsDivineCastingClass(classEnum)) {
divineSpellLvlMax = max(divineSpellLvlMax, spellSys.GetMaxSpellLevel(self->handle, classEnum, 0));
}
}

auto palLvl = objects.StatLevelGet(self->handle, stat_level_paladin);
critterSys.GetSpellLvlCanCast(self->handle, SpellSourceType::Divine, SpellReadyingType::Any);
// todo: generalize

return PyInt_FromLong(divineSpellLvlMax);
}
Expand Down
2 changes: 1 addition & 1 deletion TemplePlus/radialmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class RadialMenuReplacements : public TempleFix
}
}
auto spellClass = spellSys.GetSpellClass(classCode);
auto numSpellsPerDay = spellSys.GetSpellsPerDay(handle, classCode, spLvl);
auto numSpellsPerDay = spellSys.GetNumSpellsPerDay(handle, classCode, spLvl);
if (numSpellsPerDay < 0)
numSpellsPerDay = 0;

Expand Down
2 changes: 1 addition & 1 deletion TemplePlus/spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ int LegacySpellSystem::GetMaxSpellLevel(objHndl objHnd, Stat classCode, int char
//return addresses.GetMaxSpellSlotLevel(objHnd, classCode, characterLvl);
}

int LegacySpellSystem::GetSpellsPerDay(objHndl handle, Stat classCode, int spellLvl){
int LegacySpellSystem::GetNumSpellsPerDay(objHndl handle, Stat classCode, int spellLvl){
auto spellClass = spellSys.GetSpellClass(classCode);
auto effLvl = critterSys.GetSpellListLevelExtension(handle, classCode) + objects.StatLevelGet(handle, classCode);
return d20ClassSys.GetNumSpellsFromClass(handle, classCode, spellLvl, effLvl);
Expand Down
4 changes: 2 additions & 2 deletions TemplePlus/spell.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ struct LegacySpellSystem : temple::AddressTable
uint32_t spellRegistryCopy(uint32_t spellEnum, SpellEntry* spellEntry);
int CopyLearnableSpells(objHndl & handle, int spellClass, std::vector<SpellEntry> & entries);
uint32_t ConfigSpellTargetting(PickerArgs* pickerArgs, SpellPacketBody* spellPacketBody);
int GetMaxSpellLevel(objHndl objHnd, Stat classCode, int characterLvl);
int GetSpellsPerDay(objHndl handle, Stat classCode, int spellLvl);
int GetMaxSpellLevel(objHndl objHnd, Stat classCode, int characterLvl = 0); // if characterLvl is 0 it will fetch the actual level; it also takes into account spell list extension by PrC's and such
int GetNumSpellsPerDay(objHndl handle, Stat classCode, int spellLvl); // including from spell list extension
int ParseSpellSpecString(SpellStoreData* spell, char* spellString);

const char* GetSpellMesline(uint32_t line) const;
Expand Down
12 changes: 6 additions & 6 deletions TemplePlus/ui/ui_char.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ void CharUiSystem::SpellsShow(objHndl obj)
// find which caster class tabs should appear
for (int i = 0; i < VANILLA_NUM_CLASSES ; i++){
auto classCode = d20ClassSys.vanillaClassEnums[i];
auto spellClassCode = (classCode & 0x7F) | 0x80;
auto spellClassCode = spellSys.GetSpellClass(classCode);

if (!d20ClassSys.IsCastingClass(classCode))
continue;
Expand All @@ -349,10 +349,10 @@ void CharUiSystem::SpellsShow(objHndl obj)
ui.WidgetSetHidden(navTabBtn->widgetId, 0);

navClassPackets[uiCharSpellTabsCount].spellClassCode = spellClassCode;

int n1 = 0;
for (int spellLvl = 0; spellLvl < 10; spellLvl++){
int numSpells = d20ClassSys.GetNumSpellsFromClass(dude, classCode, spellLvl, classLvl);
int numSpells = spellSys.GetNumSpellsPerDay(dude, classCode, spellLvl); //d20ClassSys.GetNumSpellsFromClass(dude, classCode, spellLvl, classLvl);
if (numSpells > 0)
n1 += numSpells;
}
Expand Down Expand Up @@ -439,12 +439,12 @@ void CharUiSystem::SpellsShow(objHndl obj)
if (!spellSys.isDomainSpell(spellClassCode)){ //normal casting class
//LevelPacket lvlPkt;
auto classCode = spellSys.GetCastingClass(spellClassCode);
auto classLvl = objects.StatLevelGet(dude, classCode);
classLvl += critterSys.GetSpellListLevelExtension(dude, classCode);
//auto classLvl = objects.StatLevelGet(dude, classCode);
//classLvl += critterSys.GetSpellListLevelExtension(dude, classCode);
//lvlPkt.GetLevelPacket(classCode, dude, 0, classLvl);
auto numSpellsForLvl = navClassPackets[i].numSpellsForLvl;
for (int j = 0; j < NUM_SPELL_LEVELS; j++){
auto numSp = d20ClassSys.GetNumSpellsFromClass(dude, classCode, j, classLvl);
auto numSp = spellSys.GetNumSpellsPerDay(dude, classCode, j); //d20ClassSys.GetNumSpellsFromClass(dude, classCode, j, classLvl);
if (numSp >= 0){ //(lvlPkt.spellCountFromClass[j] >= 0){
numSpellsForLvl[j] = numSp; //lvlPkt.spellCountBonusFromStatMod[j] + lvlPkt.spellCountFromClass[j];
if (numSpellsForLvl[j] > 0 && classCode == stat_level_wizard) {
Expand Down
Loading

0 comments on commit c8da412

Please sign in to comment.