diff --git a/TODO.txt b/TODO.txt
index e87e4c5..abd4ae2 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,4 +1,5 @@
-Add NPC, and Dungeons roll tables
-Put the rollers in their own accordion slots
+Add Steadings tables
+Change steadings and mounts to not show English names by default
Make everything look nicer
+Maybe put roller button in a left nav bar and the results in the middle?
Add a 3d dice rolling visualizer
\ No newline at end of file
diff --git a/src/App.svelte b/src/App.svelte
index 8c80e0c..61f22ed 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -1,12 +1,15 @@
@@ -14,21 +17,38 @@
The Perilous Wilds
A web-app for rolling on tables and getting funny results
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/rollers/CreatureRoller.svelte b/src/rollers/CreatureRoller.svelte
index ab2ad4d..0ec79cb 100644
--- a/src/rollers/CreatureRoller.svelte
+++ b/src/rollers/CreatureRoller.svelte
@@ -1,26 +1,67 @@
- Random Creatures
- Roll Creature
+ Roll Creature
- {#each rollResults as result}
- {result.timestamp}: {result.value.description}
+ {#each rollResults as { creature, timestamp }}
+
+
+
+ {capitalize(creature.type)}
+ {#if creature.subtype !== ""}({creature.subtype}) {/if}: {capitalize(creature.description)}
+
+
+
+
+
+
+ Details:
+
+ {#if creature.ability}Ability: {creature.ability.description} {/if}
+ {#if creature.activity}Activity: {creature.activity.description} {/if}
+ {#if creature.adjective}Adjective: {creature.adjective.description} {/if}
+ {#if creature.age}Age: {creature.age.description} {/if}
+ {#if creature.alignment}Alignment: {creature.alignment.description} {/if}
+ {#if creature.aspect}Aspect: {creature.aspect.description} {/if}
+ {#if creature.condition}Condition: {creature.condition.description} {/if}
+ {#if creature.disposition}Disposition: {creature.disposition.description} {/if}
+ {#if creature.feature}Feature: {creature.feature.description} {/if}
+ {#if creature.npc}NPC Name: {creature.npc.name} {/if}
+ {#if creature.numAppearing}Number Appearing: {creature.numAppearing.description} {/if}
+ {#if creature.size}Size: {creature.size.description} {/if}
+ {#if creature.tags.length > 0}
+ Tags: {#each creature.tags as tag} {tag.description}, {/each}
+ {/if}
+
+
+
+
+
+ {timestamp}
+
{/each}
diff --git a/src/rollers/DangerRoller.svelte b/src/rollers/DangerRoller.svelte
index 538e0d2..71a1014 100644
--- a/src/rollers/DangerRoller.svelte
+++ b/src/rollers/DangerRoller.svelte
@@ -1,7 +1,6 @@
- Random Danger
- Roll Danger
+
+ Roll Danger
+
- {#each rollResults as result}
+ {#each rollResults as { danger, icon, timestamp }}
- {result.timestamp}: {result.danger.category} ({result.danger.subcategory}) : {result.danger.description}
+ {timestamp}: {danger.category} ({danger.subcategory}) : {danger.description}
{/each}
diff --git a/src/rollers/DetailsRoller.svelte b/src/rollers/DetailsRoller.svelte
index 154fe44..1c62ff2 100644
--- a/src/rollers/DetailsRoller.svelte
+++ b/src/rollers/DetailsRoller.svelte
@@ -1,5 +1,4 @@
- addResult(rollAbility())}>Roll Ability
+ roll(rollAbility())}>Roll Ability
- addResult(rollActivity())}>Roll Activity
+ roll(rollActivity())}>Roll Activity
- addResult(rollAdjective())}>Roll Adjective
+ roll(rollAdjective())}>Roll Adjective
- addResult(rollAge())}>Roll Age
+ roll(rollAge())}>Roll Age
- addResult(rollAlignment())}>Roll Alignment
+ roll(rollAlignment())}>Roll Alignment
- addResult(rollAspect())}>Roll Aspect
+ roll(rollAspect())}>Roll Aspect
- addResult(rollCondition())}>Roll Condition
+ roll(rollCondition())}>Roll Condition
- addResult(rollDisposition())}>Roll Disposition
+ roll(rollDisposition())}>Roll Disposition
- addResult(rollElement())}>Roll Element
+ roll(rollElement())}>Roll Element
- addResult(rollFeature())}>Roll Feature
+ roll(rollFeature())}>Roll Feature
- addResult(rollMagicType())}>Roll MagicType
+ roll(rollMagicType())}>Roll MagicType
- addResult(rollNumAppearing())}>Roll NumAppearing
+ roll(rollNumAppearing())}>Roll NumAppearing
- addResult(rollOddity())}>Roll Oddity
+ roll(rollOddity())}>Roll Oddity
- addResult(rollOrientation())}>Roll Orientation
+ roll(rollOrientation())}>Roll Orientation
- addResult(rollRuination())}>Roll Ruination
+ roll(rollRuination())}>Roll Ruination
- addResult(rollSize())}>Roll Size
+ roll(rollSize())}>Roll Size
- addResult(rollTag())}>Roll Tag
+ roll(rollTag())}>Roll Tag
- addResult(rollTerrain())}>Roll Terrain
+ roll(rollTerrain())}>Roll Terrain
- addResult(rollVisibility())}>Roll Visibility
+ roll(rollVisibility())}>Roll Visibility
- {#each rollResults as result}
- {result.timestamp}: ({result.type}): {result.value}
+ {#each rollResults as { type, value, timestamp }}
+ {timestamp}: ({type}): {value}
{/each}
diff --git a/src/rollers/DiscoveryRoller.svelte b/src/rollers/DiscoveryRoller.svelte
index 75b1891..25d7635 100644
--- a/src/rollers/DiscoveryRoller.svelte
+++ b/src/rollers/DiscoveryRoller.svelte
@@ -1,25 +1,82 @@
- Random Discovery
- Roll Discovery
+
+ Roll Discovery
+
- {#each rollResults as result}
-
- {result.timestamp}: {result.value.category} ({result.value.subcategory}): {result.value.description}
-
+ {#each rollResults as { discovery, timestamp }}
+
+
+ {capitalize(discovery.category)}{#if discovery.subcategory !== ""} ({discovery.subcategory}){/if}: {capitalize(
+ discovery.description
+ )}
+
+
+
+
+ {#if discovery.category == "creature"}
+
+ Are you feeling lucky, punk?
+
+ {:else if discovery.category == "steading"}
+
+ TODO: format steadings
+
+ {:else}
+
+ Details:
+
+ {#if discovery.age}Age: {discovery.age.description} {/if}
+ {#if discovery.alignment}Alignment: {discovery.alignment.description} {/if}
+ {#if discovery.aspect}Aspect: {discovery.aspect.description} {/if}
+ {#if discovery.creature}Produced/Inhabited By: {discovery.creature.description} {/if}
+ {#if discovery.element}Element: {discovery.element.description} {/if}
+ {#if discovery.magicType}MagicType: {discovery.magicType.description} {/if}
+ {#if discovery.ruination}Ruination: {discovery.ruination.description} {/if}
+ {#if discovery.size}Size: {discovery.size.description} {/if}
+ {#if discovery.steading}Steading: {discovery.steading.description} {/if}
+ {#if discovery.visibility}Visibility: {discovery.visibility.description} {/if}
+
+
+ {/if}
+
+
+
+ {timestamp}
+
{/each}
diff --git a/src/rollers/DungeonRoller.svelte b/src/rollers/DungeonRoller.svelte
new file mode 100644
index 0000000..a8e6911
--- /dev/null
+++ b/src/rollers/DungeonRoller.svelte
@@ -0,0 +1,103 @@
+
+
+
+
+ Roll Dungeon
+
+
+ {#each rollResults as { dungeon, timestamp }}
+
+
+ {capitalize(dungeon.size.description)} {dungeon.function.description} built by (a/an) {dungeon.builder.description}
+
+
+
+ Fell to ruination from {dungeon.ruination.description} .
+
+
+
+
+ Common Themes ({dungeon.size.commonThemes}):
+
+ {#each dungeon.commonThemes as theme}
+ {theme.category}: {theme.description}
+ {/each}
+
+
+
+ Unique Themes ({dungeon.size.uniqueThemes}):
+
+ {#each dungeon.uniqueThemes as theme}
+ {theme.category}: {theme.description}
+ {/each}
+
+
+
+ Common Areas ({dungeon.size.commonAreas}):
+
+ {#each dungeon.commonAreas as area}
+ {area.type}/{area.category}: {area.description}
+ {/each}
+
+
+
+ Unique Areas ({dungeon.size.uniqueAreas}):
+
+ {#each dungeon.uniqueAreas as area}
+ {area.type}/{area.category}: {area.description}
+ {/each}
+
+
+
+
+
+ {timestamp}
+
+ {/each}
+
+
+
diff --git a/src/rollers/FollowerRoller.svelte b/src/rollers/FollowerRoller.svelte
index 39cb491..6ab4630 100644
--- a/src/rollers/FollowerRoller.svelte
+++ b/src/rollers/FollowerRoller.svelte
@@ -1,46 +1,44 @@
- Random Follower
Roll Followers
- {#each rollResults as result}
+ {#each rollResults as { follower, timestamp }}
- {result.value.name} ({result.value.gender})
+ {follower.name} ({follower.gender})
- From {result.value.homeSteading.homesteadName} in {result.value.homeSteading.kingdomName}
+ From {follower.homeSteading.homesteadName} in {follower.homeSteading.kingdomName}
Quality:
- They are {result.value.quality.description} (Quality: {result.value.quality.value}). They
- {result.value.background.description} .
+ They are {follower.quality.description} (Quality: {follower.quality.value}). They
+ {follower.background.description} .
Tags:
- {#each result.value.tags as tag}
+ {#each follower.tags as tag}
{tag.name}: {tag.description}
{/each}
@@ -48,7 +46,7 @@
Moves:
- {#each result.value.moves as move}
+ {#each follower.moves as move}
{move.description}
{/each}
@@ -56,44 +54,44 @@
Loyalty:
- They have a loyalty score of {result.value.loyalty.value}{#if !!result.value.loyalty.description}
- and {result.value.loyalty.description} {/if}.
+ They have a loyalty score of {follower.loyalty.value}{#if !!follower.loyalty.description}
+ and {follower.loyalty.description} {/if}.
Instinct:
- When left to their own devices, they will {result.value.instinct.description} .
+ When left to their own devices, they will {follower.instinct.description} .
Cost:
- They are motivated by {result.value.cost.name} . They will want {result.value.cost.description}
+ They are motivated by {follower.cost.name} . They will want {follower.cost.description}
Hit Points:
- They are {result.value.hitPoints.description} and have {result.value.hitPoints.value} HP.
+ They are {follower.hitPoints.description} and have {follower.hitPoints.value} HP.
Armor & Shield:
- They are equipped with {result.value.armor.description} ({result.value.armor.value} armor).
+ They are equipped with {follower.armor.description} ({follower.armor.value} armor).
Damage:
- In a fight, they {result.value.damage.description} dealing d{result.value.damage.value} damage.
+ In a fight, they {follower.damage.description} dealing d{follower.damage.value} damage.
Load & Gear:
- {#each result.value.loadAndGear.gear as gear}
+ {#each follower.loadAndGear.gear as gear}
{gear}
{/each}
@@ -101,7 +99,7 @@
- {result.timestamp}
+ {timestamp}
{/each}
diff --git a/src/rollers/KingdomRoller.svelte b/src/rollers/KingdomRoller.svelte
index 5abb5cb..116f7dc 100644
--- a/src/rollers/KingdomRoller.svelte
+++ b/src/rollers/KingdomRoller.svelte
@@ -1,25 +1,21 @@
@@ -35,12 +31,12 @@
{#each categories as category}
- rollName(category)}>Roll {_.capitalize(category)}
+ roll(category)}>Roll {capitalize(category)}
{/each}
- {#each rollResults as result}
- {result.timestamp}: {result.value}
+ {#each rollResults as { value, icon, timestamp }}
+ {timestamp}: {value}
{/each}
diff --git a/src/rollers/NpcRoller.svelte b/src/rollers/NpcRoller.svelte
new file mode 100644
index 0000000..7e86c03
--- /dev/null
+++ b/src/rollers/NpcRoller.svelte
@@ -0,0 +1,85 @@
+
+
+
+
+ Roll Npc
+
+
+ {#each rollResults as { npc, timestamp }}
+
+
+ {npc.getDescription()}
+
+
+
+ From {npc.hometown} .
+
+
+
+
+ Background Context:
+
+
+ They are a(n) {npc.context.alignment.description} {npc.context.description} with
+ {npc.trait.category} ({npc.context.trait.description})
+ encountered in a(n) {npc.context.category} setting while they are {npc.context.activity.description}
+
+
+
+
+ Follower Stats:
+
+
+
+
+
+ {timestamp}
+
+ {/each}
+
+
+
diff --git a/src/rollers/PlaceRoller.svelte b/src/rollers/PlaceRoller.svelte
index dcf5e6b..acdd657 100644
--- a/src/rollers/PlaceRoller.svelte
+++ b/src/rollers/PlaceRoller.svelte
@@ -1,28 +1,23 @@
- Random Places
- Roll Region
+
+ Roll Place
+
- {#each rollResults as result}
- {result.timestamp}: {result.value}
+ {#each rollResults as { place, timestamp }}
+ {timestamp}: {place}
{/each}
diff --git a/src/rollers/RegionRoller.svelte b/src/rollers/RegionRoller.svelte
index 020f451..1ac0a60 100644
--- a/src/rollers/RegionRoller.svelte
+++ b/src/rollers/RegionRoller.svelte
@@ -1,28 +1,23 @@
- Random Regions
- Roll Region
+
+ Roll Region
+
- {#each rollResults as result}
- {result.timestamp}: {result.value}
+ {#each rollResults as { region, timestamp }}
+ {timestamp}: {region}
{/each}
diff --git a/src/rollers/creatures.ts b/src/rollers/creatures.ts
index 61eb69c..7b252aa 100644
--- a/src/rollers/creatures.ts
+++ b/src/rollers/creatures.ts
@@ -1,49 +1,59 @@
import { random, sample } from 'lodash';
import { rollUnnaturalEntity } from './dangers';
-import { Activity, Disposition, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size } from './details';
-import { rollNpc } from './npcs';
+import { Ability, Activity, Adjective, Age, Alignment, Aspect, Condition, Disposition, Feature, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size, Tag } from './details';
+import { Npc, rollNpc } from './npcs';
export class Creature {
constructor(public roll: number = 0, public subroll: number = 0, public specifcroll: number = 0, public type: string = "", public subtype: string = "", public description: string = "") { };
- details: string[] = [];
+
+ ability?: Ability;
+ activity?: Activity;
+ adjective?: Adjective;
+ age?: Age;
+ alignment?: Alignment;
+ aspect?: Aspect;
+ condition?: Condition;
+ disposition?: Disposition;
+ feature?: Feature;
+ npc?: Npc;
+ numAppearing?: NumAppearing;
+ size?: Size;
+ tags: Tag[] = [];
}
export function rollCreature(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)) {
- let creature = new Creature(roll, subroll, specificroll);
if (roll <= 4) {
return rollBeast(roll, subroll, specificroll);
} else if (roll <= 6) {
- creature.type = "human";
- let npc = rollNpc();
- creature.description = `${npc.name} the ${npc.gender} ${npc.occupation.subcategory} from ${npc.hometown}`;
- creature.details = [
- rollActivity().description,
- rollAlignment().description,
- rollDisposition().description,
- rollNumAppearing().description,
- npc.name /* TODO: figure out how to do this */
- ];
+ let human = new Creature(roll, subroll, specificroll);
+ human.type = "human";
+ human.npc = rollNpc();
+ human.description = human.npc.getDescription(true);
+ human.activity = rollActivity();
+ human.alignment = rollAlignment();
+ human.disposition = rollDisposition();
+ human.numAppearing = rollNumAppearing();
+
+ return human;
} else if (roll <= 8) {
return rollHumanoid(roll, subroll, specificroll);
} else if (roll <= 12) {
return rollMonster();
}
- return creature;
+ return new Creature(roll, subroll, specificroll);
}
export function rollBeast(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
let creature = new Creature(roll, subroll, specificroll);
creature.type = "beast";
- creature.details = [
- rollActivity().description,
- rollDisposition().description,
- rollNumAppearing().description,
- rollSize().description
- ];
+ creature.activity = rollActivity();
+ creature.disposition = rollDisposition();
+ creature.numAppearing = rollNumAppearing();
+ creature.size = rollSize();
if (subroll <= 7) {
creature.subtype = "earthbound";
@@ -113,13 +123,11 @@ export function rollWaterGoingBeast(roll: number = random(1, 12)): string {
export function rollHumanoid(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
let creature = new Creature(roll, subroll, specificroll, "humanoid");
- creature.details = [
- rollActivity().description,
- rollAlignment().description,
- rollDisposition().description,
- rollNumAppearing().description,
- rollNpc().name /* figure out how to do this */
- ];
+ creature.activity = rollActivity();
+ creature.alignment = rollAlignment();
+ creature.disposition = rollDisposition();
+ creature.numAppearing = rollNumAppearing();
+ creature.npc = rollNpc(); /* figure out how to do this */
if (subroll <= 7) {
creature.subtype = "common";
@@ -190,13 +198,12 @@ export function rollHybridHumanoid(roll: number = random(1, 12)): string {
export function rollMonster(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
let creature = new Creature(roll, subroll, specificroll, "monster");
- creature.details = [
- rollActivity().description,
- rollAlignment().description,
- rollDisposition().description,
- rollNumAppearing().description,
- rollSize().description,
- ];
+
+ creature.activity = rollActivity();
+ creature.alignment = rollAlignment();
+ creature.disposition = rollDisposition();
+ creature.numAppearing = rollNumAppearing();
+ creature.size = rollSize();
if (subroll <= 7) {
creature.subtype = "unusual";
@@ -258,45 +265,3 @@ export function rollLegendaryMonster(roll: number = random(1, 12)): string {
return "";
}
-
-
-// MONSTER. Give every monster life!
-
-// I
-// 'V
-// 48
-// UNUSUAL ......
-// 1-3
-// 4-6
-// 7-9
-// 10-12 Truai. ENTI
-// 9-10
-//
-// ASK THE FATES
-// LREATURE
-// Roll 1d12 for creature type if it hasn't already been established, then 1d12 on indicat-
-// ed subtable for specific prompt. Roll additional details as indicated, and/or at whim.
-// 1d12 QmATuRE Aim'rtoi.. DETAILS (see pages 50-53)
-// 1-4 BEAST ACTIVITY, DISPOSITION, No. APPEARING, SIZE
-// 5-6 Human ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, NPC tables
-// 7-8 HUMANOID ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, NPC tables 942 MONSTER ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, SIZE
-// Optional: ABILITY, ADJECTIVE, AGE, ASPECT, CONDITION, FEATURE, TAGS
-
-// HUMANOID . If you roll a classic fantasy species, adapt it to your setting. 1-7 COMMON 8-10 UNCOMMON 11-12 HYBRID
-
-// MONSTER. Give every monster life!
-// 1-7 UNUSUAL
-// 1-3 plant/fungus
-// 4-5 Undead Human
-// 6 Undead HUMANOID
-// 7-8 BEAST + BEAST
-// 9-10 BEAST + ABILITY
-// 1142 BEAST + FEATURE
-// 8T10.. RARE 11-12
-// 1-3 slime/ooze (4morphous) 1-3
-// 4-6 creation (Construct) 4-6
-// 7-9 BEAST + ODDITY 7-9
-// 10-12 UNNxrua1. ENTITY 10
-// II
-// 12
-// LEGENDARY
diff --git a/src/rollers/details.ts b/src/rollers/details.ts
index ec9cd4f..783555d 100644
--- a/src/rollers/details.ts
+++ b/src/rollers/details.ts
@@ -8,17 +8,17 @@ export class Ability {
export function rollAbility(roll: number = random(1, 12)): Ability {
let ability = new Ability(roll);
ability.description = [
- "bless/curse",
- "entangle/trap/snare",
- "poison/disease",
- "paralyze/petrify",
- "mimic/camouflage",
- "seduce/hypnotize",
- "dissolve/disintegrate",
+ sample(["bless", "curse"]),
+ sample(["entangle", "trap", "snare"]),
+ sample(["poison", "disease"]),
+ sample(["paralyze", "petrify"]),
+ sample(["mimic", "camouflage"]),
+ sample(["seduce", "hypnotize"]),
+ sample(["dissolve", "disintegrate"]),
rollMagicType().description,
- "drain life/magic",
+ sample(["drain life", "drain magic"]),
`immunity to ${rollElement().description}`,
- "read/control minds",
+ sample(["read minds", "control minds"]),
"[ABILITY] and [ABILITY]"
][roll - 1];
ability.description = replace(ability.description, /\[ABILITY\]/g, () => rollAbility(random(1, 11)).description);
@@ -34,16 +34,16 @@ export class Activity {
export function rollActivity(roll: number = random(1, 12)): Activity {
let activity = new Activity(roll);
activity.description = [
- "laying trap/ambush",
- "fighting/at war",
- "prowling/on patrol",
- "hunting/foraging",
- "eating/resting",
- "crafting/praying",
- "traveling/relocating",
- "exploring/lost",
+ sample(["laying trap", "ambush"]),
+ sample(["fighting", "at war"]),
+ sample(["prowling", "on patrol"]),
+ sample(["hunting", "foraging"]),
+ sample(["eating", "resting"]),
+ sample(["crafting", "praying"]),
+ sample(["traveling", "relocating"]),
+ sample(["exploring", "lost"]),
"returning home",
- "building/excavating",
+ sample(["building", "excavating"]),
"sleeping",
"dying",
][roll - 1];
@@ -59,17 +59,17 @@ export class Adjective {
export function rollAdjective(roll: number = random(1, 12)): Adjective {
let adjective = new Adjective(roll);
adjective.description = [
- "slick/slimy",
- "rough/hard/sharp",
- "smooth/soft/dull",
- "corroded/rusty",
- "rotten/decaying",
- "broken/brittle",
- "stinking/smelly",
- "weak/thin/drained",
- "strong/fat/full",
- "pale/poor/shallow",
- "dark/rich/deep",
+ sample(["slick", "slimy"]),
+ sample(["rough", "hard", "sharp"]),
+ sample(["smooth", "soft", "dull"]),
+ sample(["corroded", "rusty"]),
+ sample(["rotten", "decaying"]),
+ sample(["broken", "brittle"]),
+ sample(["stinking", "smelly"]),
+ sample(["weak", "thin", "drained"]),
+ sample(["strong", "fat", "full"]),
+ sample(["pale", "poor", "shallow"]),
+ sample(["dark", "rich", "deep"]),
"colorful",
][roll - 1];
@@ -132,16 +132,16 @@ export class Aspect {
export function rollAspect(roll: number = random(1, 12)): Aspect {
let aspect = new Aspect(roll);
aspect.description = [
- "power/strength",
- "trickery/dexterity",
- "time/constitution",
- "knowledge/intelligence",
- "nature/wisdom",
- "culture/charisma",
- "war/lies/discord",
- "peace/truth/balance",
- "hate/envy",
- "love/admiration",
+ sample(["power", "strength"]),
+ sample(["trickery", "dexterity"]),
+ sample(["time", "constitution"]),
+ sample(["knowledge", "intelligence"]),
+ sample(["nature", "wisdom"]),
+ sample(["culture", "charisma"]),
+ sample(["war", "lies", "discord"]),
+ sample(["peace", "truth", "balance"]),
+ sample(["hate", "envy"]),
+ sample(["love", "admiration"]),
rollElement().description,
"[ASPECT] and [ASPECT]"
][roll - 1];
@@ -159,19 +159,19 @@ export function rollCondition(roll: number = random(1, 12)): Condition {
let condition = new Condition(roll);
if (roll <= 1) {
- condition.description = "being built/born";
+ condition.description = sample(["being built", "being born"]);
} else if (roll <= 4) {
- condition.description = "intact/healthy/stable";
+ condition.description = sample(["intact", "healthy", "stable"]);
} else if (roll <= 7) {
- condition.description = "occupied/active/alert";
+ condition.description = sample(["occupied", "active", "alert"]);
} else if (roll <= 9) {
- condition.description = "worn/tired/weak";
+ condition.description = sample(["worn", "tired", "weak"]);
} else if (roll <= 10) {
- condition.description = "vacant/lost";
+ condition.description = sample(["vacant", "lost"]);
} else if (roll <= 11) {
- condition.description = "ruined/defiled/dying";
+ condition.description = sample(["ruined", "defiled", "dying"]);
} else if (roll <= 12) {
- condition.description = "disappeared/dead";
+ condition.description = sample(["disappeared", "dead"]);
}
return condition;
@@ -188,15 +188,15 @@ export function rollDisposition(roll: number = random(1, 12)): Disposition {
if (roll <= 1) {
disposition.description = "attacking";
} else if (roll <= 4) {
- disposition.description = "hostile/aggressive";
+ disposition.description = sample(["hostile", "aggressive"]);
} else if (roll <= 6) {
- disposition.description = "cautious/doubtful";
+ disposition.description = sample(["cautious", "doubtful"]);
} else if (roll <= 7) {
- disposition.description = "fearful/fleeing";
+ disposition.description = sample(["fearful", "fleeing"]);
} else if (roll <= 10) {
disposition.description = "neutral";
} else if (roll <= 11) {
- disposition.description = "curious/hopeful";
+ disposition.description = sample(["curious", "hopeful"]);
} else if (roll <= 12) {
disposition.description = "friendly";
}
@@ -242,13 +242,13 @@ export function rollFeature(roll: number = random(1, 12)): Feature {
} else if (roll <= 3) {
feature.description = "winged/flying";
} else if (roll <= 4) {
- feature.description = "multiple heads/headless";
+ feature.description = sample(["multiple heads", "headless"]);
} else if (roll <= 5) {
- feature.description = "many eyes/one eye";
+ feature.description = sample(["many eyes", "one eye"]);
} else if (roll <= 6) {
- feature.description = "many limbs/tails";
+ feature.description = sample(["many limbs", "tails"]);
} else if (roll <= 7) {
- feature.description = "tentacles/tendrils";
+ feature.description = sample(["tentacles", "tendrils"]);
} else if (roll <= 8) {
feature.description = rollAspect().description;
} else if (roll <= 9) {
@@ -317,15 +317,15 @@ export class Oddity {
export function rollOddity(roll: number = random(1, 12)): Oddity {
let oddity = new Oddity(roll);
oddity.description = [
- "weird color/smell/sound",
+ sample(["weird color", "smell", "sound"]),
"geometric",
- "web/network/system",
- "crystalline/glass-like",
+ sample(["web", "network", "system"]),
+ sample(["crystalline", "glass-like"]),
"fungal",
- "gaseous/smokey",
- "mirage/illusion",
- "volcanic/explosive",
- "magnetic/repellant",
+ sample(["gaseous", "smokey"]),
+ sample(["mirage", "illusion"]),
+ sample(["volcanic", "explosive"]),
+ sample(["magnetic", "repellant"]),
"devoid of life",
"unexpectedly alive",
"[ODDITY] and [ODDITY]",
@@ -379,15 +379,15 @@ export function rollRuination(roll: number = random(1, 12)): Ruination {
if (roll <= 1) {
ruination.description = "arcane disaster";
} else if (roll <= 2) {
- ruination.description = "damnation/curse";
+ ruination.description = sample(["damnation", "curse"]);
} else if (roll <= 4) {
- ruination.description = "earthquake/fire/flood";
+ ruination.description = sample(["earthquake", "fire", "flood"]);
} else if (roll <= 6) {
- ruination.description = "plague/famine/drought";
+ ruination.description = sample(["plague", "famine", "drought"]);
} else if (roll <= 8) {
ruination.description = "overrun by monsters";
} else if (roll <= 10) {
- ruination.description = "war/invasion";
+ ruination.description = sample(["war", "invasion"]);
} else if (roll <= 11) {
ruination.description = "depleted resources";
} else if (roll <= 12) {
@@ -463,19 +463,19 @@ export function rollTerrain(roll: number = random(1, 12)): Terrain {
let terrain = new Terrain(roll);
if (roll <= 1) {
- terrain.description = "wasteland/desert";
+ terrain.description = sample(["wasteland", "desert"]);
} else if (roll <= 3) {
- terrain.description = "flatland/plain";
+ terrain.description = sample(["flatland", "plain"]);
} else if (roll <= 4) {
- terrain.description = "wetland/marsh/swamp";
+ terrain.description = sample(["wetland", "marsh", "swamp"]);
} else if (roll <= 7) {
- terrain.description = "woodland/forest/jungle";
+ terrain.description = sample(["woodland", "forest", "jungle"]);
} else if (roll <= 9) {
- terrain.description = "highland/hills";
+ terrain.description = sample(["highland", "hills"]);
} else if (roll <= 11) {
terrain.description = "mountains";
} else if (roll <= 12) {
- terrain.description = rollOddity().description;
+ terrain.description = `${rollOddity().description} oddity`;
}
return terrain;
@@ -490,15 +490,15 @@ export function rollVisibility(roll: number = random(1, 12)): Visibility {
let visibility = new Visibility(roll);
if (roll <= 2) {
- visibility.description = "buried/camouflaged/nigh invisible";
+ visibility.description = sample(["buried", "camouflaged", "nigh invisible"]);
} else if (roll <= 6) {
- visibility.description = "partly covered/overgrown/hidden";
+ visibility.description = sample(["partly covered", "partly overgrown", "partly hidden"]);
} else if (roll <= 9) {
- visibility.description = "obvious/in plain sight";
+ visibility.description = sample(["obvious", "in plain sight"]);
} else if (roll <= 11) {
visibility.description = "visible at near distance";
} else if (roll <= 12) {
- visibility.description = "visible at great distance/focal point";
+ visibility.description = sample(["visible at great distance", "focal point"]);
}
return visibility;
diff --git a/src/rollers/discoveries.ts b/src/rollers/discoveries.ts
index a45ade3..ff2453d 100644
--- a/src/rollers/discoveries.ts
+++ b/src/rollers/discoveries.ts
@@ -1,14 +1,23 @@
import { random, sample } from 'lodash';
import { Creature, rollCreature } from './creatures';
-import { rollAlignment, rollElement, rollMagicType, rollOddity, rollTerrain } from './details';
+import { Age, Alignment, Aspect, Element, MagicType, rollAge, rollAlignment, rollAspect, rollElement, rollMagicType, rollOddity, rollRuination, rollSize, rollTerrain, rollVisibility, Ruination, Size, Visibility } from './details';
import { rollDungeon } from './dungeons';
import { rollSteading, Steading } from './steadings';
import { rollTreasure } from './treasures';
export class Discovery {
constructor(public roll: number = 0, public subroll: number = 0, public specificroll: number = 0, public category: string = "", public subcategory: string = "", public description: string = "") { };
+
+ age?: Age;
+ alignment?: Alignment;
+ aspect?: Aspect;
creature?: Creature;
+ element?: Element;
+ magicType?: MagicType;
+ ruination?: Ruination;
+ size?: Size;
steading?: Steading;
+ visibility?: Visibility;
}
export function rollDiscovery() {
@@ -37,12 +46,18 @@ export function rollUnnaturalFeature(roll: number = random(1, 12), subroll: numb
if (subroll <= 9) {
discovery.subcategory = "arcane";
discovery.description = rollArcaneFeature(specificroll);
+ discovery.alignment = rollAlignment();
+ discovery.magicType = rollMagicType();
} else if (subroll <= 11) {
discovery.subcategory = "planar";
discovery.description = rollPlanarFeature(specificroll);
+ discovery.alignment = rollAlignment();
+ discovery.element = rollElement();
} else if (subroll <= 12) {
discovery.subcategory = "divine";
discovery.description = rollDivineFeature(specificroll);
+ discovery.alignment = rollAlignment();
+ discovery.aspect = rollAspect();
}
return discovery;
@@ -107,7 +122,9 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
if (subroll <= 2) {
discovery.subcategory = "lair";
- discovery.description = rollLair(specificroll)
+ discovery.description = rollLair(specificroll);
+ discovery.creature = rollCreature();
+ discovery.visibility = rollVisibility();
} else if (subroll <= 4) {
discovery.subcategory = "obstacle";
discovery.description = rollObstacle(specificroll);
@@ -121,8 +138,10 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
discovery.subcategory = "terrain change";
discovery.description = rollLandmark(specificroll);
} else if (subroll <= 12) {
- discovery.subcategory = "terrain change";
+ discovery.subcategory = "resource";
discovery.description = rollResource(specificroll);
+ discovery.size = rollSize();
+ discovery.visibility = rollVisibility();
}
return discovery;
@@ -148,9 +167,9 @@ export function rollObstacle(roll: number = random(1, 12)): string {
if (roll <= 5) {
return "difficult ground";
} else if (roll <= 8) {
- return "cliff/crevasse/chasm";
+ return sample(["cliff", "crevasse", "chasm"]);
} else if (roll <= 10) {
- return "ravine/gorge";
+ return sample(["ravine", "gorge"]);
} else if (roll <= 12) {
return rollOddity().description;
}
@@ -160,15 +179,15 @@ export function rollObstacle(roll: number = random(1, 12)): string {
export function rollTerrainChange(roll: number = random(1, 12)): string {
if (roll <= 4) {
- return `limited area of ${rollTerrain()}`;
+ return `limited area of ${rollTerrain().description}`;
} else if (roll <= 6) {
- return "crevice/hole/pit/cave";
+ return sample(["crevice", "hole", "pit", "cave"]);
} else if (roll <= 8) {
return "altitude change";
} else if (roll <= 10) {
- return "canyon/valley";
+ return sample(["canyon", "valley"]);
} else if (roll <= 12) {
- return "rise/peak in distance";
+ return sample(["rise", "peak in distance"]);
}
return "";
@@ -176,17 +195,17 @@ export function rollTerrainChange(roll: number = random(1, 12)): string {
export function rollWaterFeature(roll: number = random(1, 12)): string {
if (roll <= 1) {
- return "spring/hotspring";
+ return sample(["spring", "hotspring"]);
} else if (roll <= 2) {
- return "waterfall/geyser";
+ return sample(["waterfall", "geyser"]);
} else if (roll <= 6) {
- return "creek/stream/brook";
+ return sample(["creek", "stream", "brook"]);
} else if (roll <= 8) {
- return "pond/lake";
+ return sample(["pond", "lake"]);
} else if (roll <= 10) {
return "river";
} else if (roll <= 12) {
- return "sea/ocean";
+ return sample(["sea", "ocean"]);
}
return "";
@@ -208,15 +227,15 @@ export function rollLandmark(roll: number = random(1, 12)): string {
export function rollResource(roll: number = random(1, 12)): string {
if (roll <= 4) {
- return "game/fruit/vegetable";
+ return sample(["game", "fruit", "vegetable"]);
} else if (roll <= 6) {
- return "herb/spice/dye source";
+ return sample(["herb", "spice", "dye source"]);
} else if (roll <= 9) {
- return "timber/stone";
+ return sample(["timber", "stone"]);
} else if (roll <= 11) {
- return "ore (copper, iron, etc.)";
+ return sample(["copper ore", "iron ore", "tin ore", "silver ore"]);
} else if (roll <= 12) {
- return "precious metal/gems";
+ return sample(["precious metal", "precious gems"]);
}
return "";
@@ -228,9 +247,13 @@ function rollEvidence(roll: number = random(1, 12), subroll: number = random(1,
if (subroll <= 6) {
discovery.subcategory = "tracks/spoor";
discovery.description = rollTracksSpoor(specificroll);
+ discovery.age = rollAge();
+ discovery.creature = rollCreature();
} else if (subroll <= 10) {
discovery.subcategory = "remains/debris";
discovery.description = rollRemainsDebris(specificroll);
+ discovery.age = rollAge();
+ discovery.visibility = rollVisibility();
} else if (subroll <= 12) {
discovery.subcategory = "stash/cache";
discovery.description = rollStashCache(specificroll);
@@ -305,15 +328,23 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
if (subroll <= 1) {
discovery.subcategory = "enigmatic";
discovery.description = rollEnigmaticStructure(specificroll);
+ discovery.age = rollAge(random(1, 8) + 4);
+ discovery.size = rollSize(random(1, 8) + 4);
+ discovery.visibility = rollVisibility();
} else if (subroll <= 3) {
discovery.subcategory = "infrastructure";
discovery.description = rollInfrastructureStructure(specificroll);
+ discovery.creature = rollCreature(random(1, 4) + 4);
} else if (subroll <= 4) {
discovery.subcategory = "dwelling";
discovery.description = rollDwellingStructure(specificroll);
+ discovery.creature = rollCreature(random(1, 4) + 4);
} else if (subroll <= 6) {
discovery.subcategory = "burial/religious";
discovery.description = rollBurialReligiousStructure(specificroll);
+ discovery.creature = rollCreature(random(1, 4) + 4);
+ discovery.alignment = rollAlignment();
+ discovery.aspect = rollAspect();
} else if (subroll <= 8) {
discovery.subcategory = "steading";
discovery.steading = rollSteading();
@@ -322,6 +353,10 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
} else if (subroll <= 12) {
discovery.subcategory = "ruin";
discovery.description = rollRuinStructure(specificroll);
+ discovery.creature = rollCreature(random(1, 4) + 4);
+ discovery.age = rollAge(random(1, 8) + 4);
+ discovery.ruination = rollRuination();
+ discovery.visibility = rollVisibility();
}
return discovery;
@@ -343,15 +378,15 @@ export function rollEnigmaticStructure(roll: number = random(1, 12)): string {
export function rollInfrastructureStructure(roll: number = random(1, 12)): string {
if (roll <= 4) {
- return "track/path";
+ return sample(["track", "path"]);
} else if (roll <= 8) {
return "road";
} else if (roll <= 10) {
- return "bridge/ford";
+ return sample(["bridge", "ford"]);
} else if (roll <= 11) {
- return "mine/quarry";
+ return sample(["mine", "quarry"]);
} else if (roll <= 12) {
- return "aqueduct/canal/portal";
+ return sample(["aqueduct", "canal", "portal"]);
}
return "";
@@ -361,13 +396,13 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
if (roll <= 3) {
return "campsite";
} else if (roll <= 6) {
- return "hovel/hut";
+ return sample(["hovel", "hut"]);
} else if (roll <= 8) {
return "farm";
} else if (roll <= 10) {
- return "inn/roadhouse";
+ return sample(["inn", "roadhouse"]);
} else if (roll <= 12) {
- return "tower/keep/estate";
+ return sample(["tower", "keep", "estate"]);
}
return "";
@@ -375,15 +410,15 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
export function rollBurialReligiousStructure(roll: number = random(1, 12)): string {
if (roll <= 2) {
- return "grave marker/barrow";
+ return sample(["grave marker", "grave barrow"]);
} else if (roll <= 4) {
- return "graveyard/necropolis";
+ return sample(["graveyard", "necropolis"]);
} else if (roll <= 6) {
- return "tomb/crypt";
+ return sample(["tomb", "crypt"]);
} else if (roll <= 9) {
return "shrine";
} else if (roll <= 11) {
- return "temple/retreat";
+ return sample(["temple", "retreat"]);
} else if (roll <= 12) {
return "great temple";
}
diff --git a/src/rollers/dungeons.ts b/src/rollers/dungeons.ts
index 845e2f6..4bca270 100644
--- a/src/rollers/dungeons.ts
+++ b/src/rollers/dungeons.ts
@@ -1,27 +1,348 @@
+import { random, replace, sample, times } from "lodash";
+import { Creature, rollCreature, rollHumanoid, rollMonster } from "./creatures";
+import { rollElement, rollOddity } from "./details";
+
export class Dungeon {
size: Size;
- ruination: string;
- builder: string;
- function: string;
- themes: string[];
- discovery: string;
- danger: string;
+ ruination: Ruination;
+ builder: Builder;
+ function: DunFunction;
+ commonThemes: Theme[] = [];
+ uniqueThemes: Theme[] = [];
+ commonAreas: (Discovery | Danger)[] = [];
+ uniqueAreas: (Discovery | Danger)[] = [];
printDescription() {
- return `${this.size.size} ${this.builder} ${this.function}`;
+ return `${this.size.description} ${this.function.description} built by ${this.builder.description}`;
}
}
export class Size {
- constructor(public size: string = "", public themes: string = "", public areas: string = "") { };
+ constructor(public roll: number = 0, public description: string = "", public commonThemes: number = 0, public uniqueThemes: number = 0, public commonAreas: number = 0, public uniqueAreas: number = 0) { };
+}
+
+export class Ruination {
+ constructor(public roll: number = 0, public description: string = "") { };
+}
+
+export class Builder {
+ constructor(public roll: number = 0, public description: string = "") { };
+}
+
+export class DunFunction {
+ constructor(public roll: number = 0, public description: string = "") { };
+}
+
+export class Theme {
+ constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
+}
+
+export class Discovery {
+ constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
+ type: string = "discovery";
+}
+
+export class Danger {
+ constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
+ type: string = "danger";
+ creature?: Creature;
}
export function rollDungeon(): Dungeon {
- // TODO: Add the who dungeon thing
let dungeon = new Dungeon();
- dungeon.size = new Size("huge");
- dungeon.builder = "dwarves";
- dungeon.function = "mine";
+ dungeon.size = rollSize();
+ dungeon.ruination = rollRuination();
+ dungeon.builder = rollBuilder();
+ dungeon.function = rollDunFunction();
+ times(dungeon.size.commonThemes, () => dungeon.commonThemes.push(rollTheme()));
+ times(dungeon.size.uniqueThemes, () => dungeon.uniqueThemes.push(rollTheme()));
+ times(dungeon.size.commonAreas, () => dungeon.commonAreas.push(sample([rollDiscovery, rollDanger])()));
+ times(dungeon.size.uniqueAreas, () => dungeon.uniqueAreas.push(sample([rollDiscovery, rollDanger])()));
- return new Dungeon();
-}
\ No newline at end of file
+ return dungeon;
+}
+
+function rollSize(roll: number = random(1, 12)): Size {
+ if (roll <= 3) {
+ return new Size(roll, "small", 2, random(1, 4), 6, random(1, 6 + 2));
+ } else if (roll <= 9) {
+ return new Size(roll, "medium", 3, random(1, 6), 12, random(1, 6) + random(1, 6) + 4);
+ } else if (roll <= 11) {
+ return new Size(roll, "large", 4, random(1, 6) + 1, 16, random(1, 6) + random(1, 6) + random(1, 6) + 6);
+ } else if (roll <= 12) {
+ return new Size(roll, "huge", 5, random(1, 6) + 2, 24, random(1, 6) + random(1, 6) + random(1, 6) + random(1, 6) + 10);
+ }
+
+ return new Size(roll);
+}
+
+function rollRuination(roll: number = random(1, 12)): Ruination {
+
+ if (roll <= 1) {
+ return new Ruination(roll, "arcane disaster");
+ } else if (roll <= 2) {
+ return new Ruination(roll, "damnation/curse");
+ } else if (roll <= 4) {
+ return new Ruination(roll, "earthquake/fire/flood");
+ } else if (roll <= 6) {
+ return new Ruination(roll, "plague/famine/drought");
+ } else if (roll <= 8) {
+ return new Ruination(roll, "overrun by monsters");
+ } else if (roll <= 10) {
+ return new Ruination(roll, "war/invasion");
+ } else if (roll <= 11) {
+ return new Ruination(roll, "depleted resources");
+ } else if (roll <= 12) {
+ return new Ruination(roll, "better prospects elsewhere");
+ }
+ return new Ruination(roll);
+}
+
+function rollBuilder(roll: number = random(1, 12)): Builder {
+ if (roll <= 1) {
+ return new Builder(roll, sample(["aliens", "precursors"]));
+ } else if (roll <= 2) {
+ return new Builder(roll, sample(["demigod", "demon"]));
+ } else if (roll <= 3) {
+ return new Builder(roll, "natural(caves, etc.)");
+ } else if (roll <= 5) {
+ return new Builder(roll, sample(["religious order", "cult"]));
+ } else if (roll <= 6) {
+ return new Builder(roll, rollHumanoid().description);
+ } else if (roll <= 8) {
+ return new Builder(roll, sample(["dwarves", "gnomes"]));
+ } else if (roll <= 10) {
+ return new Builder(roll, "elves");
+ } else if (roll <= 11) {
+ return new Builder(roll, sample(["wizard", "madman"]));
+ } else if (roll <= 12) {
+ return new Builder(roll, sample(["monarch", "warlord"]));
+ }
+
+ return new Builder(roll);
+}
+
+function rollDunFunction(roll: number = random(1, 12)): DunFunction {
+ if (roll <= 1) {
+ return new DunFunction(roll, sample(["source", "portal"]));
+ } else if (roll <= 2) {
+ return new DunFunction(roll, "mine");
+ } else if (roll <= 4) {
+ return new DunFunction(roll, sample(["tomb", "crypt"]));
+ } else if (roll <= 5) {
+ return new DunFunction(roll, "prison");
+ } else if (roll <= 7) {
+ return new DunFunction(roll, sample(["lair", "den", "hideout"]));
+ } else if (roll <= 9) {
+ return new DunFunction(roll, sample(["stronghold", "sanctuary"]));
+ } else if (roll <= 10) {
+ return new DunFunction(roll, sample(["shrine", "temple", "oracle"]));
+ } else if (roll <= 11) {
+ return new DunFunction(roll, sample(["archive", "library"]));
+ } else if (roll <= 12) {
+ return new DunFunction(roll, sample(["unknown", "mystery"]));
+ }
+
+ return new DunFunction(roll);
+}
+
+function rollTheme(roll: number = random(1, 12), subroll: number = random(1, 12)): Theme {
+ if (roll <= 5) {
+ return rollMundaneTheme(roll, subroll);
+ } else if (roll <= 9) {
+ return rollUnusualTheme(roll, subroll);
+ } else if (roll <= 12) {
+ return rollExtraordinaryTheme(roll, subroll);
+ }
+
+ return new Theme(roll, subroll);
+}
+
+function rollMundaneTheme(roll: number = random(1, 12), subroll: number = random(1, 12)): Theme {
+ return new Theme(roll, subroll, "mundane", [
+ "rot / decay",
+ "torture / agony",
+ "madness",
+ "all is lost",
+ "noble sacrifice",
+ "savage fury",
+ "survival",
+ "criminal activity",
+ "secrets / treachery",
+ "tricks and traps",
+ "invasion / infestation",
+ "factions at war",
+ ][subroll - 1]);
+}
+
+function rollUnusualTheme(roll: number = random(1, 12), subroll: number = random(1, 12)): Theme {
+ return new Theme(roll, subroll, "unusual", [
+ "creation / invention",
+ `elemental ${rollElement().description}`,
+ "knowledge / learning",
+ "growth / expansion",
+ "deepening mystery",
+ "transformation / change",
+ "chaos and destruction",
+ "shadowy forces",
+ "forbidden knowledge",
+ "poison / disease 10",
+ "corruption / blight",
+ "impending disaster",
+ ][subroll - 1]);
+}
+
+function rollExtraordinaryTheme(roll: number = random(1, 12), subroll: number = random(1, 12)): Theme {
+ return new Theme(roll, subroll, "extraordinary", [
+ "scheming evil",
+ "divination / scrying",
+ "blasphemy",
+ "arcane research",
+ "occult forces",
+ "an ancient curse",
+ "mutation",
+ "the unquiet dead",
+ "bottomless hunger",
+ "incredible power",
+ "unspeakable horrors",
+ "holy war",
+ ][subroll - 1]);
+}
+
+function rollDiscovery(roll: number = random(1, 12), subroll: number = random(1, 12)): Discovery {
+ if (roll <= 3) {
+ return rollDiscoveryDressing(roll, subroll);
+ } else if (roll <= 9) {
+ return rollDiscoveryFeature(roll, subroll);
+ } else if (roll <= 12) {
+ return rollDiscoveryFind(roll, subroll);
+ }
+
+ return new Discovery(roll, subroll);
+}
+
+function rollDiscoveryDressing(roll: number = random(1, 12), subroll: number = random(1, 12)): Discovery {
+ return new Discovery(roll, subroll, "dressing", [
+ sample(["junk", "debris"]),
+ sample(["tracks", "marks"]),
+ "signs of battle",
+ sample(["writing", "carving"]),
+ "warning",
+ `dead ${rollCreature().description}`,
+ sample(["bones", "remains"]),
+ sample(["book", "scroll", "map"]),
+ sample(["broken door", "broken wall"]),
+ sample(["breeze", "wind", "smell"]),
+ sample(["lichen", "moss", "fungus"]),
+ rollOddity().description,
+ ][subroll - 1]);
+}
+
+function rollDiscoveryFeature(roll: number = random(1, 12), subroll: number = random(1, 12)): Discovery {
+ return new Discovery(roll, subroll, "feature", [
+ sample(["cave-in", "collapse"]),
+ sample(["pit", "shaft", "chasm"]),
+ sample(["pillars", "columns"]),
+ sample(["locked door", "gate"]),
+ sample(["alcoves", "niches"]),
+ sample(["bridge", "stairs", "ramp"]),
+ sample(["fountain", "well", "pool"]),
+ "puzzle",
+ sample(["altar", "dais", "platform"]),
+ sample(["statue", "idol"]),
+ sample(["magic pool", "statue", "idol"]),
+ "connection to another dungeon",
+ ][subroll - 1]);
+}
+
+function rollDiscoveryFind(roll: number = random(1, 12), subroll: number = random(1, 12)): Discovery {
+ var find = [
+ "trinkets",
+ "tools",
+ sample(["weapons", "armor"]),
+ sample(["supplies", "trade goods"]),
+ sample(["coins", "gems", "jewelry"]),
+ sample(["poisons", "potions"]),
+ sample(["adventurer", "captive"]),
+ "magic item",
+ sample(["scroll", "book"]),
+ sample(["magic weapon", "magic armor"]),
+ "artifact",
+ "[FIND] and [FIND]",
+ ][subroll - 1];
+ find = replace(find, /\[FIND\]/g, () => rollDiscovery(random(1, 11)).description);
+
+ return new Discovery(roll, subroll, "find", find);
+}
+
+
+function rollDanger(roll: number = random(1, 12), subroll: number = random(1, 12)): Danger {
+ if (roll <= 4) {
+ return rollDangerTrap(roll, subroll);
+ } else if (roll <= 11) {
+ return rollDangerCreature(roll, subroll);
+ } else if (roll <= 12) {
+ return rollDangerEntity(roll, subroll);
+ }
+
+ return new Danger(roll, subroll);
+}
+
+function rollDangerTrap(roll: number = random(1, 12), subroll: number = random(1, 12)): Danger {
+ let trap = [
+ "alarm",
+ sample(["ensnaring", "paralyzing"]),
+ "pit",
+ "crushing",
+ sample(["piercing", "puncturing"]),
+ sample(["chopping", "slashing"]),
+ "confusing(maze, etc.)",
+ "gas(poison, etc.)",
+ rollElement().description,
+ "ambush",
+ "magical",
+ "[TRAP] and [TRAP]",
+ ][subroll - 1];
+ trap = replace(trap, /\[TRAP\]/g, () => rollDangerTrap(random(1, 11)).description);
+
+ return new Danger(roll, subroll, "trap", trap);
+}
+
+function rollDangerCreature(roll: number = random(1, 12), subroll: number = random(1, 12)): Danger {
+ let creature = rollCreature();
+ let activity = [
+ "waiting in ambush",
+ sample(["fighting", "squabbling"]),
+ sample(["prowling", "on patrol"]),
+ "looking for food",
+ sample(["eating", "resting"]),
+ "guarding",
+ "on the move",
+ sample(["searching", "scavenging"]),
+ "returning to den",
+ "making plans",
+ "sleeping",
+ "dying",
+ ][subroll - 1];
+ let danger = new Danger(roll, subroll, "creture", `${creature.description} that is ${activity}`);
+ danger.creature = creature;
+
+ return danger;
+}
+
+function rollDangerEntity(roll: number = random(1, 12), subroll: number = random(1, 12)): Danger {
+ return new Danger(roll, subroll, "entity", [
+ "alien interloper",
+ "vermin lord",
+ "criminal mastermind",
+ "warlord",
+ "high priest",
+ "oracle",
+ sample(["wizard", "witch", "alchemist"]),
+ `${rollMonster().description} lord`,
+ sample(["evil spirit", "ghost"]),
+ sample(["undead lord", "lich"]),
+ "demon",
+ "dark god",
+ ][subroll - 1]);
+}
diff --git a/src/rollers/kingdoms.ts b/src/rollers/kingdoms.ts
index 6794f4a..ec65b61 100644
--- a/src/rollers/kingdoms.ts
+++ b/src/rollers/kingdoms.ts
@@ -1,4 +1,4 @@
-import { random } from 'lodash';
+import { random, sample } from 'lodash';
export class Kingdom {
constructor(public description: string = "", public subtitle: string = "") { };
@@ -52,4 +52,11 @@ export function rollKingdom(roll: number = random(1, 4)): Kingdom {
let key = Object.keys(kingdoms)[roll - 1];
return kingdoms[key];
+}
+
+export function rollCategory(kingdom: string = "", category: string = ""): string {
+ if (kingdoms[kingdom] && kingdoms[kingdom][category]) {
+ return sample(kingdoms[kingdom][category]);
+ }
+ return "";
}
\ No newline at end of file
diff --git a/src/rollers/npcs.ts b/src/rollers/npcs.ts
index 06f42c2..f3ecd43 100644
--- a/src/rollers/npcs.ts
+++ b/src/rollers/npcs.ts
@@ -1,4 +1,5 @@
-import { random, sample } from 'lodash';
+import { capitalize, random, sample } from 'lodash';
+import { Activity, Alignment, rollActivity, rollAlignment } from './details';
import { Follower, rollFollower } from './followers';
import { kingdoms, rollKingdom } from './kingdoms';
@@ -7,11 +8,18 @@ export class Npc {
gender: "male" | "female";
hometown: string;
-
context: Context;
occupation: Occupation
trait: Trait;
follower: Follower;
+
+ getDescription(fullDesc: boolean = false) {
+ let str = `${this.name} the ${this.gender} ${capitalize(this.occupation.category)} (${this.occupation.description})`;
+ str += fullDesc ? ` from ${this.hometown}` : '';
+
+ return str;
+ }
+
}
export function rollNpc(): Npc {
@@ -31,7 +39,10 @@ export function rollNpc(): Npc {
}
export class Context {
- constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public subcategory: string = "") { };
+ constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
+ activity?: Activity;
+ alignment?: Alignment;
+ trait?: Trait;
}
export function rollContext(): Context {
@@ -40,71 +51,74 @@ export function rollContext(): Context {
let context = new Context(roll, subroll);
if (roll <= 3) {
context.category = "wilderness";
- context.subcategory = rollWildernessNpc(subroll);
+ context.description = rollWildernessNpc(subroll);
} else if (roll <= 9) {
context.category = "rural";
- context.subcategory = rollRuralNpc(subroll);
+ context.description = rollRuralNpc(subroll);
} else if (roll <= 12) {
context.category = "urban";
- context.subcategory = rollUrbanNpc(subroll);
+ context.description = rollUrbanNpc(subroll);
}
+ context.activity = rollActivity();
+ context.alignment = rollAlignment();
+ context.trait = rollTrait();
return context;
}
export function rollWildernessNpc(roll: number = random(1, 12)): string {
return [
- `${rollCriminal()} -4`,
- `${rollCriminal()} -4`,
- "adventurer/explorer",
- "adventurer/explorer",
- "hunter/gatherer",
- "hunter/gatherer",
- rollCommoner(),
- rollCommoner(),
- "ranger/scout",
- "ranger/scout",
- "soldier/mercenary",
- rollOfficial(),
+ `criminal ${rollCriminal()} -4`,
+ `criminal ${rollCriminal()} -4`,
+ "adventurer",
+ "explorer",
+ "hunter",
+ "gatherer",
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ "ranger",
+ "scout",
+ sample(["soldier", "mercenary"]),
+ `official ${rollOfficial()}`,
][roll - 1];
}
export function rollRuralNpc(roll: number = random(1, 12)): string {
return [
- "beggar/urchin",
- `${rollCriminal()} -1`,
- "adventurer/explorer",
- "hunter/gatherer",
- rollCommoner(),
- rollCommoner(),
- rollCommoner(),
- rollCommoner(),
- rollTradeperson(),
- `${rollMerchant()} -1`,
- "militia/soldier/guard",
- rollOfficial(),
+ sample(["beggar", "urchin"]),
+ `criminal ${rollCriminal()} -1`,
+ sample(["adventurer", "explorer"]),
+ sample(["hunter", "gatherer"]),
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `tradeperson ${rollTradeperson()}`,
+ `merchant ${rollMerchant()} -1`,
+ sample(["militia", "soldier", "guard"]),
+ `official ${rollOfficial()}`,
][roll - 1];
}
export function rollUrbanNpc(roll: number = random(1, 12)): string {
return [
- "beggar/urchin",
- "beggar/urchin",
- rollCriminal(),
- rollCommoner(),
- rollCommoner(),
- rollCommoner(),
- rollCommoner(),
- rollTradeperson(),
- rollMerchant(),
- rollSpecialist(),
- "militia/soldier/guard",
- rollOfficial(),
+ "beggar",
+ "urchin",
+ `commoner ${rollCriminal()}`,
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `commoner ${rollCommoner()}`,
+ `tradeperson ${rollTradeperson()}`,
+ `merchant ${rollMerchant()}`,
+ `specialist ${rollSpecialist()}`,
+ sample(["militia", "soldier", "guard"]),
+ `official ${rollOfficial()}`,
][roll - 1];
}
export class Occupation {
- constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public subcategory: string = "") { };
+ constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
}
export function rollOccupation(roll: number = random(1, 12), subroll: number = random(1, 12)): Occupation {
@@ -112,22 +126,22 @@ export function rollOccupation(roll: number = random(1, 12), subroll: number = r
let occupation = new Occupation(roll, subroll);
if (roll <= 1) {
occupation.category = "criminal";
- occupation.subcategory = rollCriminal(subroll);
+ occupation.description = rollCriminal(subroll);
} else if (roll <= 6) {
occupation.category = "commoner";
- occupation.subcategory = rollCommoner(subroll);
+ occupation.description = rollCommoner(subroll);
} else if (roll <= 8) {
occupation.category = "tradeperson";
- occupation.subcategory = rollTradeperson(subroll);
+ occupation.description = rollTradeperson(subroll);
} else if (roll <= 10) {
occupation.category = "merchant";
- occupation.subcategory = rollMerchant(subroll);
+ occupation.description = rollMerchant(subroll);
} else if (roll <= 11) {
occupation.category = "specialist";
- occupation.subcategory = rollSpecialist(subroll);
+ occupation.description = rollSpecialist(subroll);
} else if (roll <= 12) {
- occupation.category = "officiail";
- occupation.subcategory = rollOfficial(subroll);
+ occupation.category = "official";
+ occupation.description = rollOfficial(subroll);
}
return occupation;
@@ -135,15 +149,15 @@ export function rollOccupation(roll: number = random(1, 12), subroll: number = r
function rollCriminal(roll: number = random(1, 12)): string {
return [
- "bandit/brigand/thug",
- "bandit/brigand/thug",
+ sample(["bandit", "brigand", "thug"]),
+ sample(["bandit", "brigand", "thug"]),
"thief",
"thief",
- "bodyguard/tough",
- "bodyguard/tough",
+ "bodyguard",
+ "tough",
"burglar",
"burglar",
- "dealer/fence",
+ sample(["dealer", "fence"]),
"racketeer",
"lieutenant",
"boss"
@@ -153,66 +167,66 @@ function rollCriminal(roll: number = random(1, 12)): string {
function rollCommoner(roll: number = random(1, 12)): string {
return [
"housewife/husband",
- "hunter/gatherer",
- "hunter/gatherer",
- "farmer/herder",
- "farmer/herder",
- "farmer/herder",
- "laborer/servant",
- "laborer/servant",
- "driver/porter/guide",
- "sailor/soldier/guard",
- "clergy/monk",
- "apprentice/adventurer"
+ "hunter",
+ "gatherer",
+ "farmer",
+ "herder",
+ sample(["farmer", "herder"]),
+ "laborer",
+ "servant",
+ sample(["driver", "porter", "guide"]),
+ sample(["sailor", "soldier", "guard"]),
+ sample(["clergy", "monk"]),
+ sample(["apprentice", "adventurer"]),
][roll - 1];
}
function rollTradeperson(roll: number = random(1, 12)): string {
return [
- "cobbler/furrier/tailor",
- "weaver/basketmaker",
- "potter/carpenter",
- "mason/baker/chandler",
- "cooper/wheelwright",
- "tanner/ropemaker",
- "smith/tinker",
- "stablekeeper/herbalist",
- "vintner/jeweler",
- "inkeeper/tavernkeeper",
- "artist/actor/minstrel",
- "armorer/weaponsmith",
+ sample(["cobbler", "furrier", "tailor"]),
+ sample(["weaver", "basketmaker"]),
+ sample(["potter", "carpenter"]),
+ sample(["mason", "baker", "chandler"]),
+ sample(["cooper", "wheelwright"]),
+ sample(["tanner", "ropemaker"]),
+ sample(["smith", "tinker"]),
+ sample(["stablekeeper", "herbalist"]),
+ sample(["vintner", "jeweler"]),
+ sample(["inkeeper", "tavernkeeper"]),
+ sample(["artist", "actor", "minstrel"]),
+ sample(["armorer", "weaponsmith"]),
][roll - 1];
}
function rollMerchant(roll: number = random(1, 12)): string {
return [
- "general goods/outfitter",
- "general goods/outfitter",
- "general goods/outfitter",
+ "general goods",
+ "outfitter",
+ sample(["general goods", "outfitter"]),
"raw materials",
- "grain/livestock",
- "ale/wine/spirits",
- "clothing/jewelry",
- "weapons/armor",
- "spices/tobacco",
- "labor/slaves",
- "books/scrolls",
- "magic supplies/items"
+ sample(["grain", "livestock"]),
+ sample(["ale", "wine", "spirits"]),
+ sample(["clothing", "jewelry"]),
+ sample(["weapons", "armor"]),
+ sample(["spices", "tobacco"]),
+ sample(["labor", "slaves"]),
+ sample(["books", "scrolls"]),
+ sample(["magic supplies", "magic items"]),
][roll - 1];
}
function rollSpecialist(roll: number = random(1, 12)): string {
return [
"undertaker",
- "sage/scholar/wizard",
- "writer/illuminator",
+ sample(["sage", "scholar", "wizard"]),
+ sample(["writer", "illuminator"]),
"perfumer",
- "architect/engineer",
- "locksmith/clockmaker",
- "physician/apothecary",
- "navigator/guide",
- "alchemist/astrologer",
- "spy/diplomat",
+ sample(["architect", "engineer"]),
+ sample(["locksmith", "clockmaker"]),
+ sample(["physician", "apothecary"]),
+ sample(["navigator", "guide"]),
+ sample(["alchemist", "astrologer"]),
+ sample(["spy", "diplomat"]),
"cartographer",
"inventor"
][roll - 1];
@@ -222,16 +236,16 @@ function rollOfficial(roll: number = random(1, 12)): string {
return [
"town crier",
"tax collector",
- "armiger/gentry",
- "armiger/gentry",
- "reeve/sheriff/constable",
- "mayor/magistrate",
- "priest/bishop/abbot",
+ "armiger",
+ "gentry",
+ sample(["reeve", "sheriff", "constable"]),
+ sample(["mayor", "magistrate"]),
+ sample(["priest", "bishop", "abbot"]),
"guildmaster",
"knightltemplar",
- "elder/high priest",
+ sample(["elder", "high priest"]),
"noble (baron, etc.)",
- "lord/lady/king/queen",
+ sample(["lord", "lady", "king", "queen"]),
][roll - 1];
}
@@ -259,15 +273,15 @@ function rollAppearance(roll: number = random(1, 12)): string {
let appearance = [
"disfigured (missing teeth, eye, etc.)",
"lasting injury (bad leg, arm, etc.)",
- "tattooed/pockmarked/scarred",
- "unkempt/shabby/grubby",
- "big/thick/brawny",
- "small/scrawny/emaciated",
+ sample(["tattooed", "pockmarked", "scarred"]),
+ sample(["unkempt", "shabby", "grubby"]),
+ sample(["big", "thick", "brawny"]),
+ sample(["small", "scrawny", "emaciated"]),
"notable hair (wild, long, none, etc.)",
"notable nose (big, hooked, etc.)",
"notable eyes (blue, bloodshot, etc.)",
- "clean/well-dressed/well-groomed",
- "attractive/handsome/stunning",
+ sample(["clean", "well-dressed", "well-groomed"]),
+ sample(["attractive", "handsome", "stunning"]),
"they are [APPEARANCE] despite [a contradictory detail of your choice]"
][roll - 1];
@@ -276,17 +290,17 @@ function rollAppearance(roll: number = random(1, 12)): string {
export function rollPersonality(roll: number = random(1, 12)): string {
let personality = [
- "loner/alienated/antisocial",
- "cruel/belligerent/bully",
- "anxious/fearful/cowardly",
- "envious/covetous/greedy",
- "aloof/haughty/arrogant",
- "awkward/shy/self-loathing",
- "orderly/compulsive/controlling",
- "confident/impulsive/reckless",
- "kind/generous/compassionate",
- "easygoing/relaxed/peaceful",
- "cheerful/happy/optimistic",
+ sample(["loner", "alienated", "antisocial"]),
+ sample(["cruel", "belligerent", "bully"]),
+ sample(["anxious", "fearful", "cowardly"]),
+ sample(["envious", "covetous", "greedy"]),
+ sample(["aloof", "haughty", "arrogant"]),
+ sample(["awkward", "shy", "self-loathing"]),
+ sample(["orderly", "compulsive", "controlling"]),
+ sample(["confident", "impulsive", "reckless"]),
+ sample(["kind", "generous", "compassionate"]),
+ sample(["easygoing", "relaxed", "peaceful"]),
+ sample(["cheerful", "happy", "optimistic"]),
"they are [PERSONALITY] despite [a contradictory detail of your choice]",
][roll - 1];
@@ -295,17 +309,17 @@ export function rollPersonality(roll: number = random(1, 12)): string {
export function rollQuirk(roll: number = random(1, 12)): string {
let quirk = [
- "insecure/racist/xenophobic",
- "addict (sweets, drugs, sex, etc.)",
- "phobia (spiders, fire, darkness, etc.)",
- "allergic/asthmatic/chronically ill",
- "skeptic/paranoid",
- "superstitious/devout/fanatical",
- "miser/pack-rat",
- "spendthrift/wastrel",
- "smart aleck/know-it-all",
- "artistic/dreamer/delusional",
- "naive/idealistic",
+ sample(["insecure", "racist", "xenophobic"]),
+ sample(["addict (sweets, drugs, sex, etc.)"]),
+ sample(["phobia (spiders, fire, darkness, etc.)"]),
+ sample(["allergic", "asthmatic", "chronically ill"]),
+ sample(["skeptic", "paranoid"]),
+ sample(["superstitious", "devout", "fanatical"]),
+ sample(["miser", "pack-rat"]),
+ sample(["spendthrift", "wastrel"]),
+ sample(["smart aleck", "know-it-all"]),
+ sample(["artistic", "dreamer", "delusional"]),
+ sample(["naive", "idealistic"]),
"they are [QUIRK] despite [a contradictory detail of your choice]",
][roll - 1];
diff --git a/src/rollers/places.ts b/src/rollers/places.ts
index 4821af1..e37ee65 100644
--- a/src/rollers/places.ts
+++ b/src/rollers/places.ts
@@ -1,3 +1,6 @@
+import { sample } from "lodash";
+import { bodgeString } from "./utils";
+
export const places = {
templates: [
'The [PLACE]',
@@ -10,5 +13,11 @@ export const places = {
place: ['Barrier', 'Beach', 'Bowl', 'Camp', 'Cave', 'Circle', 'City', 'Cliff', 'Crater', 'Crossing', 'Crypt', 'Den', 'Ditch', 'Falls', 'Fence', 'Field', 'Fort', 'Gate', 'Grove', 'Hill', 'Hole', 'Hut', 'Keep', 'Lake', 'Marsh', 'Meadow', 'Mountain', 'Pit', 'Post', 'Ridge', 'Ring', 'Rise', 'Road', 'Rock', 'Ruin', 'Shrine', 'Spire', 'Spring', 'Stone', 'Tangle', 'Thmple', 'Throne', 'Tomb', 'Tower', 'Town', 'Tree', 'Vale', 'Valley', 'Village', 'Wall',],
adjective: ['Ancient', 'Ashen', 'Black', 'Bloody', 'Blue', 'Bright', 'Broken', 'Burning', 'Clouded', 'Copper', 'Cracked', 'Dark', 'Dead', 'Doomed', 'Endless', 'Fallen', 'Far', 'Fearsome', 'Floating', 'Forbidden', 'Frozen', 'Ghostly', 'Gloomy', 'Golden', 'Grim', 'Hidden', 'High', 'Iron', 'Jagged', 'Lonely', 'Lost', 'Low', 'Near', 'Petrified', 'Red', 'Screaming', 'Sharp', 'Shattered', 'Shifting', 'Shining', 'Shivering', 'Shrouded', 'Silver', 'Stalwart', 'Stoney', 'Sunken', 'Thorny', 'Thundering', 'White', 'Withered',],
noun: ['[Name]', 'Arm', 'Ash', 'Blood', 'Child', 'Cinder', 'Corpse', 'Crystal', 'Dagger', 'Death', 'Demon', 'Devil', 'Doom', 'Eye', 'Fear', 'Finger', 'Fire', 'Foot', 'Ghost', 'Giant', 'Goblin', 'God', 'Gold', 'Hand', 'Head', 'Heart', 'Hero', 'Hope', 'King', 'Knave', 'Knight', 'Muck', 'Mud', 'Priest', 'Queen', 'Sailor', 'Silver', 'Skull', 'Smoke', 'Souls', 'Spear', 'Spirit', 'Stone', 'Sword', 'Thief', 'Troll', 'Warrior', 'Water', 'Witch', 'Wizard',],
- // * Choose a name appropriate to your setting; or, if you have a name list, roll one up.
-};
\ No newline at end of file
+};
+
+export function rollPlace(): string {
+ let template = sample(places.templates);
+ let place = bodgeString(template, places);
+
+ return place;
+}
\ No newline at end of file
diff --git a/src/rollers/regions.ts b/src/rollers/regions.ts
index 3b80015..e1339ba 100644
--- a/src/rollers/regions.ts
+++ b/src/rollers/regions.ts
@@ -1,3 +1,6 @@
+import { sample } from "lodash";
+import { bodgeString } from "./utils";
+
export const regions = {
templates: [
'[ADJECTIVE] [TERRAIN]',
@@ -10,5 +13,11 @@ export const regions = {
terrain: ['Bay', 'Bluffs', 'Bog', 'Cliffs', 'Desert', 'Downs', 'Dunes', 'Expanse', 'Fells', 'Fen', 'Flats', 'Foothills', 'Forest', 'Groves', 'Heath', 'Heights', 'Hills', 'Hollows', 'Jungle', 'Lake', 'Lowland', 'March', 'Marsh', 'Meadows', 'Moor', 'Morass', 'Mounds', 'Mountains', 'Peaks', 'Plains', 'Prairie', 'Quagmire', 'Range', 'Reach', 'Sands', 'Savanna', 'Scarps', 'Sea', 'Slough', 'Sound', 'Steppe', 'Swamp', 'Sweep', 'Teeth', 'Thicket', 'Upland', 'Wall', 'Waste', 'Wasteland', 'Woods',],
adjective: ['Ageless', 'Ashen', 'Black', 'Blessed', 'Blighted', 'Blue', 'Broken', 'Burning', 'Cold', 'Cursed', 'Dark', 'Dead', 'Deadly', 'Deep', 'Desolate', 'Diamond', 'Dim', 'Dismal', 'Dun', 'Eerie', 'Endless', 'Fallen', 'Far', 'Fell', 'Flaming', 'Forgotten', 'Forsaken', 'Frozen', 'Glittering', 'Golden', 'Green', 'Grim', 'Holy', 'Impassable', 'Jagged', 'Light', 'Long', 'Misty', 'Perilous', 'Purple', 'Red', 'Savage', 'Shadowy', 'Shattered', 'Shifting', 'Shining', 'Silver', 'White', 'Wicked', 'Yellow',],
noun: ['[NAME]', 'Ash', 'Bone', 'Darkness', 'Dead', 'Death', 'Desolation', 'Despair', 'Devil', 'Doom', 'Dragon', 'Fate', 'Fear', 'Fire', 'Fury', 'Ghost', 'Giant', 'God', 'Gold', 'Heaven', 'Hell', 'Honor', 'Hope', 'Horror', 'King', 'Life', 'Light', 'Lord', 'Mist', 'Peril', 'Queen', 'Rain', 'Refuge', 'Regret', 'Savior', 'Shadow', 'Silver', 'Skull', 'Sky', 'Smoke', 'Snake', 'Sorrow', 'Storm', 'Sun', 'Thorn', 'Thunder', 'Traitor', 'Troll', 'Victory', 'Witch',]
- // * Choose a name appropriate to your setting; or, if you have a name list, roll one up. Dw THE MAP
-};
\ No newline at end of file
+};
+
+export function rollRegion(): string {
+ let template = sample(regions.templates);
+ let region = bodgeString(template, regions);
+
+ return region;
+}
\ No newline at end of file
diff --git a/src/rollers/steadings.ts b/src/rollers/steadings.ts
index b3dd5ca..be129c2 100644
--- a/src/rollers/steadings.ts
+++ b/src/rollers/steadings.ts
@@ -1,17 +1,19 @@
import { random, sample } from 'lodash';
+import { Creature, rollCreature } from './creatures';
+import type { Kingdom } from './kingdoms';
export class Steading {
- constructor(public roll: number = 0, public category: string = "") { };
- builtBy: string;
- description: string;
- kingdom: string;
+ constructor(public roll: number = 0, public category: string = "", public description: string = "") { };
+ builtBy: Creature;
+ kingdom: Kingdom;
problem: string;
}
-// This section is gonna need a lot of work
+// TODO: This section is gonna need a lot of work
export function rollSteading(roll: number = random(1, 12)): Steading {
let steading = new Steading();
- // STEADING Choose or roll 1d4 + 4 on the first CREATURE table(page 49) to see who builtit.
+ steading.builtBy = rollCreature(random(1, 4) + 4);
+
if (roll <= 5) {
steading = rollVillage();
} else if (roll <= 8) {
@@ -28,19 +30,19 @@ export function rollSteading(roll: number = random(1, 12)): Steading {
export function rollVillage(): Steading {
- return new Steading(0, "village");
+ return new Steading(0, "village", "village");
}
export function rollTown(): Steading {
- return new Steading(0, "town");
+ return new Steading(0, "town", "town");
}
export function rollKeep(): Steading {
- return new Steading(0, "keep");
+ return new Steading(0, "keep", "keep");
}
export function rollCity(): Steading {
- return new Steading(0, "city");
+ return new Steading(0, "city", "city");
}