Skip to content

Commit

Permalink
implemented iwd2 saving throw system (to best of my knowledge)
Browse files Browse the repository at this point in the history
  • Loading branch information
lynxlynxlynx committed Jan 12, 2014
1 parent a1a8512 commit fe62c9d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
7 changes: 6 additions & 1 deletion gemrb/core/EffectQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<<i)) {
saved = actor->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;
}
Expand Down
26 changes: 22 additions & 4 deletions gemrb/core/Scriptable/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<SAVECOUNT);
InternalFlags|=IF_USEDSAVE;
int ret = SavingThrow[type];
if (ret == 1) return false;
if (ret == SAVEROLL) return true;
ret += modifier + GetStat(IE_LUCK);
return ret > (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
Expand Down
2 changes: 1 addition & 1 deletion gemrb/core/Scriptable/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
29 changes: 24 additions & 5 deletions gemrb/plugins/IWDOpcodes/IWDOpcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2659,7 +2676,9 @@ int fx_control (Scriptable* Owner, Actor* target, Effect* fx)

if (fx->Parameter3 && fx->Parameter4<game->GameTime) {
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;
Expand Down

0 comments on commit fe62c9d

Please sign in to comment.