Saving Throws
This is pretty much straight out of D&D, so should be fairly obvious to most players.
The idea is when certain spells are cast, there is no 'hit or miss' chance, they are simply going to happen, but you then get a dice roll for a chance of saving your own ass from the majority of the damage.
Successful Saving Throw Results
Upon a successful save, damage is modified - not entirely prevented. Typically, per D&D, it is reduced by 1/2, 1/4, etc, and that appears to be exactly how realms works. If a spell can be saved against, then the result of the save is coded into that spell itself.
Here are some examples that were easy to spot in the code, just to give you a general impression of how this stuff works:
Spell Name | Successful Save Result |
---|---|
Burning Hands | 1/2 Damage |
Colour Spray | 1/2 Damage |
Ethereal Fist | 1/4 Damage |
Sonic Resonance | 3/4 Damage |
Some have a bit more math behind them, here's one example:
Acetum Primus
Normal Damage:dam = 1.3*(2*level*number_range( 1, 4 )+7)
Saved Throw:dam = 3*dam/4
So, you always still calculate regular damage, but if you succeed the save, you do some additional math.
For Acetum, you times the regular damage by 3, but then divide by 4.... which is just a tricky way of reducing damage by 25%
(Damage of 10 would mean (3*10)/4, or 30/4, or 7.5. So... 75% damage, 25% reduction)
The Code
In terms of realms code, all we can do is look at the old Smaug 1.8 code and see how that works, and infer the current code works on a similar system, even if slightly modified at this point. Here's a relevant snippet for Save vs. Poison, but they're all the same for the other saves as well, exact same values.
/* * Compute a saving throw. * Negative apply's make saving throw better. */ bool saves_poison_death( int level, CHAR_DATA *victim ) { int save; save = 50 + ( victim->level - level - victim->saving_poison_death ) * 5; save = URANGE( 5, save, 95 ); return chance( victim, save ); }
I really am no C programmer, but I work enough with code to squint and pretend it makes sense, I read that as saying:
We're going to have an integer number we call 'save'
That 'save' is defined by taking the number 50, adding (victims level - caster level - victim saving throw for X), and multiplying by 5.
We'll limit that resulting value to between 5 and 95
We will return the chance the victim has to save -- i.e. the % or number they need to 'roll' to save themselves.
Applied Examples
- Mob level 50, player level 50 with -20 saving throw:
50 + (50 - 50 - (-20)) * 5 50 + (20) * 5 = 100 Returns: chance: (player, 100%) -- 100% saving throw success
- If the mob is level 54, player level 50 with -20 saving throw:
50 + (50 - 54 - (-20)) * 5 50 + (16) * 5 = 80 Returns: chance: (player, 80%) -- 80% saving throw chance
- If the mob is level 49, then:
50 + (50 - 49 - (-X) * 5 50 + (1 - (-X)) * 5 = 100
Solving for X then results in -19 to achieve max 100% save chance against a level 49 mob.
Since we do most fighting here at Avatar level, then the primary variable here is just the mobs level, and we can make a simple chart showing the max "Save vs. X" number you need to always save:
MoB Level: 100% save number: 48: -18 49: -19 50: -20 51: -21 52: -22 53: -23 54: -24
Conclusions
Realms Saving Throws work exactly like D&D
Not all spells/attacks grant a saving throw opportunity. Those that do are specifically coded with a unique damage modifier.
This code outputs your percentage of succeeding a saving throw. I don't really know how that is then rolled/calculated, but since its a percentage it shouldn't really matter. In D&D terms, 80% saving throw chance would just mean rolling a d20 and getting a 5 or higher. I'm assuming that one way or the other realms is doing similar math and simulated 'rolls'.
In situations where a mob launches an attack that grants a saving throw, you can significantly reduce the damage you eat by having a high saving throw.
Damage still stacks with Sanctuary, Protection, Resists, etc. When 'saved' against, a spell that would normally do 100 damage may instead send 50 damage to the player. The player's spells then further reduce damage. Sanctuary would drop that 50 to 25. If the mob is evil and you have protection, the result is 18.75 damage received.
Maximum Saving Throw Value
At least in Smaug 1.8, and given I have never seen a mob higher than level 54, having a Save Vs. X of 24 is the max you would ever need for 100% success.
Bonus Fun
There's also code that modifies how saving throws based on Resistance/Immunities, written by the man himself.
This just seems to be a nice little common sense modifier where if you are immune/resistant/susceptible to X, you get a big bonus, small bonus, or penalty, to your saving throw chance.
/* * Make adjustments to saving throw based in RIS -Thoric */ int ris_save( CHAR_DATA *ch, int chance, int ris ) { sh_int modifier; modifier = 10; if (IS_SET (ch->immune, ris) || IS_SET (ch->stance_immune, ris)) modifier -= 10; if (IS_SET (ch->resistant, ris) || IS_SET (ch->stance_immune, ris)) modifier -= 2; if ( IS_SET(ch->susceptible, ris ) || IS_SET ( ch->stance_immune, ris)) { if ( IS_NPC( ch ) && IS_SET( ch->immune, ris ) ) modifier += 0; else modifier += 2; } if ( modifier <= 0 ) return 1000; if ( modifier == 10 ) return chance; return (chance * modifier) / 10; }