Let's get acquainted with "combat mechanics" found in many role-playing games. We briefly touched the basics of dice-throwing process in D&D dice, and now we'll learn how it is applied.
We are to play extremely simplified "one-dimensional" version of the classic Rogue game: the sequence of monsters (and some stuff) is generated - and we want to "replay" every combat using dice-throwing with predefined random generator and tell how long the hero survives. Screenshot above is from the different game ("Quest for Glory I, VGA version" by Sierra) but situation (and mechanics) is quite similar!
Use Engel's Randomizer. I.e. given initial seed
every next value
is generated by adding 3.1415926
, raising to the 8-th
power - and then taking fractional part (itself truncated
to first 7
digits after the decimal point). To simulate die-throwing divide 0..1
range to necessary
sections corresponding to die sides, just as in Dice Rolling task.
When the hero and some monster are engaged in a fight, they attack each other in turns (except that some monsters
have 2
or 3
attacks which happen one by one on monster's turn). Every attack is performed in two steps:
Hit is calculated by throwing a single 1d20
die and checking if the result is above the threshold.
Threshold is calculated as 21
minus attacker's level
and minus defender's armor class
(AC). The latter is
confusing: armor class is "the lower the better" (historically). Besides this attacker may have weapon with magical bonus
(to-hit modifier
) which adds to the value shown by the die.
Damage calculation is simpler, it is just throwing of dice defined by weapon type, adding any magical bonus
(to-damage modifier
) and, in case when attack is performed by hero, adding bonus due to strength
(monsters
seemingly has no strength, or rather no bonus due to it).
Let's assume the strength gives +1
when it is 15
or more, +2
when 18
or more, -1
when below 12
-
in other words int(strength / 3) - 4
.
Consider an example: Hero at the 3
level of experience (and strength 16
) meets Hobgoblin with AC 5
.
Hero is wielding a mace with +1
to-hit and +1
to-damage. Hero attacks first, hitting threshold is
21 - attacker_level - defender_AC = 21 - 3 - 5 = 13
Suppose the throw of 1d20
die yields 12
, we add +1
to-hit modifier and so we just meet the threshold -
attack hits.
Now the mace general damage is 2d4
, we throw two dice, say, giving 3+2=5
. To this we add +1
of to-dam
bonus and +1
bonus for strength - thus Hobgoblin's life points (also called "hit points") are reduced by 7
.
Suppose the monster survives and delivers response.
Hero is wearing armor improving AC by 4
from default value of 10
, so resulting AC is 6
. Hobgoblin itself
is level 1
creature without hit bonus. So the hitting threshold is 21-1-6 = 14
. If 1d20
die
is cast to give 14
or higher, the damage is then calculated as 1d8
(damage type is simply defined by monster
type and they have no to-damage bonus).
For convenience we have prepared monster list in a form which could be easily copy-pasted into the code in most scripting languages:
[
# name, exp, $lvl, $ac, $dmg, $letter, $special
['Bat', 1, 1, 3, '1d2'],
['Snake', 3, 1, 5, '1d3'],
['Jackal', 2, 1, 7, '1d2'],
['Kobold', 1, 1, 7, '1d4'],
['Hobgoblin', 3, 1, 5, '1d8'],
['Floating Eye', 5, 1, 9, '1d1', 'E'], # can freeze player
['Giant Ant', 10, 2, 3, '1d6', 'A'], # can poison to reduce strength
['Gnome', 8, 2, 5, '1d6'],
['Leprechaun', 10, 3, 8, '1d1'], # can steal money
['Orc', 5, 2, 6, '1d6/1d6'],
['Zombie', 7, 3, 8, '1d8'],
['Nymph', 40, 3, 9, '1d2'], # can steal inventory
['Rust Monster', 25, 5, 2, '0d0/0d0'], # can rust (weaken) armor
['Quasit', 35, 3, 2, '1d2/1d2/1d4'],
['Centaur', 15, 4, 4, '1d6/1d6'],
['Yeti', 40, 4, 6, '1d6/1d6'],
['Troll', 55, 6, 4, '1d6/2d4'],
['Wraith', 55, 5, 4, '1d6'], # can reduce experience
['Umber Hulk', 130, 5, 2, '3d4/2d5'],
['Vampire', 250, 6, 1, '1d10'],
['Dragon', 500, 7, 3, '1d8/1d8/3d6'],
]
Every monster is denoted by the first letter of its name, except cases where optional field "letter" is present.
So G
is for gnome and A
is for giant ant.
Ignore special abilities except for Giant Ant and Rust Monster. For them, in case of hit is successful,
cast additional 1d4
die and if it shows 4
either decrement hero's strength or increment AC respectively. Do
this before damage is calculated/inflicted.
Monster hit points are calculated at the beginning of the fight as (monster_level)d8
(e.g. sum of casting
several 1d8
dice).
When the monster is defeated, its Exp
value is added to heroe's experience. This may increase hero's level.
Next level is assigned on reaching 10
, 20
, 40
, 80
, 160
points (and so on, doubling).
Hero's health is expressed by current hit-points
value and is limited by maxHP
, which starts at 14
and
is increased by throwing 1d10
die on every level andvancement.
As a way to replenish current hit-points
let us add defeated monster's exp
(capped by maxHP
) after every
fight is completed (and possible level advance happens).
Initial hero's strength is 16
. For monsters it is always 12
(so they have no damage bonus).
Hero's weapon (its damage) and armor (its AC) are defined at start of each run randomly:
weapons = [
['rock', '1d2'],
['dagger', '1d6'],
['mace', '2d4'],
['sword', '1d10'],
['zweihander', '3d6'],
['spear', '1d8'],
];
armors = [
['leather-armor', 8],
['ring-mail', 7],
['scale-mail', 6],
['chain-mail', 5],
['splint-mail', 4],
['plate-armor', 3],
Besides monsters hero may encounter some useful items, represented with the following symbols:
(
weapon-enchantment (increase "to-hit"))
weapon-enchantment (increase "to-dam")!
potion of increase strength?
scroll of enchant armor (decrease AC):
slime-mold, food restoring health to maxHP
Few more subtle details (thanks to our colleague Clive): hero's starting
level is 1
, initial hit-points are at maximum, player or monster dies at HP = 0
or less (actually some
other games may treat this as "unconsious" state, from which it is yet possible to rehabilitate); there are
no special restrictions on AC
- it may potentially go over 10
or become negative (and in some games
it often does). Strength is also not "capped" at least in our implementation (it is not the same with original
game as it uses non-linear dependence with damage).
Input data provide N
for the number of test-cases following.
Next N
lines each start with randomizer seed, weapon and armor choice and then a long sequence of monsters
and items the hero is going to encounter.
Answer calculate by which monster the hero is defeated on each run and put this into the answer as a pair of
values - letter denoting the monster and numeric index showing how far the hero travelled (how many symbols
of the monsters/items line were passed successfully). Concatenate everything with spaces. In case when hero
conquers all monsters, put &
symbol in the answer (instead of the monster's name) - it means the hero
found the amulet of Yendor (or some chest of gold etc).
Example
input:
5
0.258461 dagger scale-mail BSKKHS:)SKB(HASLALG)BHALE?HOLNZRHZCKL?OZLTS?YZZ:R!:LH?QBLNOGO
0.679051 rock scale-mail S)JSHJJEJKSA:(JJAA!SEZJG)N!JNL:S!JNRCKJ((NBKOA(YET?GJ:ZDTGASCWO
0.763629 mace leather-armor BS(JHHJHEBEHB(JLSA:O!SE(AZK(!J?ZLZG:EOBHOO!KEGJ)NL:!?)K)RGB?EJ?CLGVR
0.363055 mace ring-mail SJJHSJHE:A?B!KEHKKGGZLOS)BHOK!HKB?ECYE!)EHNB!ERGHUEUGTJ)Z(T(E(R
0.527506 sword scale-mail B(SJHH:JJBAKJJJHB(JOH)AOJ?JAJGBAH:EAJOT?Q)C)YAULZ??WBUJGQG(!!SLH
answer:
T 41 H 4 & 68 T 53 T 38
The debug-output of this example could be found by this link - let's try to decipher few first lines:
New Run -- correspondint to 1st testcase, 0.258461 dagger scale-mail BSKK
rnd: 0.1913744 -- next random value (after 0.258461) - seemingly generating Bat's hit-points
Attack: hero(14) Bat(2) -- values in parentheses show remaining health
rnd: 0.1837846 -- next random value - testing whether hero hits the Bat on attack
hit: 4 vs 17 -- (no, not hit)
Attack: Bat(2) hero(14)
rnd: 0.96505
hit: 20 vs 14 -- bat is more successful
rnd: 0.0797763
dam: 1,2=1 -- but only inflicts small damage
... a number of lines skipped till the last attack with this Bat
Attack: hero(10) Bat(2)
rnd: 0.8982159
hit: 18 vs 17
rnd: 0.1906181
dam: 1,6=3 -- Bat has 2 hit-points and so is defeated by damage 3
killed Bat
Exp: 1 (+1) -- hero's experience is increased
rnd: 0.5617105 -- next monster's health is generated
Attack: hero(11) Snake(5)
rnd: 0.4353387
hit: 9 vs 15
... and so on