From fe62c9d11024194f0776c199807bf6e150d0338d Mon Sep 17 00:00:00 2001 From: Jaka Kranjc Date: Sun, 12 Jan 2014 11:59:29 +0100 Subject: [PATCH] implemented iwd2 saving throw system (to best of my knowledge) --- gemrb/core/EffectQueue.cpp | 7 +++++- gemrb/core/Scriptable/Actor.cpp | 26 ++++++++++++++++++---- gemrb/core/Scriptable/Actor.h | 2 +- gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp | 29 ++++++++++++++++++++----- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/gemrb/core/EffectQueue.cpp b/gemrb/core/EffectQueue.cpp index c6926659b2..076b0101d7 100644 --- a/gemrb/core/EffectQueue.cpp +++ b/gemrb/core/EffectQueue.cpp @@ -1087,7 +1087,12 @@ static bool check_resistance(Actor* actor, Effect* fx) bool saved = false; for (int i=0;i<5;i++) { if( fx->SavingThrowType&(1<GetSavingThrow(i, bonus); + // FIXME: first bonus handling for iwd2 is just a guess + if (iwd2fx) { + saved = actor->GetSavingThrow(i, bonus-fx->SavingThrowBonus, fx->SpellLevel, fx->SavingThrowBonus); + } else { + saved = actor->GetSavingThrow(i, bonus); + } if( saved) { break; } diff --git a/gemrb/core/Scriptable/Actor.cpp b/gemrb/core/Scriptable/Actor.cpp index 88e8233b3b..d2dd541c24 100644 --- a/gemrb/core/Scriptable/Actor.cpp +++ b/gemrb/core/Scriptable/Actor.cpp @@ -3222,21 +3222,39 @@ void Actor::RollSaves() // in adnd, the stat represents the limit (DC) that the roll with all the boni has to pass // since it is a derived stat, we also store the direct effect bonus/malus in it, but make sure to do it negated -// FIXME: in 3ed, the stat is added to the roll and boni (not negated), then compared to some predefined value (DC) +// in 3ed, the stat is added to the roll and boni (not negated), then compared to some predefined value (DC) #define SAVECOUNT 5 static int savingthrows[SAVECOUNT]={IE_SAVEVSSPELL, IE_SAVEVSBREATH, IE_SAVEVSDEATH, IE_SAVEVSWANDS, IE_SAVEVSPOLY}; /** returns true if actor made the save against saving throw type */ -bool Actor::GetSavingThrow(ieDword type, int modifier) +bool Actor::GetSavingThrow(ieDword type, int modifier, int spellLevel, int saveBonus) { assert(type (int) GetStat(savingthrows[type]); + + if (!third) { + ret += modifier + GetStat(IE_LUCK); + return ret > (int) GetStat(savingthrows[type]); + } + + int roll = ret; + // NOTE: assuming criticals apply to iwd2 too + // NOTE: we use GetStat, assuming the stat save bonus can never be negated like some others + int save = GetStat(savingthrows[type]); + ret = roll + save + modifier; + if (ret > 10 + spellLevel + saveBonus) { + // ~Saving throw result: (d20 + save + bonuses) %d + %d + %d vs. (10 + spellLevel + saveMod) 10 + %d + %d - Success!~ + displaymsg->DisplayRollStringName(40974, DMC_LIGHTGREY, this, roll, save, modifier, spellLevel, saveBonus); + return true; + } else { + // ~Saving throw result: (d20 + save + bonuses) %d + %d + %d vs. (10 + spellLevel + saveMod) 10 + %d + %d - Failed!~ + displaymsg->DisplayRollStringName(40975, DMC_LIGHTGREY, this, roll, save, modifier, spellLevel, saveBonus); + return false; + } } /** implements a generic opcode function, modify modified stats diff --git a/gemrb/core/Scriptable/Actor.h b/gemrb/core/Scriptable/Actor.h index ba1ebd93dd..7c31bf0c4d 100644 --- a/gemrb/core/Scriptable/Actor.h +++ b/gemrb/core/Scriptable/Actor.h @@ -440,7 +440,7 @@ class GEM_EXPORT Actor : public Movable { /** gets saving throws */ void RollSaves(); /** returns a saving throw */ - bool GetSavingThrow(ieDword type, int modifier); + bool GetSavingThrow(ieDword type, int modifier, int spellLevel=0, int saveBonus=0); /** Returns true if the actor is targetable */ bool ValidTarget(int ga_flags, Scriptable *checker = NULL) const; /** Clamps a stat value to the valid range for the respective stat */ diff --git a/gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp b/gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp index 61595c7b86..6465356b53 100644 --- a/gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp +++ b/gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp @@ -553,10 +553,21 @@ static int check_iwd_targeting(Scriptable* Owner, Actor* target, ieDword value, case STI_CIRCLESIZE: return DiffCore((ieDword) target->GetAnims()->GetCircleSize(), val, rel); case STI_EVASION: - if (target->GetThiefLevel() < 7 ) { - return 0; + if (enhanced_effects) { + // NOTE: no idea if this is used in iwd2 too + // FIXME: check for evasion itself + if (target->GetThiefLevel() < 2 && target->GetMonkLevel() < 1) { + return 0; + } + // FIXME: if it is used, make sure to pass correct values here (pulled from the effect) + val = target->GetSavingThrow(4, 0); // reflex + } else { + if (target->GetThiefLevel() < 7 ) { + return 0; + } + val = target->GetSavingThrow(1,0); //breath } - val = target->GetSavingThrow(1,0); //breath + if (val) { return 1; } @@ -1195,7 +1206,13 @@ int fx_blinding_orb (Scriptable* Owner, Actor* target, Effect* fx) damage *= 2; } //check saving throw - bool st = target->GetSavingThrow(0,0); //spell + bool st; + if (enhanced_effects) { + st = target->GetSavingThrow(2, 0, fx->SpellLevel, fx->SavingThrowBonus); // fortitude + } else { + st = target->GetSavingThrow(0,0); //spell + } + if (st) { target->Damage(damage/2, DAMAGE_FIRE, Owner, fx->IsVariable, fx->SavingThrowType); return FX_NOT_APPLIED; @@ -2659,7 +2676,9 @@ int fx_control (Scriptable* Owner, Actor* target, Effect* fx) if (fx->Parameter3 && fx->Parameter4GameTime) { fx->Parameter3 = 0; - if (target->GetSavingThrow(IE_SAVEWILL, 0)) return FX_NOT_APPLIED; + if (target->GetSavingThrow(IE_SAVEWILL, 0, fx->SpellLevel, fx->SavingThrowBonus)) { + return FX_NOT_APPLIED; + } } if(0) print("fx_control(%2d)", fx->Opcode); bool enemyally = true;