Attacker rolls 1d20 + ATTACK (character attribute)
Defender may either “Dodge” (roll 1d20 + Agility, must beat attack roll to dodge entirely), or may “Block”, which guarantees the attack lands, but reduces damage by the Block value, to a minimum of 1 damage.
Critical hits (natural 20s) do double damage.
// A sample (GS)script for an arbitary combat system.
// The attacker selects a target to attack, and the target gets two choices
// They can try evade damage entirely by using an AGILITY buffed roll
// Or they can BLOCK which will subtract their block value from the damage
// (minimum damage 1). If the attacker rolls a 20 and lands damage
// (of any kind) it is doubled as a critical hit. We report this as a
// "mighty swing" in the output
// have the caller select a target
Character target=gsSelectCharacter(CALLER,"Select a target to attack");
// have the target select a defence type
String defencetype=gsGetChoice(target,CALLER+" is attacking you, pick a defence type!",["Dodge","Block"]);
// do some attack rolls ; the attacker gets their "ATTACK" attribute added
// just because otherwise this code biases the defender who gets their bonus
Integer naturalattackroll=gsRand(1,20);
// note we force this KV into an Integer, naturally it's a string and that
// will ruin the maths later.
Integer attackvalue=gsGetKV(CALLER,"Characters.Attack");
Integer attackroll=naturalattackroll+attackvalue;
Integer defenceroll=gsRand(1,20);
// only gets a bonus if "dodge" mode
if (defencetype=="Dodge") {
Integer naturalagility=gsGetKV(CALLER,"Characters.Agility");
defenceroll=defenceroll+naturalagility;
}
// and calculate the attack
String output="";
Integer originaldamage=gsRand(1,6); // 1-6 damage
Integer damage=originaldamage; // for debugging, so we can see the original
if (defencetype=="Dodge") {
// all or nothing attack
if (defenceroll>attackroll) {
// miss
output=" swings at "+target+", but misses!";
damage=0;
} else {
// hit...
// is it a crit?
if (naturalattackroll==20) {
output=" swings mightily at "+target;
damage=damage*2;
} else { output=" swings at "+target; }
}
}
if (defencetype=="Block") {
// defence roll does nothing, we just take damage. maybe double.
// double it before the block value. you may wish to do it after
// which would make the minimum crit damage blockable to 2 rather than 1
output=" strikes against "+target+"'s shield";
if (naturalattackroll==20) {
damage=damage*2;
output=" strikes mightily against "+target+"'s shield";
}
Integer blockvalue=gsGetKV(CALLER,"Characters.Block");
damage=damage-blockvalue;
if (damage<1) { damage=1; } // cap the reduction to 1 damage
}
// add damage to the message, if any was done
if (damage>0) {
output=output+", dealing "+damage+" points of damage";
}
Integer discard=gsSayAsChar(CALLER,"/me "+output);
// and inflict the damage. Need an API call for this :P
// this ought to work for now
discard=gsAPIX(CALLER,"Roller.rollDamageAgainst",[target+"","1","1","1","1","1","0",damage+"",CALLER+output]);