Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dragon Discipile WIP #619

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
54ec304
Dragon Disciple WIP
Sagenlicht Sep 16, 2021
0312673
Updated Dragon Disciple
Sagenlicht Sep 17, 2021
b9d12de
Update dragon_disciple.py
Sagenlicht Sep 17, 2021
6e6b68f
Merge branch 'master' into DragonDisciple
Sagenlicht Sep 20, 2021
783606e
Added Ability Boost
Sagenlicht Sep 20, 2021
0cb6e91
Fixed Heritage bug
Sagenlicht Sep 20, 2021
809df43
Fixed Cone Breath Weapon
Sagenlicht Sep 20, 2021
1ad5cfa
Further progress for the DD
Sagenlicht Sep 21, 2021
6e4d1e0
Finished help file for DD
Sagenlicht Sep 22, 2021
7fcad2c
DD: Dropped Blindsense, fixed fire smoke
Sagenlicht Sep 23, 2021
d02b5fb
Added Flying Toggle (Nonfunctional yet)
Sagenlicht Sep 30, 2021
e641ab5
Moved Flying to seperate condtion
Sagenlicht Oct 1, 2021
2ebb5a7
added Darley Wings Mesh as Wings for the DD
Sagenlicht Oct 14, 2021
f77c9dc
Merge branch 'master' into DragonDisciple
Sagenlicht Oct 26, 2021
d8ae0ec
Merge branch 'master' into DragonDisciple
Nov 21, 2021
7ec38ee
String fixes: DD requirements fit inside scroll box; feat descrition …
Nov 22, 2021
b085be2
Added PyObjHndl method anim_goal_throw_spell_w_cast_anim to properly …
Nov 22, 2021
9696b90
DD fixes Breath weapon
Nov 22, 2021
d1daf13
Merge branch 'DragonDisciple' of https://github.com/GrognardsFromHell…
Sagenlicht Nov 22, 2021
1aabeb1
Update to DD Draconic Heritage Handling
Sagenlicht Nov 23, 2021
2d2d8cb
First Draft of Bonus Spells Feature
Sagenlicht Nov 24, 2021
fbbfe61
Merge branch 'master' into DragonDisciple
Sagenlicht Nov 24, 2021
4099c50
Merge branch 'master' into DragonDisciple
Nov 24, 2021
67e6a9e
Merge branch 'DragonDisciple' of https://github.com/GrognardsFromHell…
Nov 24, 2021
a43fa6a
Forgot to merge the draconic_heritage feat to the DD
Sagenlicht Nov 25, 2021
8f9182e
Added new error codes
Sagenlicht Dec 6, 2021
1586499
Condition hashtable init replacement; added log message for when it o…
Dec 22, 2021
96c76ef
Merge branch 'DragonDisciple' of https://github.com/GrognardsFromHell…
Dec 22, 2021
b43a73d
reflex throw will now use SpellSaveThrow when used for spell actions,…
Dec 22, 2021
e21d766
Added get_caster_class method to python EventObjSpellsPerDay
Dec 22, 2021
05c1d8e
Renamed chargeAfterPicker for more accurate meaning
Dec 23, 2021
5fe70c7
Minor magic number cleanup from natural attacks review
Dec 24, 2021
370c30b
Changed Bonus Spells per Day
Sagenlicht Jan 18, 2022
422d1c4
Update dragon_disciple.py
Sagenlicht Jan 18, 2022
69a037a
Merge pull request #701 from GrognardsFromHell/bugfixes
DudeMcDude Sep 6, 2022
e590df5
Fixes animation script particle errors on map load
Sep 7, 2022
0a2315f
Merge pull request #702 from GrognardsFromHell/bugfixes
DudeMcDude Sep 7, 2022
fdb94bf
Minor wiki help errors
Sep 7, 2022
bb602d2
Merge branch 'bugfixes' into develop
Sep 9, 2022
b750dd0
Scribe scroll - automated infrastructure instead of the old manual pr…
Sep 9, 2022
9b6d579
Fixes crash issue when AI party member casts Dominate Monster (aka 'S…
Sep 10, 2022
9eefcb0
Fixes #682
Sep 10, 2022
d1b2858
Fixed error in targeting.py will_kos
Sep 10, 2022
c4ef9bd
Merge from develop
Sep 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions TemplePlus/action_sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1716,7 +1716,7 @@ int ActionSequenceSystem::TrimPathToRemainingMoveLength(D20Actn* d20a, float rem
uint32_t ActionSequenceSystem::ActionCostNull(D20Actn* d20Actn, TurnBasedStatus* turnBasedStatus, ActionCostPacket* actionCostPacket)
{
actionCostPacket->hourglassCost = 0;
actionCostPacket->chargeAfterPicker = 0;
actionCostPacket->attackCost = 0;
actionCostPacket->moveDistCost = 0;
return 0;
}
Expand Down Expand Up @@ -3371,7 +3371,7 @@ BOOL ActionSequenceSystem::SimulsAdvance()

int ActionSequenceSystem::ActionCostFullAttack(D20Actn* d20, TurnBasedStatus* tbStat, ActionCostPacket* acp)
{
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
acp->hourglassCost = 4;
int flags = d20->d20Caf;
Expand Down Expand Up @@ -3512,13 +3512,13 @@ int ActionSequenceSystem::ActionCostProcess(TurnBasedStatus* tbStat, D20Actn* d2
if (tbStat->surplusMoveDistance >= actCost.moveDistCost)
{
tbStat->surplusMoveDistance -= actCost.moveDistCost;
if ( actCost.chargeAfterPicker <= 0
|| actCost.chargeAfterPicker + tbStat->attackModeCode <= tbStat->baseAttackNumCode + tbStat->numBonusAttacks)
if ( actCost.attackCost <= 0
|| actCost.attackCost + tbStat->attackModeCode <= tbStat->baseAttackNumCode + tbStat->numBonusAttacks)
{
if ((int) tbStat->numBonusAttacks < actCost.chargeAfterPicker)
tbStat->attackModeCode += actCost.chargeAfterPicker;
if (actCost.attackCost > (int) tbStat->numBonusAttacks )
tbStat->attackModeCode += actCost.attackCost;
else
tbStat->numBonusAttacks -= actCost.chargeAfterPicker;
tbStat->numBonusAttacks -= actCost.attackCost;
if (tbStat->attackModeCode == tbStat->baseAttackNumCode && !tbStat->numBonusAttacks)
tbStat->tbsFlags &= ~TBSF_FullAttack;
result = AEC_OK;
Expand Down Expand Up @@ -3782,12 +3782,13 @@ int ActionSequenceSystem::StdAttackTurnBasedStatusCheck(D20Actn* d20a, TurnBased
return AEC_TARGET_INVALID;
}

const int STD_ATK_HG_COST= 2;
if (hgState != -1)
hgState = turnBasedStatusTransitionMatrix[hgState][2];
hgState = turnBasedStatusTransitionMatrix[hgState][STD_ATK_HG_COST];
tbStat->hourglassState = hgState;

if (inventory.ItemWornAt(d20a->d20APerformer, 3) || dispatch.DispatchD20ActionCheck(d20a, tbStat, dispTypeGetCritterNaturalAttacksNum) <= 0)
tbStat->attackModeCode = 0;
if (inventory.ItemWornAt(d20a->d20APerformer, EquipSlot::WeaponPrimary) || dispatch.DispatchD20ActionCheck(d20a, tbStat, dispTypeGetCritterNaturalAttacksNum) <= 0)
tbStat->attackModeCode = ATTACK_CODE_PRIMARY;
else
tbStat->attackModeCode = ATTACK_CODE_NATURAL_ATTACK;
tbStat->baseAttackNumCode = tbStat->attackModeCode + 1;
Expand Down Expand Up @@ -4308,12 +4309,15 @@ const char*actionErrorCodeStrings[] =
"AEC_NEED_A_STRAIGHT_LINE",
"AEC_NO_ACTIONS",
"AEC_NOT_IN_COMBAT",
"AEC_AREA_NOT_SAFE"
"AEC_AREA_NOT_SAFE",
"AEC_ABILITY_ON_COOLDOWN",
"AEC_ALREADY_USED_THIS_TURN",
"AEC_ALREADY_ACTIVE"
};
ostream & operator<<(ostream & str, ActionErrorCode aec)
{
size_t i = (size_t)aec;
if (i <= AEC_AREA_NOT_SAFE) {
if (i <= AEC_ALREADY_ACTIVE) {
str << actionErrorCodeStrings[i];
}
else {
Expand Down
5 changes: 4 additions & 1 deletion TemplePlus/action_sequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ enum ActionErrorCode : uint32_t
AEC_NEED_A_STRAIGHT_LINE,
AEC_NO_ACTIONS,
AEC_NOT_IN_COMBAT,
AEC_AREA_NOT_SAFE
AEC_AREA_NOT_SAFE,
AEC_ABILITY_ON_COOLDOWN,
AEC_ALREADY_USED_THIS_TURN,
AEC_ALREADY_ACTIVE
};

// Allows for direct use of ActionErrorCode in format() strings
Expand Down
31 changes: 28 additions & 3 deletions TemplePlus/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ class ConditionFunctionReplacement : public TempleFix {
void apply() override {
logger->info("Replacing Condition-related Functions");

replaceFunction<void()>(0x100E19A0, []() {
conds.hashmethods.ConditionHashtableInit(conds.mCondStructHashtable);
});
//dispTypeConditionAddPre
static int(__cdecl* orgTempAbilityLoss)(DispatcherCallbackArgs) = replaceFunction<int(__cdecl)(DispatcherCallbackArgs)>(0x100EA1F0, [](DispatcherCallbackArgs args) {
Stat statDamaged = (Stat)args.GetCondArg(0);
Expand Down Expand Up @@ -1863,16 +1866,16 @@ int __cdecl GlobalToHitBonus(DispatcherCallbackArgs args)
&& !d20Sys.d20Query(args.objHndCaller, DK_QUE_Polymorphed) )
{
int attackIdx = dispIo->attackPacket.dispKey - (ATTACK_CODE_NATURAL_ATTACK + 1);
int bonValue = 0; // temporarily used as an index value for obj_f_attack_bonus_idx field
int atkBonIdx = 0;
for (int i = 0, j=0; i < 4; i++)
{
j += objects.getArrayFieldInt32(args.objHndCaller, obj_f_critter_attacks_idx, i); // number of attacks
if (attackIdx < j){
bonValue = i;
atkBonIdx = i;
break;
}
}
bonValue = objects.getArrayFieldInt32(args.objHndCaller, obj_f_attack_bonus_idx, bonValue);
int bonValue = objects.getArrayFieldInt32(args.objHndCaller, obj_f_attack_bonus_idx, atkBonIdx);
bonusSys.bonusAddToBonusList(&dispIo->bonlist, bonValue, 1, 118); // base attack
}

Expand Down Expand Up @@ -7479,3 +7482,25 @@ void CondStructNew::AddAoESpellRemover() {
AddHook(dispTypeD20Signal, DK_SIG_Spell_End, spCallbacks.AoeSpellRemove);
}

uint32_t CondHashSystem::ConditionHashtableInit(ToEEHashtable<CondStruct>* hashtable)
{
const int VANILLA_COND_CAP = 1000;
return HashtableInit(hashtable, VANILLA_COND_CAP /*2023*/);
}

uint32_t CondHashSystem::CondStructAddToHashtable(CondStruct* condStruct, bool overriding)
{

uint32_t key = StringHash(condStruct->condName);
CondStruct* condFound;
uint32_t result = HashtableSearch(condHashTable, key, &condFound);
if (result || overriding)
{
result = HashtableOverwriteItem(condHashTable, key, condStruct);
}
if (result == 3) { // over capacity
logger->error("Condition hashtable over capacity ({})! Trying to add {}", condHashTable->capacity, condStruct->condName);
}
return result;

}
19 changes: 3 additions & 16 deletions TemplePlus/condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,9 @@ struct CondHashSystem : ToEEHashtableSystem < CondStruct >
temple::Dll::RegisterAddressPtr((void**)&condHashTable);
}

uint32_t ConditionHashtableInit(ToEEHashtable<CondStruct> * hashtable)
{
return HashtableInit(hashtable, 1000);
}

uint32_t CondStructAddToHashtable(CondStruct * condStruct, bool overriding = false)
{
uint32_t key = StringHash(condStruct->condName);
CondStruct * condFound;
uint32_t result = HashtableSearch(condHashTable, key, &condFound);
if (result || overriding)
{
result = HashtableOverwriteItem(condHashTable, key, condStruct);
}
return result;
}
uint32_t ConditionHashtableInit(ToEEHashtable<CondStruct>* hashtable);

uint32_t CondStructAddToHashtable(CondStruct* condStruct, bool overriding = false);

int GetCondStructHashkey(CondStruct* condStruct)
{
Expand Down
1 change: 1 addition & 0 deletions TemplePlus/config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ static ConfigSetting configSettings[] = {
CONF_BOOL(antialiasing),
CONF_BOOL(softShadows),
CONF_BOOL(noSound),
//CONF_BOOL(showFps),
CONF_BOOL(featPrereqWarnings),
CONF_BOOL(spellAlreadyKnownWarnings),
CONF_BOOL(NPCsLevelLikePCs),
Expand Down
4 changes: 2 additions & 2 deletions TemplePlus/critter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ uint32_t LegacyCritterSystem::HasMet(objHndl critter, objHndl otherCritter) {
return addresses.HasMet(critter, otherCritter);
}

uint32_t LegacyCritterSystem::AddFollower(objHndl npc, objHndl pc, int unkFlag, bool asAiFollower) {
return addresses.AddFollower(npc, pc, unkFlag, asAiFollower);
uint32_t LegacyCritterSystem::AddFollower(objHndl npc, objHndl pc, int forcedFollower, bool asAiFollower) {
return addresses.AddFollower(npc, pc, forcedFollower, asAiFollower);
}

bool LegacyCritterSystem::FollowerAtMax(){
Expand Down
26 changes: 15 additions & 11 deletions TemplePlus/d20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2966,7 +2966,7 @@ ActionErrorCode D20ActionCallbacks::ActionCheckTripAttack(D20Actn* d20a, TurnBas

ActionErrorCode D20ActionCallbacks::ActionCostCastSpell(D20Actn * d20a, TurnBasedStatus * tbStat, ActionCostPacket * acp){
acp->hourglassCost = 0;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0.0f;
auto flags = d20a->d20Caf;
if ( (flags & D20CAF_FREE_ACTION) || !combatSys.isCombatActive()){
Expand Down Expand Up @@ -3030,7 +3030,7 @@ ActionErrorCode D20ActionCallbacks::ActionCostCastSpell(D20Actn * d20a, TurnBase
}

ActionErrorCode D20ActionCallbacks::ActionCostFullRound(D20Actn* d20a, TurnBasedStatus* tbStat, ActionCostPacket* acp){
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
acp->hourglassCost = 4;
if ( (d20a->d20Caf & D20CAF_FREE_ACTION) || !combatSys.isCombatActive())
Expand Down Expand Up @@ -3856,7 +3856,7 @@ ActionErrorCode D20ActionCallbacks::TurnBasedStatusCheckPython(D20Actn* d20a, Tu
}

ActionErrorCode D20ActionCallbacks::ActionCostFullAttack(D20Actn * d20a, TurnBasedStatus * tbStat, ActionCostPacket * acp){
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
acp->hourglassCost = 4;
//int flags = d20a->d20Caf;
Expand All @@ -3873,7 +3873,7 @@ ActionErrorCode D20ActionCallbacks::ActionCostFullAttack(D20Actn * d20a, TurnBas
}

ActionErrorCode D20ActionCallbacks::ActionCostPartialCharge(D20Actn * d20a, TurnBasedStatus * tbStat, ActionCostPacket * acp){
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
acp->hourglassCost = 3;
if ((d20a->d20Caf & D20CAF_FREE_ACTION) || !combatSys.isCombatActive())
Expand All @@ -3887,6 +3887,10 @@ ActionErrorCode D20ActionCallbacks::ActionCostPython(D20Actn* d20a, TurnBasedSta
return (ActionErrorCode) d20Sys.GetPyActionCost(d20a, tbStat, acp);
}

/*
0x100910F0
Used in: Standard attack, Standard Ranged attack, Trip Attack, Touch Attack, Throw Weapon, Throw Grenade
*/
ActionErrorCode D20ActionCallbacks::ActionCostStandardAttack(D20Actn* d20a, TurnBasedStatus* tbStat, ActionCostPacket* acp){

if ( d20Sys.d20Query(d20a->d20APerformer, DK_QUE_HoldingCharge)
Expand All @@ -3897,12 +3901,12 @@ ActionErrorCode D20ActionCallbacks::ActionCostStandardAttack(D20Actn* d20a, Turn
}

acp->hourglassCost = 0;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;

if (!(d20a->d20Caf & D20CAF_FREE_ACTION) && combatSys.isCombatActive())
{
acp->chargeAfterPicker = 1;
acp->attackCost = 1;

auto retainSurplusMoveDist = false;

Expand All @@ -3925,7 +3929,7 @@ ActionErrorCode D20ActionCallbacks::ActionCostStandardAttack(D20Actn* d20a, Turn
ActionErrorCode D20ActionCallbacks::ActionCostMoveAction(D20Actn *d20, TurnBasedStatus *tbStat, ActionCostPacket *acp)
{
acp->hourglassCost = 0;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
if (!(d20->d20Caf & D20CAF_FREE_ACTION) && combatSys.isCombatActive())
{
Expand All @@ -3941,7 +3945,7 @@ ActionErrorCode D20ActionCallbacks::ActionCostMoveAction(D20Actn *d20, TurnBased

ActionErrorCode D20ActionCallbacks::ActionCostNull(D20Actn* d20a, TurnBasedStatus* tbStat, ActionCostPacket* acp){
acp->hourglassCost = 0;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
return AEC_OK;
}
Expand All @@ -3953,21 +3957,21 @@ ActionErrorCode D20ActionCallbacks::ActionCostSwift(D20Actn* d20a, TurnBasedStat
}

acp->hourglassCost = 0;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
tbStat->tbsFlags |= TBSF_SwiftActionPerformed;
return AEC_OK;
}

ActionErrorCode D20ActionCallbacks::ActionCostStandardAction(D20Actn*, TurnBasedStatus*, ActionCostPacket*acp){
acp->hourglassCost = 2;
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
return AEC_OK;
};

ActionErrorCode D20ActionCallbacks::ActionCostWhirlwindAttack(D20Actn* d20a, TurnBasedStatus* tbStat, ActionCostPacket*acp) {
acp->chargeAfterPicker = 0;
acp->attackCost = 0;
acp->moveDistCost = 0;
acp->hourglassCost = 4;
if ( ( d20a->d20Caf & D20CAF_FREE_ACTION) || !combatSys.isCombatActive()){
Expand Down
4 changes: 2 additions & 2 deletions TemplePlus/d20_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ enum class ActionCostType : int {
struct ActionCostPacket
{
int hourglassCost;
int chargeAfterPicker; // flag I think; is only set at stuff that requires using the picker it seems
int attackCost; // how many attacks does this consume when doing Full Attack? (0 if not relevant; haven't seen a value > 1)
float moveDistCost;

ActionCostPacket() { hourglassCost = 0; chargeAfterPicker = 0; moveDistCost = 0.0f; }
ActionCostPacket() { hourglassCost = 0; attackCost = 0; moveDistCost = 0.0f; }
};
//const auto TestSizeOfActionCostPacket = sizeof(ActionCostPacket); // should be 12 (0xC)

Expand Down
74 changes: 69 additions & 5 deletions TemplePlus/damage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "pybind11/pybind11.h"
#include "python/python_dice.h"

const int DAMAGE_MES_UNKNOWN = 103;

namespace py = pybind11;

template <> class py::detail::type_caster<objHndl> {
Expand Down Expand Up @@ -962,16 +964,78 @@ bool Damage::SavingThrowSpell(objHndl obj, objHndl attacker, int dc, SavingThrow
// return addresses.SavingThrowSpell(obj, attacker, dc, type, flags, spellId);
}

bool Damage::ReflexSaveAndDamage(objHndl obj, objHndl attacker, int dc, int reduction, int flags, const Dice& dice, DamageType damageType, int attackPower, D20ActionType actionType, int spellId) {
SpellPacketBody spPkt(spellId);
BonusList bonlist;

int GetTargetSpellDcBonus(objHndl attacker, objHndl obj, SpellPacketBody &spPkt) {
if (!spPkt.spellEnum) {
return 0;
}
// Gets a DC bonus based on the target of the spell
BonusList bonlist;
dispatch.DispatchTargetSpellDCBonus(attacker, obj, &bonlist, &spPkt);

int nDCBonus = bonlist.GetEffectiveBonusSum();
return nDCBonus;
}

/* 0x100B9500 */
// Note: this is also used in traps, where spellId = 0
bool Damage::ReflexSaveAndDamage(objHndl obj, objHndl attacker, int dc, int reduction, int flags, const Dice& dice, DamageType damageType, int attackPower, D20ActionType actionType, int spellId) {
//return addresses.ReflexSaveAndDamage(obj, attacker, dc, reduction, flags, dice.ToPacked(), damageType, attackPower, actionType, spellId);

auto isSpellSave = actionType == D20A_CAST_SPELL; // todo: might require generalization for new action types?

return addresses.ReflexSaveAndDamage(obj, attacker, dc, reduction, flags, dice.ToPacked(), damageType, attackPower, actionType, spellId);
DispIoReflexThrow evtObj;
evtObj.reduction = (D20SavingThrowReduction)reduction;
evtObj.attackPower = (D20AttackPower)attackPower;
evtObj.damageMesLine = 105; // {105}{~Saving Throw~[TAG_SAVING_THROW_DESC]}
evtObj.attackType = (int)damageType;
evtObj.flags = (D20SavingThrowFlag)flags;

if (isSpellSave) { // in vanilla, this always called SavingThrow, which would not apply the descriptor flags (and also the new DC bonus dispatch)
evtObj.throwResult = SavingThrowSpell(obj, attacker, dc, SavingThrowType::Reflex, flags, spellId);
}
else {
evtObj.throwResult = SavingThrow(obj, attacker, dc, SavingThrowType::Reflex, flags);
}

auto caf = D20CAF_NONE;
if (evtObj.throwResult == 1) {
caf = D20CAF_SAVE_SUCCESSFUL;
if (reduction == D20SavingThrowReduction::D20_Save_Reduction_None) {
evtObj.effectiveReduction = 0;
}
else if (reduction == D20SavingThrowReduction::D20_Save_Reduction_Half) {
evtObj.effectiveReduction = 50;
}
else if (reduction == D20SavingThrowReduction::D20_Save_Reduction_Quarter) {
evtObj.effectiveReduction = 25;
}
else {
evtObj.effectiveReduction = 100;
}
}


dispatch.Dispatch49ReflexSaveReduction(obj, &evtObj);
if (evtObj.effectiveReduction == 100) {
if (isSpellSave) {
DealSpellDamage(obj, attacker, dice, (DamageType)evtObj.attackType, evtObj.attackPower,
100, DAMAGE_MES_UNKNOWN, D20A_CAST_SPELL, spellId, caf);
}
else {
DealDamage(obj, attacker, dice, (DamageType)evtObj.attackType, evtObj.attackPower,
100, DAMAGE_MES_UNKNOWN, actionType);
}
}
else if (isSpellSave) {
DealSpellDamage(obj, attacker, dice, (DamageType)evtObj.attackType, evtObj.attackPower,
evtObj.effectiveReduction, evtObj.damageMesLine, D20A_CAST_SPELL, spellId, caf);
}
else {
DealDamage(obj, attacker, dice, (DamageType)evtObj.attackType, evtObj.attackPower,
100, evtObj.damageMesLine, actionType);
}

return evtObj.throwResult;
}

void Damage::DamagePacketInit(DamagePacket* dmgPkt)
Expand Down
Loading