This commit is contained in:
Kim ravn Hansen
2025-08-31 10:08:06 +02:00
commit 81e1196669
12 changed files with 4014 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
out/*
.DS_*

12
Makefile Executable file
View File

@@ -0,0 +1,12 @@
sort:
cd tooling && lua process.lua ../main.adoc --overwrite
html:
asciidoctor -b html main.adoc -o out/main.html && open out/main.html
pdf:
asciidoctor-pdf main.adoc -o out/main.pdf && open out/main.pdf
d20:
echo "" > out/statsD20.csv
lua tooling/mathD20.lua > out/statsD20.csv && open out/statsD20.csv

393
ideas.adoc Executable file
View File

@@ -0,0 +1,393 @@
= Ideas
== MANIFESTO
* Quick, easy, simple.
* Fun, laughter, satire, irreverent.
=== THINGS WE WANT
* Fun, laughter, humor, satire, informal rules.
* Fast & easy to get into.
* Fast & smooth gameplay (not too much math, not many exceptions).
* Should feel a bit like a good, but very immersive, board game.
* Combat that is FUN, no matter the outcome.
* Teamwork, problem solving, resource anxiety.
=== THINGS WE DON'T WANT
* Arguing over technicalities.
* Spending game time looking at the rules.
* Internal strife or competition to be best or mow down the most monsters.
* Power gaming and min/maxing.
* People getting bored during combat.
* Undetectable, unperceivable, or unstoppable events that kill adventurers
without player input or agency.
=== UNIMPORTANT
* "Good" roleplay.
* Balance. Not all characters should be equally "good" on the battlefield.
== IDEAS
=== Adventurer's Blessing
* All Adventurers have The Adventurer's Blessing.
* They have a different eye color.
* They have access to racial perks (ancient blood that awakens as they gain levels).
* They don't get PTSD or any other mundane mental illnesses, get common colds
and other mundane diseases, they have very high pain tolerance, and they are
generally awesome.
* Their gift can burn out if they do evil stuff such as:
** Kill for fun or sadism, or killing the truly innocent, such as kids (100%
burnout).
** Kill beings that aren't monsters or villains (high risk of burnout).
** Harm beings that aren't monsters or villains (moderate risk of burnout).
** Steal from or swindle beings that aren't monsters or villains (low risk of
burnout).
** Stop actively adventuring (burnout risk increases over time).
** Become parents (100%)
** All these risks are cumulative.
=== MAX (for d20 system) and 80 (for d100 system)
No matter how skilled you are, your target number cant be higher than a
certain limit Any roll above that limit is an automatic failure.
However, your skill level itself isn't capped. This matters when you score a
critical hit. For example, if your attack skill is 22, you'll still fail on
rolls of 16 to 20—but if you roll a 15 (a critical hit), your damage will be
22.
=== ATTACK & DAMAGE
Attacks always deal at least a bit of damage.
* Glancing Blow (rolled above your TN) - deals damage equal to your weapon's Base
Damage, and no special effects can apply to the attack.
* Hit (rolled below your TN) Deals damage based on your roll plus the weapon's Base Damage.
** Hits MAY trigger ONE Hit Effect.
*** Some weapons have Hit Effects.
*** Most Hit Effects cost a number of Hit Points to trigger.
*** Many Hit Effects require that the attacker be of a certain level.
*** Only one Hit Effect may be triggered per Hit.
* Crit (roll equal to your TN) Deals damage equal to TWICE your SKILL LEVEL
plus weapon's Base Damage.
** Crits MAY trigger ANY available Hit Effects
*** The player chooses which Hit Effects to trigger.
*** Level Requirements are ignored (I think)
*** They will not drain any Hit Points.
** When it comes to Hit Effects, Crits count as Hits, except for the fact that
certain classes/abilities have Crit Effects that only triggers when you Crit.
** Usually only one Effect applies - and the player gets to choose.
Monster Crits:: Boss Monsters (and certain Skirmisher monsters) can crit too -
and they have random Crit Effects - each Crit-Capable monster has its own Crit
Table of nasty effects that can be triggered on a Crit.
=== MAGIC && SPELLS
You use Wands to cast Spells.
You roll your Magic skill.
* Each spell should take up one page.
* Each spell should have a description of what happens when you succeed,
fizzle, and crit. Also, each WAND (not spell) should have a quality rating,
indicating the max target number available. Here are some PARTIAL EXAMPLES:
** Fizzle (roll above TN) - the spell fizzles, but you may try again next
round.
** Success (rolled below TN) - the spell takes effect -look up the effect in
the spell's description. Each spell has a table where you can look up the
effect, based on what you rolled. The wand is usually drained after
successfully casting a spell.
** Crit (roll equal TN) - The spell takes effect, but you get to choose the
effect; you may choose any effect tier up to, and including, one tier higher
than what your roll would normally grant. The wand is usually NOT drained
after a Crit.
==== SPELLS
Fireballs::
Causes insane pain in the testicles of the target. Can only target testicle-havers.
Higher effect tiers actually set fire to the balls.
Revive Adventurer::
* Only adventurers can be resurrected.
* They can be resurrected within 1 day of their death per adventurer level.
* When using a wand to resurrect an adventurer, you must always roll higher
than their level.
* There is a high chance that the wand can never be used again.
* There is a small risk that the adventurer will be turned into an intelligent
undead of a type that is determined by their stats, level, and some
randomness (they will typically rise as a revenant, but death knight,
vampire, and lich are also in play).
* There is a risk that the adventurer will gain some otherworldly traits that
have followed them from the other world. These traits can be demonic,
angelic, necromantic, sylvan, elemental, etc.
=== DEFENSE AND ARMOR
==== ARMOR
When an adventurer dons armor, their max HP and current HP increases by a value
that depends on the value. When they doff the armor, their max- and current HP
is lowered by the same amount.
[WARNING]
You can die (or at least reach Zero Hit Points) if you doff armor while close
to death.
==== ITEM SLOTS
Adventurers begin play with 4d4 Item Slots. Item Slots are used to carry stuff,
and they also grant you Hit Points.
* Normal Items take up a single Item Slot.
* Large Items - like armors - take up more than one Item Slot.
* Small Items - like gold and gems - take up so little space that you can can
squeeze a number of them into one Item Slot.
* If you have unused Item Slots, you get extra Hit Points. You get one HP per
unused slot, multiplied by your level. For instance, a level 3 character with
4 unused Item Slots gets 3*4=12 extra Hit Points.
[WARNING]
You can die (or at least reach Zero Hit Points) if you are low on Hit Points
and pick up heavy stuff.
=== DIFFICULTY (advantage/disadvantage)
Works just like DnD and all the others.
=== SKILLS (THERE ARE NO ATTRIBUTES)
These are the base skills that all adventurers have to begin with, and as the
character progresses, they can attain new skills that can allow them to do more
and fancy stuff.
[%header,cols="3,9"]
|===
| Basic Skills | Description
//----------------------|------------------------------------------------------
| Melee Attack | Attacks against baddies in melee range.
| Ranged Attack | Attacks against baddies outside melee range.
| Magic | Using wands to cast spells.
// | Skulduggery | Stealth & stuff.
// | Knowledge | History, geography, lore.
// | Grit | Toughness, raw strength, willpower.
// | Awareness | Perception, comprehension, alertness, insight.
//----------------------|------------------------------------------------------
|===
==== Skill Burning
D20 Version::
You can burn one of your skills (permanently reducing its score by 1) before
you roll, and you can force the die roll to become whatever you want. If your
skill score is currently 13, you can burn one point, reducing it to 12,
but then you have the power to force the d20 to become whatever you want (in
this case a 12 would usually be the best option).
You can also do this retroactively, after you've rolled, but you must burn
three skill points.
D100 Version::
Burn 5 skill points before you roll to force a roll to become whatever you want.
Burn 5 skill points after you've rolled to make a reroll. 10 skill points on your
next reroll, 15 on the next, and so on.
Burn 2 skill points before you roll to gain advantage.
=== ADVANCEMENT
Advancement incentivise fast and dangerous fun.
We want fun, fast, and toe-curlingly dangerous dungeon crawls.
We want lots silly and "active" downtime (i.e. all the players do fun stuff).
Fast-Paced Dungeon Crawls::
We award fast-paced dungeon crawls, so
* Each monster "defeated" (killed, pacified, or routed) gives XP.
* Each encounter has a "bonus time" — if you defeat the encounter within that
time, you get bonus XP.
** Each monster has a "bonus time" attribute - typically a number of minutes.
** An encounter's "bonus time" is calculated by adding up all "bonus time"
attributes.
Fast-Paced Almost-Always-Successful Environmental Encounters::
The PCs gain experience for _cleverly_ or _luckily_ overcoming environmental
challenges such as traps, cliffs, pits, and puzzles.
All challenges should be solvable or even have an obvious/naive brute force
solution - but using the naive solution does not grant XP - you gain XP by
daring and by being clever.
* If the PCs scale a wall by being clever (using their brains) or daring
(successful skill rolls), they gain XP. But even if they aren't clever or
lucky, the GM should consider letting them scale the wall anyway, simply by
brute forcing the problem.
* If the PCs cleverly disable or daringly circumvent a trap, they should get XP
- but the PCs could brute force the problem, but not gaining XP. **On that
note** - most traps
should be visible - invisible traps that deals automatic damage are not fun.
* If the PCs open a door by picking a lock, social engineering, or otherwise
being clever, they gain XP. But if they simply bash it to pieces, they don't
get XP.
Fun and Silly Downtime::
* PCs get lots XP for carousing. Especially if they get up to mischief - but
only if they do so as a party, and not individuals.
** Gambling is an option
** Prize fighting is an option.
* PCs should only level up during downtime.
* PCs can gain a bit of XP if they donate money to charity or invest in a
house, fortress, etc.
Ad hoc Progress::
* (d100) Maybe 1 XP could be converted directly into a +1 in a skill. Or maybe
it'll cost [current value / 10 rounded down] XP to increment a skill.
* (d20) Maybe it'll cost [current value] XP to increment a skill.
=== PERKS/ABILITIES/STUFF
Monstrous Gourmand:: If a dead monster has fresh meat on it, you can probably
eat it without issue. You can spend 1 hour preparing the meat, then you have 1
daily ration of food. Large monsters can yield more than one ration. Be aware
that only you can eat those rations safely - normal people could get sick from
eating monster meat.
Dwarf (level 1):: You have one extra item slot (maybe for a later dwarf perk).
You have a lot of facial hair, no matter what gender you are. Your tolerance
for alcohol is quite high.
Assassinate (d100):: Works better for the d100 version of this game. Instead of
rolling "attack", you roll Skulduggery. If you hit, you deal the same amount of
damage as what you rolled on your d100, but if you fail, you miss completely,
dealing no damage, and no special effect. *NOTE:* Assassination should have its
own type of special effect, if any at all.
== Stats
* Skills - not attributes
* Item Slots
* Hit Points
* Level
* Dodge/Defense Points ???
== Attack (Ideas)
=== D20 Always Damage, Sometimes Effect
----
LET roll = [roll d20]
// Crit
IF roll == [Skill Level] THEN
damage = [weapon base damage] * 2 + roll
effect = [weapon's special effect, if available]
// Success
ELSE IF roll < [Skill Level] THEN
damage = [weapon base damage] + roll
effect = [weapon's special effect, if available]
// Minimal Success
ELSE
damage = [weapon base damage]
effect = none
----
=== D100 Always Damage, Sometimes Effect
When you attack, roll a d100 and use the relevant skill (Melee Attack or Ranged Attack) as the
Target Number.
*Hits* happen when you roll _lower_ than your Target Number. Hits deal damage
equal to your weapon's Base Damage plus the __digit sum__ of your roll (9 if
you rolled 18 and 15 if you rolled 69).
*Glancing Blows* happen when you roll _higher_ than your Target Number. In this
case you deal damage equal to your weapon's Base Damage plus the _lowest digit_
of your roll (2 if you rolled 72 or 0 if you rolled 90). Glancing blows usually
only deal damage and don't have any fancy side effects.
*Critical Hits* happen when your roll is exactly the same as your Target Number.
Critical Hits deal damage equal to your weapon's Base Damage plus the number
you rolled.
=== Dual Wielding
Dual weapons should be a Package-thing.
If using two weapons, you use your best weapon first.
a. If you failed your roll, (but didn't roll a 20???) you get to make an attack
with your off hand weapon.
b. You can spend HP to attack (once per round) with your off-hand weapon.
==== Sword & Board
If using sword'n'board, you make an attack with your main weapon first, if you roll at/under
your TN and under your damage cap you
* Make a shield bash???
* Regain some Hit Points??
=== Resistance
We should have a skill that allows us to resist AoE effects such as sleep or
fireball. Even though the caster has already rolled to cast the spell, targets
of AoE or certain effects should have a chance to avoid or reduce the effects
(unless the casting was so powerful that the target does not get a roll).
=== Exhaustion
Maybe exhaustion takes up time slots. If you become overburdened, you take
penalties.
=== Consumables
Torches::
2 per Item Slot. Lasts 69 real life minutes.
Rations::
3 per Item Slot. Lasts an entire day, and includes both food and water.
Money::
50 Coins per Item Slot.
Gems::
2 Gems per Item Slot. (Gems scratch each other if not packed correctly).
=== Monsters & Combat
Many monsters (the majority) should have special abilities that make combat
more interesting.
* Set the adventurer on fire that must be put out.
* Push the adventurer away, possibly knocking them on their ass.
* Spray itching powder that must be dealt with.
* Making an area of the battlefield uninhabitable with fire, webs, etc.
* Temporarily able to fly or jump stupid high, possibly spending their next
turn up in the air.
* Fart so badly that the adventurer MUST run away on their next turn.
* Hover.
* Cause adventurer to hover (or become weightless), making them unable to move,
and making them very queasy.
* Randomly interrupt combat, even when it's not their turn.
* Make opportunity attacks.
* Randomly heal an adventurer because they can't really control their magic.
=== Gooblin
Slimy goblin
== PLACES
=== Ballrocks Gates

958
main.adoc Executable file
View File

@@ -0,0 +1,958 @@
= The Rules Doom & Destruction & Stuff
// {{{ VARIABLES
// :stylesheet: style.css
:stylesheet: style.css
:doctype: article
:icons: font
:sectlinks:
:toc:
:toclevels: 1
:toc-placement!:
:experimental:
:stem:
:xrefstyle: full
:author: Kim Ravn Hansen
:email: moccalotto@gmail.com
:pdf-page-size: a5
:reproducible:
:table-stripes: even
:x: ×
:one: <<nat1,One>>
:twenty: <<nat20,Twenty>>
:DM: Destruction Manager
// VARIABLES }}}
== Creating Adventurers
Each player should begin play with TWO adventurers. Both adventurers should be
created by following these steps.
=== {counter:creation}. Skills
Adventurers have the following skills
|===
//--------------|---------------------------------------------------------
| Awareness | Attention, Alertness, Perception, Comprehension, Insight
| Grit | Toughness Strength, Willpower
| Knowledge | History, Geography, Lore
| Magic | Using wands, scrolls, and magical artifacts
| Melee Combat | Attacking nearby opponents
| Ranged Combat | Attacking opponents at range
| Skulduggery | Stealth, deception
//--------------|---------------------------------------------------------
|===
For each skill, roll 1d6, add 6, and assign that value to the skill. Each skill
should now have a score between 7 and 12.
TIP: The skill scores are likely to change before you're done creating the adventurer,
so write them on a piece of paper rather than on the adventurer's sheet for now.
[[ancestry,ancestry]]
=== {counter:creation}. Ancestry
All adventurers are human. However, the adventurers blessing may have triggered
some ancient dormant blood from distant nonhuman ancestors.
Ancestries have some effects now, but they also allow you to access certain
Perks when you level up later on.
[%header,cols="^1,^2,9"]
|===
| d8 | Ancestry | Description
//---|---------------|--------------------------------------
| 1 | Human | +1 to all skills.
| 2 | Dwarven | Raise your Melee Combat to 10
| 3 | Elven | Raise your Ranged Combat to 10
| 4 | Gigantic | Raise your Grit to 10
| 5 | Gnomish | Raise your Awareness to 10
| 6 | Primordial | Raise your Magic to 10
| 7 | Draconic | Raise your Knowledge to 10
| 8 | Demonic | Raise your Skulduggery to 10
//---|---------------|--------------------------------------
|===
NOTE: Raising a skill that is already 10 or higher has no effect.
[[foundation,foundation]]
=== {counter:creation}. Foundation
An adventurer's foundation is a set of gear the they start with and they are
proficient with. Your foundation may also affect your skill scores.
Roll on the table below to find your Foundation. Note that you may need to reroll.
[%header,cols="^1,^2s,3a,3a,5a",grid="rows"]
|===
| d20 | Foundation | Proficiencies | Gear | Effects
//------|-------------------|---------------+-----------+-------------------------------+
//START_SORT //HEADLINE:
//
//---------------------------------------------------------------------------------------
//HEADLINE: BRAWLER
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Brawler
|[unstyled]
* Light Armor
|[unstyled]
* Studded Leather
* Spiked Gauntlets
* 40 Silver Pieces
|[unstyled]
* 15 Hit Points
* 7 Item Slots
* Melee Combat raised to 10
* Knowledge limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: DRUID
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Druid
|[unstyled]
* Proficient with any type of armor, provided it's made exclusively of natural
materials like leather, hide, wood, wool, etc.
|[unstyled]
* Sickle
* Poisoner's Kit
* Healer's Kit
* 10 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
//
//---------------------------------------------------------------------------------------
//HEADLINE: Fencer
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Fencer
|[unstyled]
* Light Armor
* Advanced Weapons
|[unstyled]
* Leather
* Rapier
* Dagger
* 40 Silver Pieces
|[unstyled]
* 15 Hit Points
* 5 Item Slots
* The TWO WEAPONS perk.
* Melee Combat raised to 10
* Magic limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: GUARD
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Guard
|[unstyled]
* Medium Armor
* Advanced Weapons
|[unstyled]
* Halberd
* Bull's Eye Lantern
* Signal Whistle
* Map of Local Area
* 50 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Awareness raised to 10
* Melee Combat raised to 10
* Skulduggery limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: MAGICIAN
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Magician
|[unstyled]
* None
|[unstyled]
* Tier 2 Wand with random spell.
* Tier 1 Wand with random spell.
* 10 Silver Pieces
|[unstyled]
* 10 Hit Points
* 6 Item Slots
* Melee Combat limited to 10
* Ranged Combat limited to 5
* Magic raised to 10
* Grit limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: MEDIC
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Medic
|[unstyled]
* Light Armor
* Medium Armor
|[unstyled]
* Club
* Sling
* 3 Daggers
* Healer's Kit
* 40 Silver Pieces
|[unstyled]
* 10 Hit Points
* 6 Item Slots
//
//---------------------------------------------------------------------------------------
//HEADLINE: RECKLESS
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Reckless
|[unstyled]
* Advanced Weapons
|[unstyled]
* Great Axe
* 50 Silver Pieces
|[unstyled]
* 20 Hit Points
* 7 Item Slots
* Melee Combat raised to 10
* Awareness raised to 10
* Grit raised to 10
* Magic limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: ROVER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Rover
|[unstyled]
* Light Armor
* Advanced Weapons
|[unstyled]
* Leather Armor
* Short Sword
* Longbow
* Snare Maker's Kit
* 25 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Magic Reduced to 10
* Awareness raised to 10
* Ranged Combat raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SKIRMISHER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Skirmisher
|[unstyled]
* Light Armor
* Shields
* Advanced Weapons
|[unstyled]
* Spear
* Small Shield
* 50 Silver Pieces
|[unstyled]
* 15 Hit Points
* 6 Item Slots
* Melee Combat raised to 10
* Awareness raised to 10
* Skulduggery raised to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SNEAK
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Sneak
|[unstyled]
* Light Armor
|[unstyled]
* 3 daggers
* Small Crossbow
* Poisoner's Kit
* 30 Silver Pieces
|[unstyled]
* 10 Hit Points a
* 6 Item Slots b ==>
* Melee Combat raised to 10
* Awareness raised to 10
* Skulduggery raised to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPELLSWORD
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spellsword
|[unstyled]
* Advanced Weapons
|[unstyled]
* Tier 1 Wand with random spell.
* Longsword
* 30 Silver Pieces
|[unstyled]
* 12 Hit Points
* 5 Item Slots
* Melee Combat raised to 10
* Ranged Combat limited to 10
* Magic raised to 10
* Skulduggery limited to 10
* Grit raised to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPELUNKER
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spelunker
|[unstyled]
* None
|[unstyled]
* Spear
* Caltrops
* Bull's Eye Lantern
* Map Maker's Kit
* Chalk
* Caltrops
* 5 Silver Pieces
|[unstyled]
* 10 Hit Points
* 4 Item Slots
* Awareness raised to 10
* Melee Combat raised to 10
* Skulduggery raised to 10
* Magic limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: SPIT'N'POLISH
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Spit'n' Polish
|[unstyled]
* Heavy Armor
* Shield
* Advanced Weapons
|[unstyled]
* Half-Plate
* Large Shield
* Long Sword
* 10 Silver Pieces
|[unstyled]
* 10 Hit Points
* 2 Item Slots
* Melee Combat raised to 10
* Magic Reduced to 6
* Awareness Reduced to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: STILETTO
//---------------------------------------------------------------------------------------
| {counter:foundation}
| Stiletto
|[unstyled]
* Light Armor
|[unstyled]
* Padded Armor
* 3 Daggers
* Small Crossbow
* Poisoner's Kit
* 20 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Melee Combat raised to 10
* Ranged Combat raised to 10
* Awareness raised to 10
* Magic limited to 6
* Knowledge limited to 10
//
//---------------------------------------------------------------------------------------
//HEADLINE: Tinkerer
//---------------------------------------------------------------------------------------
| {counter:foundation}
|Tinkerer
|[unstyled]
* Light Armor
|[unstyled]
* Studded Leather
* Wrench (club)
* Tinkerer's Kit
* 30 Silver Pieces
|[unstyled]
* 10 Hit Points
* 5 Item Slots
* Awareness raised to 10
* Knowledge raised to 10
//END_SORT
//
//---------------------------------------------------------------------------------------
// REROLL
//---------------------------------------------------------------------------------------
| {counter:foundation}+
4+| Reroll, and continue rerolling results of {foundation} and higher.
|===
=== {counter:creation}. Gear
Roll two d8s; one for the left-hand table, and once for the right-hand table
[%unbreakable]
.Utility Gear
[%header,cols="^2,4,^2,4"]
|===
| First d8 | Item 1 | Second d8 |Item 2
//---------|-------------------------|-----------|---------------------------------
| 1 | 3 Torches | 1 | Grappling hook + 10 meter rope
| 2 | 3 Spikes | 2 | Storm Lantern
| 3 | Poisoner's Kit | 3 | Rope, 25 meters
| 4 | 100 Ball bearings | 4 | Pole, 3m, foldable
| 5 | Chalk | 5 | Shovel
| 6 | 3 Common Rations Pack | 6 | Tinkerer's Kit
| 7 | Bull's Eye Lantern | 7 | Oil Lamp + 3 units of oil
| 8 | 2d10 Silver Pieces | 8 | Map Maker's Kit
//---------|-------------------------|-----------|---------------------------------
|===
=== {counter:creation}. Background
Your background is what your adventurer used to do before they received the
Adventurer's Blessing.
If the DM makes you roll for something that is directly related to your
background, let the DM know - they might just give you an advantage.
Roll a d20 and a d6 and look at the table below to find your background.
[%header,cols="^1,5,^1,5"]
|===
//---|----------------------|----|----------------------------
| d20| d6 rolled 1, 3, or 5 | d20| d6 rolled 2, 4, or 6
| 1 | Apothecary | 1 | Hunter
| 2 | Baker | 2 | Hustler
| 3 | Banker | 3 | Laborer
| 4 | Bartender | 4 | Lazy spouse
| 5 | Butcher | 5 | Magicians apprentice
| 6 | Carter | 6 | Merchant
| 7 | Chandler | 7 | Monestarian
| 8 | Chef | 8 | Musician
| 9 | Clergy | 9 | Notary
| 12 | Cook | 12 | Royalty
| 13 | Courier | 13 | Sailor
| 14 | Courtier | 14 | Scribe
| 15 | Doctor | 15 | Smith
| 16 | Entertainer | 16 | Solder
| 17 | Farmer | 17 | Squire
| 18 | Fisherman | 18 | Street urchin
| 19 | Foreigner | 19 | Thief
| 20 | Gambler | 20 | Gold Smith
//---|----------------------|----|----------------------------
|===
=== {counter:creation}. Appearance
Roll d12 twice on the table below to find your body type. If you roll the same
value both times, the trait is extra pronounced.
.Body traits
[%header,cols="^1,11"]
|===
| d12 | Body traits
//------|-------------------
| 1 | Tall
| 2 | Short
| 3 | Muscular
| 4 | Stocky
| 5 | Lanky
| 6 | Graceful
| 7 | Slender
| 8 | Wiry
| 9 | Broad
| 10 | Round belly
| 11 | Awkward
| 12 | Athletic
//------|-------------------
|===
Roll d20 once for facial traits.
.Facial traits
[%header,cols="^1,11"]
|===
| d20 | Facial trait
//------|-------------------------------------------
| 1 | Sharp cheekbones and hollow eyes
| 2 | Crooked nose broken long ago
| 3 | Piercing eyes that seem to glow
| 4 | Full lips and a cleft chin
| 5 | Long, braided beard or mustache
| 6 | High forehead with deep worry lines
| 7 | One eye covered by a patch
| 8 | Elaborate facial tattoos or markings
| 9 | Eyebrows like wings—thick and dramatic
| 10 | Jawline strong enough to cut stone
| 11 | Burn scar across one cheek
| 12 | Missing ear or visible notch in it
| 13 | Eyes of two different colors (pupils are still bronze-coloured)
| 14 | Prominent dimples when smiling
| 15 | Nose like a hawks beak
| 16 | Gnarled, bushy eyebrows
| 17 | Lips always curled in a smirk
| 18 | Eyes that never blink (or seem not to)
| 19 | Crystal embedded in the forehead
| 20 | Completely smooth, expressionless face
//------|-------------------------------------------
|===
.Hair traits
[%header,cols="^1,11"]
|===
| d10 | Hair Trait
//------|------------------------------------------------
| 1 | Long and silky, flows like water
| 2 | Short and spiky like a hedgehog
| 3 | Thick dreadlocks tied with beads
| 4 | Curly and untamed, a wild mane
| 5 | Slicked back with oils or grease
| 6 | Braided with ribbons or charms
| 7 | Patchy or thinning with bald spots
| 8 | Voluminous afro that defies helmets
| 9 | Snow-white despite a youthful face
| 10 | Hair constantly shifts color like a mood ring
//------|------------------------------------------------
|===
=== {counter:creation}. Personality
Your personality consists of a vice, a virtue, and a quirk.
At their discretion,the GM can award XP when you play out your personality
traits — especially your vice, and only if you don't overdo it.
==== Vice
Roll once to find your vice.
[%header,cols="^1,11"]
|===
| d12 | Vice
//------|--------------------------------------------
| 1 | Loves owning and interacting with treasure
| 2 | Addicted to Snarf - magical angel dust
| 3 | Gets a kick out of telling outrageous lies
| 4 | Solves problems with fists
| 5 | Obsessive collector of bizarre items
| 6 | Always flirting, even at the worst times
| 7 | Gambler who cant resist a wager
| 8 | Glutton for food, drink, or pleasure
| 9 | Reckless thrill-seeker, craves danger
| 10 | Talks to self constantly
| 11 | Talks to invisible friend
| 11 | Addicted to forbidden knowledge or magic
| 12 | Obsessed with cleanliness
//------|--------------------------------------------
|===
==== Virtue
Roll once to find your virtue. The DM might give you extra
XP if your virtues come into play.
[%header,cols="^1,11"]
|===
| d20 | Virtue
//------|--------------------------------------------
| 1 | Loyal to a fault, never breaks a promise
| 2 | Courageous in the face of danger
| 3 | Generous with time, wealth, and effort
| 4 | Honest, even when it hurts
| 5 | Protective of the weak and voiceless
| 6 | Wise beyond their years
| 7 | Forgives easily, even enemies
| 8 | Hardworking and persistent
| 9 | Pious or deeply spiritual
| 10 | Self-sacrificing for the good of others
| 11 | Finds beauty in all things
| 12 | Curious and open-minded
| 13 | Kind-hearted, even to the undeserving
| 14 | Inspires courage in others
| 15 | Always seeks the truth
| 16 | Disciplined and self-controlled
| 17 | Brave enough to admit weakness
| 18 | Empathic, feels others' pain
| 19 | Just and fair, upholds law or balance
| 20 | Keeps hope alive, even in darkness
//------|--------------------------------------------
|===
==== Quirk
Roll once to find your quirk. The DM might give you extra XP if your quirks
come into play.
[%header,cols="^1,11"]
|===
| d20 | Quirk
//----|----------------------------------------------
| 1 | Likes to rhyme
| 2 | Believes animals understand them
| 3 | Eats only one type of food
| 4 | Names all their weapons and gear
| 5 | Laughs at inappropriate moments
| 6 | Deep dislike of mirrors
| 7 | Collects bones, teeth, or pebbles
| 8 | Speaks in third person
| 9 | Talks to their pet stone
| 10 | Always wears gloves
| 11 | Whistles when nervous
| 12 | Believes in bizarre superstitions
| 13 | Refuses to walk through doorways first
| 14 | Smells everything before touching it
| 15 | Never says their real name
| 16 | Only speaks in third person
| 17 | Claims to have lived many past lives
| 18 | Counts out their coins slowly and meticulously
| 19 | Hates silence, starts singing or humming
| 20 | Gassy, and proud of it
//----|----------------------------------------------
|===
=== {counter:creation}. Fill Out The Adventurer's Sheet
Now you fill in all the details you've rolled. All you need to do is to choose
a gender and a name.
Your adventurer has a number of Item Slots, determined by their Foundation. The
sheet provides space for 10 slots, but you may have fewer. Shade, hatch, or
cross out any unusable Item Slots. == Perks
== Items
=== Weapons
//---------------
// SIMPLE WEAPONS
//---------------
==== Simple Weapons
[%unbreakable]
--
All adventurers can use simple weapons, regardless of <<foundation>>,
<<perks>>, or <<class>>.
[%header,cols="^2,^3,^2,^2,^2,6"]
|===
| Range | Weapon | Hands | IS | Damage | Special Effect
//----------|-------------------|-------|----|--------|----------------
| Any | Dagger | 1 | ⅓ | 4 |
| Any | Spear | 1 | 2 | 5 |
| Melee | Club | 1 | 1 | 4 |
| Melee | Flail | 1 | 1 | 6 |
| Melee | Handaxe | 1 | 1 | 6 |
| Melee | Longspear | 2 | 3 | 9 |
| Melee | Mace | 1 | 2 | 7 |
| Melee | Morning star | 1 | 2 | 8 |
| Melee | Quarterstaff | 2 | 2 | 6 |
| Melee | Sickle | 1 | 1 | 4 |
| Melee | Warhammer | 1 | 2 | 6 |
| Ranged | Sling | 2 | 1 | 4 |
| Ranged | Small Crossbow | 2 | 2 | 8 |
//----------|-------------------|-------|----|--------|----------------
|===
--
==== Advanced Weapons
[%unbreakable]
--
Any adventurer who has a <<foundation>>, <<class>>, or <<perk>> that allows
them to use advanced weapons can use the weapons on this list. Adventurers who
haven't got such an ability has <<disadvantage>> when attacking with advanced
weapons, and can never use their special abilities.
[%header,cols="^2,^3,^2,^2,6"]
|===
| Range | Weapon | Hands | Damage | Special Effect
//---------|-------------------|-------|-------------------------
| Any | Javelin | 1 | | Better than spear, somehow
| Melee | Battleaxe | 1 | 8 | Mini cleave?
| Melee | Claymore | 2 | 8 | Something cool that the Zweihänder doesn't have
| Melee | Falchion | 2 | |
| Melee | Greataxe | 2 | 10 | Cleave
| Melee | Halberd | 1 | 11 | Pull
| Melee | Longsword | 1 | 8 |
| Melee | Rapier | 1 | 6 | Fast: attack again?
| Melee | Scimitar | 1 | 7 |
| Melee | Short Sword | 1 | 6 |
| Melee | Stiletto | 1 | 4 | Fast: attack again?
| Melee | Zweihänder | 1 | 10 | Push
| Ranged | Large Crossbow | 1 | 10 |
| Ranged | Longbow | 1 | |
| Ranged | Shortbow | 1 | |
//---------|-------------------|-------|-------------------------
|===
--
==== Weird Weapons
[%unbreakable]
--
In order to be able to use one of the weird weapons on this list, an adventurer
must have a <<foundation>>, <<class>>, or <<perk>> that allows them to use that
specific weapon. For instance, an adventurer who has an ability to use the Kosh
can use koshes, but not any of the other weird weapons.
[%header,cols="^2,^3,^2,^2,6"]
|===
| Range | Weapon | Hands | Damage | Special Effect
//---------|-------------------|--------|--------|----------------
| Melee | Bastard Sword | 1 | 10 | None - high base damage
| Ranged | Blowgun | 1 | |
| Ranged | Bolas | 1 | 8 |
| Melee | Kosh | 1 | 8 | Knock-out
//---------|-------------------|--------|--------|----------------
|===
--
=== Armors
.Light Armor
[%header,cols="2,^1,^1,2"]
|===
//----------------------|-----|-------|---------------------------------
| Armor | HP | Sneak | Notes
//----------------------|-----|-------|---------------------------------
| Padded Armor | 1 | Yes | Cheap, bulky cloth layers
| Leather Armor | 2 | No | Flexible leather
| Studded Leather | 3 | No | Reinforced with metal studs
| Hide Shirt | 2 | Yes | Made from thick animal hide
| Gambeson | 2 | Yes | Quilted cloth and fibres
| Traveler's Coat | 1 | Yes | Light and practical
//----------------------|-----|-------|---------------------------------
|===
.Medium Armor
[%header,cols="2,^1,^1,2"]
|===
//----------------------|-----|-------|---------------------------------
| Armor | HP | Sneak | Notes
//----------------------|-----|-------|---------------------------------
| Scale Mail | 4 | Yes | Metal scales, noisy
| Chain Shirt | 4 | Yes | Metal rings, worn under clothes
| Brigandine | 5 | Yes | Plates riveted inside a jacket
| Lamellar Armor | 5 | Yes | Laced metal or leather plates
| Ring Mail | 4 | Yes | Rings over padded base
| Hardened Leather | 3 | Yes | Boiled and shaped for stiffness
//----------------------|-----|-------|---------------------------------
|===
.Heavy Armor
[%header,cols="2,^1,^1,2"]
|===
//----------------------|-----|-------|---------------------------------
| Armor | HP | Sneak | Notes
//----------------------|-----|-------|---------------------------------
| Chainmail | 6 | No | Full-body chain coverage
| Splint Mail | 7 | No | Metal strips on a backing
| Banded Mail | 7 | No | Horizontal bands over padding
| Half-Plate | 8 | No | Partial plate, better mobility
| Full Plate | 9 | No | Maximum protection, very heavy
| Coat of Plates | 8 | No | Metal plates sewn into a coat
//----------------------|-----|-------|---------------------------------
|===
== Perks
This chapter is not for
* Racial.
** There should be a racial perk tree that can be unlocked. Only adventurers
can access the blood of the ancients (elf, dwarf, etc.)
** No races should get dark vision unless they are at MAX level.
** Dwarves should get an extra item slot (possibly more if you take this perk
multiple times).
** Dwarves are good in dungeons (know cardinal directions, head-map, ability to
"smell" metals and ores).
** Elves are good on the surface (navigating by stars, being difficult to
surprise, requiring less sleep).
** Gnomes???
** Primordials/primals (ancient humans)
** Prim((anus))
* Monstrous Gourmand.
* Unlock medium (and later on heavy) armor.
* Unlock Special Effects for common melee weapons.
* Exotic Weapon Perk Tree
** Initially you get access to a "simple" exotic weapon.
** Later on you can use certain two-handed weapons in one hand.
* Multi-attack if you roll higher than X. Possibly play into what happens when
attack skill is higher than MAX TN.
== Gear
* Weapons
** Melee Weapons
** Ranged Weapons
** Special Weapons??
*** Bolas
*** Kosh
*** Spiked Chain
*** Meteor Hammer
*** Bastard Sword (can be used one handed if adventurer has the right perk)
* Armors
* Misc
** Food
** Dungeon Spelunking Gear
** Wilderness Survival Gear
** Transport, Wagons, Beasts
* Valuables
** Coins
** Gems
** Misc (art, etc.)
== Campaign
* Map
** The world should be weird and funny, but not ridiculous.
** ShipWorld: the world, when seen from above, looks like the outline of a
ship, that's seen from above. But instead of being made of wooden planks,
there is real terrain and flora. But there should/could be elevation changes
where the different decks (such as the Poop Deck) are.
*** What's around the ship?
*** What happens if you dig?
*** Can dungeons reach into the inner hull/decks of the ship?
** DeadWorld: Maybe the world is the surface of some gigantic dead creature.
*** What's around the creature?
*** What happens if you dig?
*** Do dungeons reach into the inner parts of the corpse? Like the brain?
** FloorWorld: The world is the floor of a mage's study. She accidentally
created this world, but destroyed everything else.
* Cities and Towns
** Capita (the Capital)
* Prominent People
** Master Baator
** Richard Tator (dictator)
** Laika Bors
* History
== Doom Manager's Rules
* Advancement
** XP for killing Monsters.
** XP for uncovering Secret Knowledge and Locations.
** XP for spending money.
** XP for spending carousing.
* Adventuring
** Splitting the party: It is a viable strategy to split the party, and send in
a sacrificial team in advance - but the GM can and should require that each
present player send in one of their adventurers so that all players are
engaged at the same time.
== Spells
* A note on which types of magical artifacts can carry spells (wands, books,
and reusable scrolls).
* Alphabetized list of spells
* One spell = One page (a5) - but very special spells (like Wish) may take up
two pages, but keep in mind that the two pages must still be arranged
prettily.
== Magical Items
* Magical Weapons
* Magical Armors
* Special Wands/Scrolls/Books
* Wondrous Items
** Naïvitea (tea that makes you blonde)
== Monsters
* One page = one (typical) baddy.
* Baddies should have special TWISTS. When spawning baddies, the DM should roll
random TWISTS for each baddy or group of baddies.
* Monsters
** Mandag: a really bad male hag
** Halvbitter: more badass than Djinn
** Gooblin
** Cowlbear (a bear in a cowl?)

187
monsters.adoc Executable file
View File

@@ -0,0 +1,187 @@
= Monster's Guide To Doom & Destruction & Stuff
== WEIRDS
Mondays:: A type of monster invented by Fred after he'd had a really bad day.
He called it, a Monday, and it is almost impossible to describe.
* It is bestowed with an extreme, but unknowable, intelligence.
* It is extremely large, but is able to be wholly or partially ephemeral to
suit their needs.
* It can take the shape of forests, castles, large bodies of water, airships,
or similar.
* It can coalesce into a smaller, more substantial monster, but it rarely does.
* Its heart is located somewhere inside it, but it can be hard to find, and it
never looks like a heart.
* It eats happiness and shits out bad health.
== OILS
Garg Oil::
* Oily slime monster with wings.
* Can fly.
* Related to Slime.
* Drown attack.
* Oil splash attack.
* Resistant to piercing weapons.
Gargle Oil::
* Thinner version of Garg Oil.
* Very slippery.
* Flammable.
* Resistant to piercing weapons.
* Resistant to slashing weapons.
* Can turn into slime puddle.
* Spray attack.
* Organic Compound Spray Attack.
Targ Oil::
* Thicker and sticker version of Garg Oil.
* Stronger.
* Sticky attacks.
* Cannot fly, but wings are considered armor pieces.
Farg Oil::
* Gargle Oil with powerful ranged attacks and spells.
Gelatinous Pube::
* Disgustingly smelly seaweed thing
Slime::
A type of Oil, a slime is a semi-intelligent monster that can be made out of
anything from rainwater to lava, these monsters are often highly caustic, and
can constrict their opponents.
When a slime is born, it is usually a few cubic centimeters in size, but as it
consumes more and more material, it grows larger. Many slimes like to feed on
living organic matter (people, plants, animals, etc.).
Pooh-ma::
A vicious wolf-like oily monster born in the sewers and waste pits of cities,
military camps, and similar concentrations of feces.
* Basically a dire-wolf made of feces.
* Is technically a slime, but can also be classified as an undead, an orc,
or even a golem, depending on its composition.
* Strong.
* Spreads diseases that can affect adventurers.
* Stink breath weapon.
* Claws.
* Pooh-fling (throws own body parts at opponent, high damage, but loses own HP).
* Resistance to piercing weapons (roll damage with disadvantage).
* Resistance to fire (roll damage with disadvantage).
* Usually antisocial, but can hunt in packs with its brothers.
* It does not like the light (all checks are difficult when in bright light).
B'ooze::
* An ooze made of booze.
== ORCS
[quote,Oralix LeDique]
Orcs are to trees what undeads to the Enlightened.
Green and brown skinned creatures that are created when trees and large plants
die from unnatural causes.
* Orcs are a category containing orcs, trolls, cyclops
* Not gnolls, goblins or hobs.
* Created completely from plant matter => green and brown skins.
* They exude a kind of blight that slowly degenerates vegetation, which makes
the orcs stronger.
* Boss Orcs can reverse their blight, killing off a few orcs and rapidly
increasing plant growth.
* Continue to grow as long as there is nourishment (plant matter).
* Sometimes destroy forests to create more orcs.
* Only become undead if some outside force (such as an evil mage) turns them.
* Tough, extreme pain tolerance, and high morale.
* Individual orcs have animalistic intelligence, but sometimes a Great Leader
that can control or direct the entire army.
* Die if they are kept away from an open sky for too long; they cannot be
imprisoned in a donjon or inside any kind of building - they'll rot.
* Breeder orcs are a kind of "queen" orc that can charm enlightened males into
mating with them, creating hybrid orc spawn.
Hybrid Orcs::
* Like nephilim
* Intelligent
* Independent
* Very Powerful
== UNDEADS
* Undead creatures rise automatically. Especially if they have died from
traumatic events such as war, assault, and magical accidents.
* Once slain, some undeads can rise again. Usually as less powerful beings.
* Undeads almost always have worse stats than when they were alive.
* Generally immune to fear.
* Generally slower.
* Generally able to see/sense in darkness.
* Powerful undeads, such as liches, generally do not rise spontaneously.
Mummy Troll::
A troll (who is technically an Orc) that has been magically preserved, wrapped
in magical bandages, and turned undead.
Undeads of the Sea::
Sailors and enlightened sea creatures can become undead.
Sailors tend to walk towards shore and become a menace on the beaches and
harbours of the world. Sea creatures tend to patrol their old territories and
make a mess there.
Crack-Ann:: Female undead Kraken. Rotten and spiteful. Poisonous and stinky
bodily fluids ad nauseam.
Old George::
Male version of Crack-Ann. He's an elderly dude, who is slow and not as young
as he was. Sailors have learned to navigate around him, and generally avoid
him.
== Bug Bears
Combine a bug and a bear.
* Many varieties
* Some are mostly bug, some are mostly bear.
* Some have wings, some have mandibles, some have cute bear ears on exoskeletal
head.
== GOBLIN
* Evil type of gnome
* A bit like Rask Gar.
* Dark vision.
* Not very fond of gnomes.
* Cowards.
* Power cycles:
** Males are intelligent, cunning, and fierce.
** Females are physically very strong and tough.
** Goblins are less powerful during 12 "daytime" hours.
** ?? On odd years males get a boost to their mental stats, and
on even years females get a boost to their physical stats.
This is universal. It means that, no matter where you are,
you either have clever males or strong females, it varies from year to year.
* Specializes in:
** Extremely unsafe mechanical engineering.
** Narcotics and similar poisons.
** Unstable blast powder.
** Traps that are unfair, unstable, and unnecessarily gruesome.
== AUTOMATA
Golems
== MIMIC
* House Mimic: A mimic the size and shape of a house.
* Fortress Mimic: A mimic the size and shape of a fortress, and with all
of the armaments too.
== MISC
Haggis (Hag, slime ??)::
Disgusting smelly blob of vile spellcasting.
Cognac::
Much more awesome than a gin (djinn)

14
readme.adoc Executable file
View File

@@ -0,0 +1,14 @@
= Yet Another Reduced Instruction Set for Doom & Destruction & Stuff.
Kim Ravn Hansen <moccalotto@gmail.com>
:stylesheet: style.css
:sectlinks:
:toc:
:toclevels: 1
:toc-placement!:
:experimental:
:stem:
* xref:adventurer#[Adventurerss Guide to Doom & Destruction & Stuff].
* xref:hero#[Heros Guide to Doom & Destruction & Stuff].
* xref:elite#[Elites Guide to Doom & Destruction & Stuff].

37
sheet.adoc Executable file
View File

@@ -0,0 +1,37 @@
[%header,cols="6, 3, 3"]
|===
| Skill | Max Score | Current Score
//----------------------|-----------|------------------------------------------
| Melee Attack | |
| Ranged Attack | |
| Magic | |
| Skulduggery | |
| Grit | |
| Knowledge | |
| Awareness | |
//----------------------|-----------|------------------------------------------
|===
[%header,cols="6, 3, 3"]
|===
| Weapon | Damage | Effects
//----------------------|-----------|------------------------------------------
| Unarmed Combat | 4 | None
| Short Sword | 6 | Light (if you roll lower than X, you get an extra attack)
| | |
| | |
//----------------------|-----------|------------------------------------------
|===
[%header,cols="6, 3, 3"]
|===
| Wand | Quality | Spent
//----------------------|-----------|------------------------------------------
| | |
| | |
| | |
| | |
//----------------------|-----------|------------------------------------------
|===

1687
style.css Executable file

File diff suppressed because it is too large Load Diff

249
tooling/mathD100.lua Executable file
View File

@@ -0,0 +1,249 @@
--
-- {{{ Digit Functions
--- Get sorted base-10 digits of a number
---@param n integer
---@return integer[]
local function get_sorted_digits(n)
local digits = {}
for d in tostring(math.abs(n)):gmatch("%d") do
table.insert(digits, tonumber(d))
end
table.sort(digits)
return digits
end
-- }}}
--{{{ print_r
local function print_r(t)
local print_r_cache = {}
local function sub_print_r(t, indent)
if (print_r_cache[tostring(t)]) then
print(indent .. "*" .. tostring(t))
else
print_r_cache[tostring(t)] = true
if (type(t) == "table") then
local tLen = #t
for i = 1, tLen do
local val = t[i]
if (type(val) == "table") then
print(indent .. "#[" .. i .. "] => " .. tostring(t) .. " {")
sub_print_r(val, indent .. string.rep(" ", string.len(i) + 8))
print(indent .. string.rep(" ", string.len(i) + 6) .. "}")
elseif (type(val) == "string") then
print(indent .. "#[" .. i .. '] => "' .. val .. '"')
else
print(indent .. "#[" .. i .. "] => " .. tostring(val))
end
end
for pos, val in pairs(t) do
if type(pos) ~= "number" or math.floor(pos) ~= pos or (pos < 1 or pos > tLen) then
if (type(val) == "table") then
print(indent .. "[" .. pos .. "] => " .. tostring(t) .. " {")
sub_print_r(val, indent .. string.rep(" ", string.len(pos) + 8))
print(indent .. string.rep(" ", string.len(pos) + 6) .. "}")
elseif (type(val) == "string") then
print(indent .. "[" .. pos .. '] => "' .. val .. '"')
else
print(indent .. "[" .. pos .. "] => " .. tostring(val))
end
end
end
else
print(indent .. tostring(t))
end
end
end
if (type(t) == "table") then
print(tostring(t) .. " {")
sub_print_r(t, " ")
print("}")
else
sub_print_r(t, " ")
end
print()
end
--}}}
--{{{ table_count
function table_count(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
--}}}
--{{{ range(low, high, n)
---Create a table with integers in a given range
---@param low integer Lowest number
---@param high integer Highest number
---@param n integer Increment - the array will contain every nth number between [low..high]
---@return table
local function range(low, high, n)
local t = {}
for i = low, high, n do
table.insert(t, i)
end
return t
end
---}}}
--{{{ sortMapByValueDesc(m)
---Sort the table m by value.
---@param m table
---@return table
local function sortMapByValueDesc(m)
local totalCount = 0
local tmp = {}
-- create a temporary table that is easier to sort
for damage, occurrences in pairs(m) do
local entry = {
damage = damage,
count = occurrences,
}
totalCount = totalCount + occurrences
table.insert(tmp, entry)
end
table.sort(tmp, function(a, b)
return a.count > b.count
end)
return tmp
--
-- local result = {}
-- for _, v in pairs(tmp) do
-- result[v.damage] = v.count
-- end
--
--
-- if table_count(result) ~= table_count(m) then
-- error("I couldn't sort!!")
-- end
--
-- return result
end
--}}}
--{{{table_sum(t)
---numeric sum of table values
---@param t integer[]
---@return integer
local function table_sum(t)
local result = 0
for _, v in pairs(t) do
result = result + v
end
return result
end
--}}}
--{{{mostCommonDamageValues(instances, ratio)
--- Calculate the most likely values
---@param instances table A map of [damage score] => [occurrences]
---@param ratio number Include most common damage until the sum of the probabilities of the damage scores are at least this number.
---@return table
local function mostCommonDamageValues(instances, ratio)
if ratio == nil then
ratio = 0.5
end
local sortedInstances = sortMapByValueDesc(instances)
local totalOccurrences = table_sum(instances)
local result = {}
local occurrenceAccumulator = 0
for _, instance in pairs(sortedInstances) do
occurrenceAccumulator = occurrenceAccumulator + instance.count
table.insert(result, instance.damage)
if occurrenceAccumulator / totalOccurrences >= ratio then
return result
end
end
return result
end
--}}}
--{{{calculateDamageD100(skill, base_damage)
---Calculate the average of the d100 attack method
---@param skill integer The skill level of the attacker (range of 1 to 100, but will be capped to 20)
---@param base_damage integer The base damage of the attacker's weapon.
---@return number
---@return table mostRolled the damage values that are most likely to be rolled
local function calculateDamageD100(skill, base_damage)
local sum = 0
local n = 0
local tn = math.min(skill, 80)
local damages = {}
for rolled = 1, 100, 1 do
local digits = get_sorted_digits(rolled)
local damage = 0
if rolled > tn then
-- glancing blow: damage equal to weapon's base damage.
damage = base_damage
end
if rolled < tn then
-- normal hit: damage equal digit sum of what is rolled plus base damage.
damage = table_sum(digits) + base_damage
end
if rolled == tn then
-- Critical Hit: damage equal to what you rolled.
damage = rolled
end
local key = tostring(damage)
n = n + 1
sum = sum + damage
if not damages[key] then
damages[key] = 1
else
damages[key] = damages[key] + 1
end
end
return sum / n, mostCommonDamageValues(damages, 0.5)
end
--}}}
local skill_min = 30
local skill_max = 80
local skill_inc = 5
local skills_table = range(skill_min, skill_max, skill_inc)
local damage_min = 0
local damage_max = 10
local damage_inc = 3
local damages_table = range(damage_min, damage_max, damage_inc)
io.write("skill\\damage", ";")
for i, dmg in pairs(damages_table) do
io.write(string.format("%d (avg);%d (typical)", dmg, dmg))
if i < #damages_table then
io.write(";")
end
end
print("")
for _, skill in pairs(skills_table) do
io.write(skill, ";")
local tmp = {}
for key, damage in ipairs(damages_table) do
local avg, dmg = calculateDamageD100(skill, damage)
tmp[key] = string.format("%.2f;%s", avg, table.concat(dmg, ", "))
end
print(table.concat(tmp, ";"))
end

217
tooling/mathD20.lua Executable file
View File

@@ -0,0 +1,217 @@
--
--{{{ print_r(t)
local function print_r(t)
local print_r_cache = {}
local function sub_print_r(t, indent)
if (print_r_cache[tostring(t)]) then
print(indent .. "*" .. tostring(t))
else
print_r_cache[tostring(t)] = true
if (type(t) == "table") then
local tLen = #t
for i = 1, tLen do
local val = t[i]
if (type(val) == "table") then
print(indent .. "#[" .. i .. "] => " .. tostring(t) .. " {")
sub_print_r(val, indent .. string.rep(" ", string.len(i) + 8))
print(indent .. string.rep(" ", string.len(i) + 6) .. "}")
elseif (type(val) == "string") then
print(indent .. "#[" .. i .. '] => "' .. val .. '"')
else
print(indent .. "#[" .. i .. "] => " .. tostring(val))
end
end
for pos, val in pairs(t) do
if type(pos) ~= "number" or math.floor(pos) ~= pos or (pos < 1 or pos > tLen) then
if (type(val) == "table") then
print(indent .. "[" .. pos .. "] => " .. tostring(t) .. " {")
sub_print_r(val, indent .. string.rep(" ", string.len(pos) + 8))
print(indent .. string.rep(" ", string.len(pos) + 6) .. "}")
elseif (type(val) == "string") then
print(indent .. "[" .. pos .. '] => "' .. val .. '"')
else
print(indent .. "[" .. pos .. "] => " .. tostring(val))
end
end
end
else
print(indent .. tostring(t))
end
end
end
if (type(t) == "table") then
print(tostring(t) .. " {")
sub_print_r(t, " ")
print("}")
else
sub_print_r(t, " ")
end
print()
end
--}}}
--{{{ table_count(t)
function table_count(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
--}}}
--{{{ range(low, high, n)
---Create a table with integers in a given range
---@param low integer Lowest number
---@param high integer Highest number
---@param n integer Increment - the array will contain every nth number between [low..high]
---@return table
local function range(low, high, n)
local t = {}
for i = low, high, n do
table.insert(t, i)
end
return t
end
---}}}
-- {{{ sortMapByValueDesc(m)
---Sort the table m by value.
---@param m table
---@return table
local function sortMapByValueDesc(m)
local tmp = {}
-- create a temporary table that is easier to sort
for damage, occurrences in pairs(m) do
local entry = {
damage = damage,
count = occurrences,
}
table.insert(tmp, entry)
end
table.sort(tmp, function(a, b)
return a.count > b.count
end)
return tmp
end
--}}}
-- {{{ arraySum(t)
local function table_sum(t)
local accumulator = 0
for _, v in pairs(t) do
accumulator = accumulator + v
end
return accumulator
end
---}}}
--{{{ mostCommonDamageValues(instances, ratio)
--- Calculate the most likely values
---@param instances table A map of [damage score] => [occurrences]
---@param ratio number Include most common damage until the sum of the probabilities of the damage scores are at least this number.
---@return table
local function mostCommonDamageValues(instances, ratio)
if ratio == nil then
ratio = 0.25
end
local sortedInstances = sortMapByValueDesc(instances)
local totalOccurrences = table_sum(instances)
local result = {}
local occurrenceAccumulator = 0
for _, instance in pairs(sortedInstances) do
occurrenceAccumulator = occurrenceAccumulator + instance.count
table.insert(result, instance.damage)
if occurrenceAccumulator / totalOccurrences > ratio then
return result
end
end
return result
end
--}}}
-- {{{ calculateDamageD20(skill, base_damage)
---@param skill integer
---@param base_damage integer
---@return number average The average damage
---@return table typical The damage numbers that, together, are likely to occur more than 50% of the time.
local function calculateDamageD20(skill, base_damage)
local sum = 0
local n = 0
local tn = math.min(skill, 15)
local outcomes = {}
for rolled = 1, 20, 1 do
local damage = 0
if rolled > tn then
-- glancing blow
damage = base_damage
end
if rolled == tn then
-- crit
damage = 2 * (skill + base_damage)
end
if rolled < tn then
-- hit
damage = rolled + base_damage
end
local key = tostring(damage)
if outcomes[key] == nil then
outcomes[key] = 1
else
outcomes[key] = outcomes[key] + 1
end
sum = sum + damage
n = n + 1
end
return sum / n, mostCommonDamageValues(outcomes, 0.5)
end
-- }}}
local skill_min = 5
local skill_max = 15
local skill_inc = 1
local skills_table = range(skill_min, skill_max, skill_inc)
local damage_min = 0
local damage_max = 10
local damage_inc = 3
local damages_table = range(damage_min, damage_max, damage_inc)
io.write("skill\\damage", ";")
for i, dmg in pairs(damages_table) do
io.write(string.format("%d (avg);%d (typical)", dmg, dmg))
if i < #damages_table then
io.write(";")
end
end
print("")
for _, skill in pairs(skills_table) do
io.write(skill, ";")
local tmp = {}
for key, damage in ipairs(damages_table) do
local avg, dmg = calculateDamageD20(skill, damage)
tmp[key] = string.format("%.2f;%s", avg, table.concat(dmg, ", "))
end
print(table.concat(tmp, ";"))
end

68
tooling/process.lua Executable file
View File

@@ -0,0 +1,68 @@
-- Sort selected areas of a text file
--
-- Each area has a number of sections,
-- and each section has a headline that
-- is used as a key.
--
-- The program simply treats each section as a string, and treats each area as a
-- collection of strings. The strings are sorted such that the sections in
-- the area will appear in order.
--
-- For now, only asciidoc (and markdown) headlines are supported, but
-- description lists are on the way
--
-- TODO:
-- Variables and substitutions with evaluation via dostring
-- Syntax for settings vars could be
-- {{? mufassa = "tjams" }}
-- {{? mufassa tjams }}
--
-- Syntax for inserting vars could be
-- {{:: string.upper(mufassa) }}
-- my little pony is {{: mufassa .. " næsehorn "}}
--
-- Can assist in streamlining data across the three guides.
-- Can ease links.
--
-- Maybe a quick var insert:
-- @@@mufassa (inserts the contents of mufassa variable)
--
local filename = arg[1]
-- Check that a filename was given
if arg[1] == nil then
print(string.format("usage: %s [filename]", arg[0]))
os.exit(0)
end
-- Check that file exists
local f = io.open(filename, "r+")
if not f then
print(string.format("file '%s' does not exist", filename))
os.exit(1)
end
local sorter = require("sorter")
local sorted = sorter(f:lines())
if arg[2] == "--overwrite" then
--
-- Check if there were any changes to the file.
f:seek("set")
if sorted == f:read("a*") then
print("No sorting needed. Closing file")
f:close()
os.exit(0)
end
f:seek("set")
f:write(sorted)
f:flush()
f:close()
os.exit(0)
end
f:close()
print(sorted)

190
tooling/sorter.lua Executable file
View File

@@ -0,0 +1,190 @@
-- This program scans a text for REGIONS to sort.
--
-- Each REGION contains the following:
-- A "START_SORT:" string command that also tells the sorter which types of HEADLINES the REGION contains.
-- (optionally) a number of PREFACE lines.
-- A number of SECTIONS to sort
-- An "END_SORT" command
--
-- Each SECTION contains the following
-- A HEADLINE
-- A number of lines of body text.
--
-- A HEADLINE can (currently) be one of:
-- - An asciidoc headline: a line that always begins with a number of '=' characters, followed by at least one normal text character.
-- These headlines are convenient because it allows us to easily alphabetize headlines in certain chapters
-- (for instance in chapters where spells, items, or abilities each have their own headline).
-- - A hidden headline. A text they always begins "//HEADLINE:", followed by a number of normal text characters.
-- These hidden headlines are useful when we want to alphabetize tables, lists, and other sections that do not contain
-- explicit headlines.
--
--
-- Each REGION has a number of SECTIONS, and each SECTION
-- has a HEADLINE. HEADLINES can be actual asciidoc headlines (strings beginning with a number of "=" characters)
-- or they can be pseudo-headlines that exist as comments inside the asciidoc file.
--
--
-- {{{ Some variables to help us
local output = "" -- Output buffer
local STATE_SCANNING = 0 -- State machine: scanning for START_SORT commands
local MODE_SORTING = 1 -- State machine: sorting, and looking for END_SORT commands.
local state = STATE_SCANNING -- State machine: current mode
local headlinePattern = "" -- If a line matches this pattern, is a section headline (a sort key)
local sections = {} -- The sections we're currently sorting.
local preface = "" -- contains the text in a chunk that comes before the first section headline
--}}}
--{{{ _start_sort(line)
---Check if a line starts with START_SORT and then a key to look for.
---@param line string The line we're checking
---
---@return boolean success Was the line correctly formatted?
---@return boolean start_sort Did this line contain a correct START_SORT command?
---@return string pattern The regex pattern to scan for to find the headline/key that each section starts with.
---
local function _is_start_sort_command(line)
local match = string.match(line, "^//%s*START_SORT%s*(%S*)%s*$")
if not match then
return true, false, ""
end
--
-- ASCIIDOC HEADLINE
--
-- These types of headlines start with a number of "=" characters.
-- They sort REGIONS of text where each SECTION begins with an asciidoc headline
if string.sub(match, 1, 1) == "=" then
-- We are sorting by section names
-- The type of section we're sorting (i.e. its depth) is denoted by the given number '=' characters
-- Every time we encounter a section with the corresponding number of equal signs, we consider that a sorting key.
return true, true, "^" .. match .. "%s+"
end
--
-- HIDDEN HEADLINE
--
-- These headlines begin with "//HEADLINE:"
-- They are comments inside the asciidoc source code so they do not show up in the rendered text.
-- Thus they sort REGIONS of text where each SECTION begins with a hidden headline
if match == "//HEADLINE:" then
-- We are sorting by custom keys.
-- This means that every time we encounter the string "HEADLINE:" we consider the next line a sorting key.
return true, true, "^%s*//HEADLINE:"
end
return false, false, match
end
--}}}
-- {{{ _state_machine_scan(line)
local function _state_machine_scan(line)
local success, is_start_sort_command, _headline_pattern = _is_start_sort_command(line)
if not success then
local errMsg = string.format("Failed to parse sort key: '%s'", _headline_pattern)
print(errMsg)
error(errMsg)
end
if is_start_sort_command then
state = MODE_SORTING
headlinePattern = _headline_pattern
sections = {}
preface = ""
end
output = output .. line
end
--}}}
--{{{ _state_machine_sort(line)
local function _state_machine_sort(line)
--
-- NEW SECTION STARTED
--
if string.match(line, headlinePattern) then -- We found a new section headline/sortkey
-- Start a new section
sections[#sections + 1] = line
return
end
--
-- SORTED REGION ENDED
--
if string.match(line, "^//%s*END_SORT") then
-- We have encountered a command to stop sorting. So we should stop sorting.
-- Each section within the current sorting area is a single string
-- Sort those strings to sort the entire area,
-- and compile/combine/join the strings into the output.
table.sort(sections)
local sorted = table.concat(sections, "")
-- Compile the resulting sorted text.
output = output .. preface .. sorted .. line
-- Reset the state machine to start looking for new areas to sort.
state = STATE_SCANNING
sections = {}
preface = ""
return
end
-- SECTION PREFACE
--
-- This happens if we have preface text before the first heading/sortkey
-- Preface text is paragraph text that comes after START_SORT, but before the
-- first sorting key/section is encountered.
if nil == sections[#sections] then
preface = preface .. line
return
end
-- This line is a normal line within the section.
-- Add it to the current section.
sections[#sections] = sections[#sections] .. line
end
-- }}}
--{{{ _state_machine_process_single_line(line)
local function _state_machine_process_single_line(line)
line = line .. "\n"
-- SCANNING
if state == STATE_SCANNING then
_state_machine_scan(line)
return
end
--
-- SORTING
--
if state == MODE_SORTING then
_state_machine_sort(line)
return
end
end
--}}}
--{{{ sorter(lines)
---Scan a file and sort the headings of the chunks marked for sorting
---@param lines Iterator
---@return string output sorted string
local function sorter(lines)
for line in lines do
_state_machine_process_single_line(line)
end
if not (state == STATE_SCANNING and #sections == 0) then
error("you must be missing an END_SORT or similar")
end
return output
end
--}}}
return sorter