Skip to content

Commit

Permalink
Merge pull request #758 from dolio/fix/misc
Browse files Browse the repository at this point in the history
Various minor fixes
  • Loading branch information
doug1234 authored Feb 17, 2024
2 parents 46d16cd + 565d743 commit 05b8cba
Show file tree
Hide file tree
Showing 17 changed files with 371 additions and 55 deletions.
32 changes: 29 additions & 3 deletions TemplePlus/action_sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,20 @@ int32_t ActionSequenceSystem::DoAoosByAdjcentEnemies(objHndl obj)
// return _AOOSthg2_100981C0(obj);
}

int32_t ActionSequenceSystem::ProvokeAooFrom(objHndl provoker, objHndl enemy)
{
if (objects.GetFlags(enemy) & OF_INVULNERABLE) // see above
return 0;

if (!combatSys.CanMeleeTarget(enemy, provoker)) return 0;
if (critterSys.IsFriendly(provoker, enemy)) return 0;
if (!d20Sys.d20QueryWithData(enemy, DK_QUE_AOOPossible, provoker)) return 0;
if (!d20Sys.d20QueryWithData(enemy, DK_QUE_AOOWillTake, provoker)) return 0;

DoAoo(enemy, provoker);
return 1;
}

bool ActionSequenceSystem::SpellTargetsFilterInvalid(D20Actn& d20a){

auto valid = true;
Expand Down Expand Up @@ -2810,13 +2824,25 @@ void ActionSequenceSystem::ActionPerform()
}

else{
bool preempted = false;
switch (d20->D20ActionTriggersAoO(d20a, &tbStatus))
{
case 0:
break;
case 2:
preempted = ProvokeAooFrom(d20a->d20APerformer, d20a->d20ATarget);
break;
case 1:
default:
preempted = DoAoosByAdjcentEnemies(d20a->d20APerformer);
break;
}

if ( d20->D20ActionTriggersAoO(d20a, &tbStatus) && DoAoosByAdjcentEnemies(d20a->d20APerformer)) {
if (preempted) {
logger->debug("ActionPerform: \t Sequence Preempted {}", d20a->d20APerformer);
--*(curIdx);
sequencePerform();
}
else{
} else {
curSeq->tbStatus = tbStatus;
*(uint32_t*)(&curSeq->tbStatus.tbsFlags) |= TBSF_HasActedThisRound;
InterruptCounterspell(d20a);
Expand Down
1 change: 1 addition & 0 deletions TemplePlus/action_sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ struct ActionSequenceSystem : temple::AddressTable
uint32_t seqCheckFuncs(TurnBasedStatus *tbStatus);
void DoAoo(objHndl, objHndl);
int32_t DoAoosByAdjcentEnemies(objHndl);
int32_t ProvokeAooFrom(objHndl provoker, objHndl enemy);

bool SpellTargetsFilterInvalid(D20Actn &d20a);
void HandleInterruptSequence();
Expand Down
81 changes: 51 additions & 30 deletions TemplePlus/animgoals/anim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,62 +457,83 @@ int AnimSystem::PushAnimate(objHndl obj, int anim) {
return addresses.PushAnimate(obj, anim);
}

BOOL AnimSystem::PushSpellCast(SpellPacketBody & spellPkt, objHndl item)
void AnimSystem::SetGoalDataForSpellPacket(SpellPacketBody & pkt, AnimSlotGoalStackEntry & goalData, bool wand, bool conjure)
{

// note: the original included the spell ID generation & registration, this is separated here.
auto caster = spellPkt.caster;
auto caster = pkt.caster;
auto casterObj = objSystem->GetObject(caster);
AnimSlotGoalStackEntry goalData;
if (!goalData.InitWithInterrupt(caster, ag_throw_spell_w_cast_anim))
return FALSE;
SpellEntry ent(pkt.spellEnum);

goalData.skillData.number = spellPkt.spellId;

SpellEntry spEntry(spellPkt.spellEnum);
goalData.skillData.number = pkt.spellId;

// if self-targeted spell
if (spEntry.IsBaseModeTarget(UiPickerType::Single) && spellPkt.targetCount == 0 ){
goalData.target.obj = spellPkt.caster;

if (spellPkt.aoeCenter.location.location == 0){
if (ent.IsBaseModeTarget(UiPickerType::Single) && pkt.targetCount == 0) {
goalData.target.obj = caster;
if (pkt.aoeCenter.location.location == 0)
goalData.targetTile.location = casterObj->GetLocationFull();
}
else{
goalData.targetTile.location = spellPkt.aoeCenter.location;
}
}
else
goalData.targetTile.location = pkt.aoeCenter.location;

else{
auto tgt = spellPkt.targetListHandles[0];
} else {
auto tgt = pkt.targetListHandles[0];
goalData.target.obj = tgt;
if (tgt && spellPkt.aoeCenter.location.location == 0 ){
if (tgt && pkt.aoeCenter.location.location == 0) {
goalData.targetTile.location = objSystem->GetObject(tgt)->GetLocationFull();
}
else {
goalData.targetTile.location = spellPkt.aoeCenter.location;
} else {
goalData.targetTile.location = pkt.aoeCenter.location;
}
}

if (inventory.UsesWandAnim(item)){
goalData.animIdPrevious.number = temple::GetRef<int(__cdecl)(int)>(0x100757C0)(spEntry.spellSchoolEnum); // GetAnimIdWand
if (wand){
goalData.animIdPrevious.number = GetWandAnimId(ent.spellSchoolEnum, conjure);
}
else{
goalData.animIdPrevious.number = temple::GetRef<int(__cdecl)(int)>(0x100757B0)(spEntry.spellSchoolEnum); // GetSpellSchoolAnimId
goalData.animIdPrevious.number = GetCastingAnimId(ent.spellSchoolEnum, conjure);
}
}

BOOL AnimSystem::PushSpellCast(SpellPacketBody & spellPkt, objHndl item)
{
// note: the original included the spell ID generation & registration, this is separated here.
AnimSlotGoalStackEntry goalData;
if (!goalData.InitWithInterrupt(spellPkt.caster, ag_throw_spell_w_cast_anim))
return FALSE;

SetGoalDataForSpellPacket(spellPkt, goalData, inventory.UsesWandAnim(item), false);

return goalData.Push(nullptr);
}

BOOL AnimSystem::PushSpellDismiss(SpellPacketBody & pkt)
{
AnimSlotGoalStackEntry goalData;
if (!goalData.InitWithInterrupt(pkt.caster, ag_throw_spell_w_cast_anim))
return FALSE;

SetGoalDataForSpellPacket(pkt, goalData, true, true);

return goalData.Push(nullptr);
}

int AnimSystem::GetWandAnimId(int school, bool conjure) {
auto dec = conjure ? 1 : 0;
return temple::GetRef<int(__cdecl)(int)>(0x100757C0)(school) - dec;
}

int AnimSystem::GetCastingAnimId(int school, bool conjure) {
auto dec = conjure ? 1 : 0;
return temple::GetRef<int(__cdecl)(int)>(0x100757B0)(school) - dec;
}


BOOL AnimSystem::PushSpellInterrupt(const objHndl& caster, objHndl item, AnimGoalType animGoalType, int spellSchool){
AnimSlotGoalStackEntry goalData;
goalData.InitWithInterrupt(caster, animGoalType);
goalData.target.obj = (*actSeqSys.actSeqCur)->spellPktBody.caster;
goalData.skillData.number = 0;
if (inventory.UsesWandAnim(item))
goalData.animIdPrevious.number = temple::GetRef<int(__cdecl)(int)>(0x100757C0)(spellSchool); // GetAnimIdWand
goalData.animIdPrevious.number = GetWandAnimId(spellSchool);
else
goalData.animIdPrevious.number = temple::GetRef<int(__cdecl)(int)>(0x100757B0)(spellSchool); // GetSpellSchoolAnimId
goalData.animIdPrevious.number = GetCastingAnimId(spellSchool);

return goalData.Push(nullptr);
}
Expand Down
9 changes: 8 additions & 1 deletion TemplePlus/animgoals/anim.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,16 @@ friend struct AnimSlotGoalStackEntry;
pushes spell animation, including wand animation if relevant
*/
BOOL PushSpellCast(SpellPacketBody &spellPkt, objHndl item);

BOOL PushSpellInterrupt(const objHndl& caster, objHndl item, AnimGoalType animGoalType, int spellSchool);

/*
pushes an animation for dismissing an active spell
*/
BOOL PushSpellDismiss(SpellPacketBody &spellPkt);
int GetWandAnimId(int school, bool conjure = false);
int GetCastingAnimId(int school, bool conjure = false);
void SetGoalDataForSpellPacket(SpellPacketBody &pkt, AnimSlotGoalStackEntry &goalData, bool wand, bool conjure=false);

/*
used by the general out-of-combat mouse LMB click handler
*/
Expand Down
87 changes: 84 additions & 3 deletions TemplePlus/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class ClassAbilityCallbacks
// Aura Of Courage
static int __cdecl CouragedAuraSavingThrow(DispatcherCallbackArgs args);

static int FailedCopyScroll(DispatcherCallbackArgs args);

static int FeatBrewPotionRadialMenu(DispatcherCallbackArgs args);
static int FeatScribeScrollRadialMenu(DispatcherCallbackArgs args);
Expand Down Expand Up @@ -568,6 +569,9 @@ class ConditionFunctionReplacement : public TempleFix {
SubDispDefNew sdd(dispTypeDealingDamageWeaponlikeSpell, 0, classAbilityCallbacks.SneakAttackDamage, 0u,0u); // Weapon-like spell damage hook
write(0x102ED2A8, &sdd, sizeof(SubDispDefNew));

// Wizard
replaceFunction<int(DispatcherCallbackArgs)>(0x10102AE0, classAbilityCallbacks.FailedCopyScroll);

// D20Mods countdown handler
replaceFunction<int(DispatcherCallbackArgs)>(0x100EC9B0, genericCallbacks.D20ModCountdownHandler);
replaceFunction<int(DispatcherCallbackArgs)>(0x100E98B0, genericCallbacks.D20ModCountdownEndHandler);
Expand Down Expand Up @@ -1153,7 +1157,8 @@ int GenericCallbacks::TripAooQuery(DispatcherCallbackArgs args)
int GenericCallbacks::ImprovedTripBonus(DispatcherCallbackArgs args)
{
auto dispIo = dispatch.DispIoCheckIoType10(args.dispIO);
if (dispIo->flags & 1){
// 2 seems to be defender
if (dispIo->flags & 1 && !(dispIo->flags & 2)) {
dispIo->bonOut->AddBonusWithDesc(4, 0, 114, feats.GetFeatName(FEAT_IMPROVED_TRIP));
}
return 0;
Expand Down Expand Up @@ -1943,7 +1948,8 @@ int __cdecl GlobalToHitBonus(DispatcherCallbackArgs args)
// helplessness bonus
if (dispIo->attackPacket.victim
&& d20Sys.d20Query(dispIo->attackPacket.victim, DK_QUE_Helpless)
&& !d20Sys.d20Query(dispIo->attackPacket.victim, DK_QUE_Critter_Is_Stunned))
&& !d20Sys.d20Query(dispIo->attackPacket.victim, DK_QUE_Critter_Is_Stunned)
&& !(dispIo->attackPacket.flags & D20CAF_RANGED))
bonusSys.bonusAddToBonusList(&dispIo->bonlist, 4, 30, 136);

// flanking bonus
Expand Down Expand Up @@ -3256,6 +3262,24 @@ void ConditionSystem::RegisterNewConditions()
DispatcherHookInit(cond, 1, dispTypeRadialMenuEntry, 0, AidAnotherRadialMenu, 0, 0);
//

{
static CondStructNew condHeld;
condHeld.ExtendExisting("Held");
condHeld.subDispDefs[11].dispCallback = [](DispatcherCallbackArgs args) {
static auto orig = temple::GetRef<int(__cdecl)(DispatcherCallbackArgs)>(0x100EDF10);
// disable effect tooltip if freedom of movement
if (!d20Sys.d20Query(args.objHndCaller, DK_QUE_Critter_Has_Freedom_of_Movement))
return orig(args);
return 0;
};
condHeld.AddHook(dispTypeAbilityScoreLevel, DK_STAT_STRENGTH, HeldCapStatBonus);
condHeld.AddHook(dispTypeAbilityScoreLevel, DK_STAT_DEXTERITY, HeldCapStatBonus);

static CondStructNew condSleeping;
condSleeping.ExtendExisting("Sleeping");
condSleeping.AddHook(dispTypeAbilityScoreLevel, DK_STAT_DEXTERITY, HelplessCapStatBonus);
}

/*
char mCondIndomitableWillName[100];
CondStructNew *mCondIndomitableWill;
Expand Down Expand Up @@ -3649,6 +3673,31 @@ int TacticalOptionAbusePrevention(DispatcherCallbackArgs args)
return temple::GetRef<int(__cdecl)(DispatcherCallbackArgs)>(0x100F7ED0)(args); // replaced in ability_fixes.cpp
}

// Port of 0x100E7F80. Was used in Unconscious but missing in similar
// conditions. Helpless critters should have 0 effective dexterity, and
// paralyzed creatures should have 0 effective strength.
int HelplessCapStatBonus(DispatcherCallbackArgs args)
{
DispIoBonusList *dispIo = dispatch.DispIoCheckIoType2(args.dispIO);

dispIo->bonlist.AddCap(0, 0, 109);

return 0;
}

// As above, but check for freedom of movement, since it doesn't remove the held
// condition.
int HeldCapStatBonus(DispatcherCallbackArgs args)
{
DispIoBonusList *dispIo = dispatch.DispIoCheckIoType2(args.dispIO);

if (!d20Sys.d20Query(args.objHndCaller, DK_QUE_Critter_Has_Freedom_of_Movement))
dispIo->bonlist.AddCap(0, 0, 109);

return 0;
}


#pragma region Barbarian Stuff

int __cdecl CombatExpertiseRadialMenu(DispatcherCallbackArgs args)
Expand Down Expand Up @@ -3994,7 +4043,11 @@ int RendOnDamage(DispatcherCallbackArgs args)
auto previousTarget = args.GetCondArgObjHndl(2);
if (hasDeliveredDamage && attackDescr == previousAttackDescr && previousTarget == dispIo->attackPacket.victim)
{
Dice dice(2, 6, 9);
int strScore = objects.StatLevelGet(args.objHndCaller, stat_strength);
int bonus = objects.GetModFromStatLevel(strScore);
if (bonus > 0) bonus += bonus/2;

Dice dice(2, 6, bonus);
dispIo->damage.AddDamageDice(dice.ToPacked(), DamageType::PiercingAndSlashing, 133);
//damage.AddDamageDice(&dispIo->damage, dice.ToPacked(), DamageType::PiercingAndSlashing, 133);
floatSys.FloatCombatLine(args.objHndCaller, 203);
Expand Down Expand Up @@ -6279,6 +6332,24 @@ int ClassAbilityCallbacks::CouragedAuraSavingThrow(DispatcherCallbackArgs args)
return 0;
}

int ClassAbilityCallbacks::FailedCopyScroll(DispatcherCallbackArgs args) {
auto dispIo = dispatch.DispIoCheckIoType7(args.dispIO);

auto failedScRanks = args.GetCondArg(1);
auto curScRanks = critterSys.SkillBaseGet(args.objHndCaller, SkillEnum::skill_spellcraft);
auto failedSpellEnum = args.GetCondArg(0);

// if we've gained spellcraft ranks, get rid of the condition
if (curScRanks > failedScRanks) {
conds.ConditionRemove(args.objHndCaller, args.subDispNode->condNode);
// if the scroll being copied matches, set return value
} else if (failedSpellEnum == dispIo->data1) {
dispIo->return_val = 1;
}

return 0;
}

int ClassAbilityCallbacks::FeatBrewPotionRadialMenu(DispatcherCallbackArgs args){
return ItemCreationBuildRadialMenuEntry(args, BrewPotion, "TAG_BREW_POTION", 5066);
}
Expand Down Expand Up @@ -7539,6 +7610,16 @@ void Conditions::AddConditionsToTable(){
}
}

{
static CondStructNew condColorSprayStun;
condColorSprayStun.ExtendExisting("sp-Color Spray Stun");
condColorSprayStun.AddHook(dispTypeD20Query, DK_QUE_SneakAttack, genericCallbacks.QuerySetReturnVal1);

static CondStructNew condColorSprayBlind;
condColorSprayBlind.ExtendExisting("sp-Color Spray Blind");
condColorSprayBlind.AddHook(dispTypeTurnBasedStatusInit, DK_NONE, TurnBasedStatusInitNoActions);
}

// New Conditions!
conds.hashmethods.CondStructAddToHashtable((CondStruct*)conds.mConditionDisableAoO);
conds.hashmethods.CondStructAddToHashtable((CondStruct*)conds.mCondGreaterTwoWeaponFighting);
Expand Down
3 changes: 3 additions & 0 deletions TemplePlus/condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ int RecklessOffenseAcPenalty(DispatcherCallbackArgs args);
int RecklessOffenseToHitBonus(DispatcherCallbackArgs args);
int TacticalOptionAbusePrevention(DispatcherCallbackArgs args);

int HeldCapStatBonus(DispatcherCallbackArgs args);
int HelplessCapStatBonus(DispatcherCallbackArgs args);

int CombatExpertiseRadialMenu(DispatcherCallbackArgs args);
int CombatExpertiseSet(DispatcherCallbackArgs args);

Expand Down
Loading

0 comments on commit 05b8cba

Please sign in to comment.