made a lot of things better

This commit is contained in:
RussellChamp committed 2021-07-30 19:19:03 -04:00
1 parent d5a1654b22
commit 51948299fa
21 files changed
+1127 -475

No files matched your search

+3 -2
View File
@@ -1,4 +1,5 @@
Add NPC, and Dungeons roll tables Add Steadings tables
Put the rollers in their own accordion slots Change steadings and mounts to not show English names by default
Make everything look nicer 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 Add a 3d dice rolling visualizer
+40 -20
View File
@@ -1,12 +1,15 @@
<script lang="ts"> <script lang="ts">
import { Accordion, AccordionHeader, AccordionItem } from "sveltestrap";
import CreatureRoller from "./rollers/CreatureRoller.svelte"; import CreatureRoller from "./rollers/CreatureRoller.svelte";
import KingdomRoller from "./rollers/KingdomRoller.svelte";
import RegionRoller from "./rollers/RegionRoller.svelte";
import PlaceRoller from "./rollers/PlaceRoller.svelte";
import DangerRoller from "./rollers/DangerRoller.svelte"; import DangerRoller from "./rollers/DangerRoller.svelte";
import DiscoveryRoller from "./rollers/DiscoveryRoller.svelte";
import FollowerRoller from "./rollers/FollowerRoller.svelte";
import DetailsRoller from "./rollers/DetailsRoller.svelte"; import DetailsRoller from "./rollers/DetailsRoller.svelte";
import DiscoveryRoller from "./rollers/DiscoveryRoller.svelte";
import DungeonRoller from "./rollers/DungeonRoller.svelte";
import FollowerRoller from "./rollers/FollowerRoller.svelte";
import KingdomRoller from "./rollers/KingdomRoller.svelte";
import NpcRoller from "./rollers/NpcRoller.svelte";
import PlaceRoller from "./rollers/PlaceRoller.svelte";
import RegionRoller from "./rollers/RegionRoller.svelte";
import Footer from "./componenets/Footer.svelte"; import Footer from "./componenets/Footer.svelte";
</script> </script>
@@ -14,21 +17,38 @@
<h1>The Perilous Wilds</h1> <h1>The Perilous Wilds</h1>
<h2>A web-app for rolling on tables and getting funny results</h2> <h2>A web-app for rolling on tables and getting funny results</h2>
<hr /> <hr />
<KingdomRoller /> <Accordion>
<hr /> <AccordionItem active header="Creatures">
<RegionRoller /> <CreatureRoller />
<hr /> </AccordionItem>
<PlaceRoller /> <AccordionItem header="Dangers">
<hr /> <DangerRoller />
<DangerRoller /> </AccordionItem>
<hr /> <AccordionItem header="Details">
<DiscoveryRoller /> <DetailsRoller />
<hr /> </AccordionItem>
<CreatureRoller /> <AccordionItem header="Discoveries">
<hr /> <DiscoveryRoller />
<FollowerRoller /> </AccordionItem>
<hr /> <AccordionItem header="Dungeons">
<DetailsRoller /> <DungeonRoller />
</AccordionItem>
<AccordionItem header="Followers">
<FollowerRoller />
</AccordionItem>
<AccordionItem header="Kingdoms">
<KingdomRoller />
</AccordionItem>
<AccordionItem header="NPCs">
<NpcRoller />
</AccordionItem>
<AccordionItem header="Places">
<PlaceRoller />
</AccordionItem>
<AccordionItem header="Regions">
<RegionRoller />
</AccordionItem>
</Accordion>
<Footer /> <Footer />
</main> </main>
+51 -10
View File
@@ -1,26 +1,67 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash"; import { capitalize } from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { Button, Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Row } from "sveltestrap";
import { Creature, rollCreature } from "./creatures"; import { Creature, rollCreature } from "./creatures";
export let rollResults: { value: Creature; timestamp: string }[] = []; export let rollResults: { creature: Creature; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let value = rollCreature(); let creature = rollCreature();
console.log("creature", value); rollResults = [{ creature, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
rollResults = [{ value, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
} }
</script> </script>
<main> <main>
<h2>Random Creatures</h2> <Button color="primary" on:click={roll}>Roll Creature</Button>
<button type="button" class="btn btn-primary" on:click={roll}>Roll Creature</button>
{#each rollResults as result} {#each rollResults as { creature, timestamp }}
<h4>{result.timestamp}: {result.value.description}</h4> <Card class="mb-3">
<CardHeader>
<CardTitle>
{capitalize(creature.type)}
{#if creature.subtype !== ""}({creature.subtype}) {/if}: {capitalize(creature.description)}
</CardTitle>
</CardHeader>
<CardBody>
<CardText>
<Container>
<Row>
<strong>Details:</strong>
<ul>
{#if creature.ability}<li>Ability: {creature.ability.description}</li>{/if}
{#if creature.activity}<li>Activity: {creature.activity.description}</li>{/if}
{#if creature.adjective}<li>Adjective: {creature.adjective.description}</li>{/if}
{#if creature.age}<li>Age: {creature.age.description}</li>{/if}
{#if creature.alignment}<li>Alignment: {creature.alignment.description}</li>{/if}
{#if creature.aspect}<li>Aspect: {creature.aspect.description}</li>{/if}
{#if creature.condition}<li>Condition: {creature.condition.description}</li>{/if}
{#if creature.disposition}<li>Disposition: {creature.disposition.description}</li>{/if}
{#if creature.feature}<li>Feature: {creature.feature.description}</li>{/if}
{#if creature.npc}<li>NPC Name: {creature.npc.name}</li>{/if}
{#if creature.numAppearing}<li>Number Appearing: {creature.numAppearing.description}</li>{/if}
{#if creature.size}<li>Size: {creature.size.description}</li>{/if}
{#if creature.tags.length > 0}<li>
Tags: {#each creature.tags as tag} {tag.description}, {/each}
</li>{/if}
</ul>
</Row>
</Container>
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
{/each} {/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
.card-subtitle {
padding-bottom: 1em;
}
ul {
margin-left: 2em;
}
</style> </style>
+6 -6
View File
@@ -1,7 +1,6 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { Icon } from "sveltestrap"; import { Button, Icon } from "sveltestrap";
import { Danger, rollDanger } from "./dangers"; import { Danger, rollDanger } from "./dangers";
export let rollResults: { danger: Danger; icon: string; timestamp: string }[] = []; export let rollResults: { danger: Danger; icon: string; timestamp: string }[] = [];
@@ -21,12 +20,13 @@
</script> </script>
<main> <main>
<h2>Random Danger</h2> <span class="btn">
<button type="button" class="btn btn-primary" on:click={roll}>Roll Danger</button> <Button color="primary" on:click={roll}>Roll Danger</Button>
</span>
{#each rollResults as result} {#each rollResults as { danger, icon, timestamp }}
<h4> <h4>
{result.timestamp}: {result.danger.category} ({result.danger.subcategory}) <Icon name={result.icon} />: {result.danger.description} {timestamp}: {danger.category} ({danger.subcategory}) <Icon name={icon} />: {danger.description}
</h4> </h4>
{/each} {/each}
</main> </main>
+22 -23
View File
@@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { Button, Icon } from "sveltestrap"; import { Button, Icon } from "sveltestrap";
import { import {
@@ -26,72 +25,72 @@
let rollResults: { type: string; value: string; timestamp: string }[] = []; let rollResults: { type: string; value: string; timestamp: string }[] = [];
function addResult(item: { type: string; description: string; roll: number }) { function roll(item: { type: string; description: string; roll: number }) {
rollResults = [{ type: item.type, value: item.description, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; rollResults = [{ type: item.type, value: item.description, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
} }
</script> </script>
<main> <main>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollAbility())}>Roll Ability</Button> <Button color="primary" on:click={() => roll(rollAbility())}>Roll Ability</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollActivity())}>Roll Activity</Button> <Button color="primary" on:click={() => roll(rollActivity())}>Roll Activity</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollAdjective())}>Roll Adjective</Button> <Button color="primary" on:click={() => roll(rollAdjective())}>Roll Adjective</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollAge())}>Roll Age</Button> <Button color="primary" on:click={() => roll(rollAge())}>Roll Age</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollAlignment())}>Roll Alignment</Button> <Button color="primary" on:click={() => roll(rollAlignment())}>Roll Alignment</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollAspect())}>Roll Aspect</Button> <Button color="primary" on:click={() => roll(rollAspect())}>Roll Aspect</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollCondition())}>Roll Condition</Button> <Button color="primary" on:click={() => roll(rollCondition())}>Roll Condition</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollDisposition())}>Roll Disposition</Button> <Button color="primary" on:click={() => roll(rollDisposition())}>Roll Disposition</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollElement())}>Roll Element</Button> <Button color="primary" on:click={() => roll(rollElement())}>Roll Element</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollFeature())}>Roll Feature</Button> <Button color="primary" on:click={() => roll(rollFeature())}>Roll Feature</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollMagicType())}>Roll MagicType</Button> <Button color="primary" on:click={() => roll(rollMagicType())}>Roll MagicType</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollNumAppearing())}>Roll NumAppearing</Button> <Button color="primary" on:click={() => roll(rollNumAppearing())}>Roll NumAppearing</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollOddity())}>Roll Oddity</Button> <Button color="primary" on:click={() => roll(rollOddity())}>Roll Oddity</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollOrientation())}>Roll Orientation</Button> <Button color="primary" on:click={() => roll(rollOrientation())}>Roll Orientation</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollRuination())}>Roll Ruination</Button> <Button color="primary" on:click={() => roll(rollRuination())}>Roll Ruination</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollSize())}>Roll Size</Button> <Button color="primary" on:click={() => roll(rollSize())}>Roll Size</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollTag())}>Roll Tag</Button> <Button color="primary" on:click={() => roll(rollTag())}>Roll Tag</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollTerrain())}>Roll Terrain</Button> <Button color="primary" on:click={() => roll(rollTerrain())}>Roll Terrain</Button>
</span> </span>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => addResult(rollVisibility())}>Roll Visibility</Button> <Button color="primary" on:click={() => roll(rollVisibility())}>Roll Visibility</Button>
</span> </span>
{#each rollResults as result} {#each rollResults as { type, value, timestamp }}
<h4>{result.timestamp}: ({result.type}): {result.value}</h4> <h4>{timestamp}: ({type}): {value}</h4>
{/each} {/each}
</main> </main>
+66 -9
View File
@@ -1,25 +1,82 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash"; import { Button, Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Row, Icon } from "sveltestrap";
import { capitalize } from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { Discovery, rollDiscovery } from "./discoveries"; import { Discovery, rollDiscovery } from "./discoveries";
export let rollResults: { value: Discovery; timestamp: string }[] = []; export let rollResults: { discovery: Discovery; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
rollResults = [{ value: rollDiscovery(), timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; let discovery = rollDiscovery();
rollResults = [{ discovery, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
}
function getIcon(t: string, c: string): string {
return "";
} }
</script> </script>
<main> <main>
<h2>Random Discovery</h2> <span class="btn">
<button type="button" class="btn btn-primary" on:click={roll}>Roll Discovery</button> <Button color="primary" on:click={roll}>Roll Discovery</Button>
</span>
{#each rollResults as result} {#each rollResults as { discovery, timestamp }}
<h4> <Card class="mb-3">
{result.timestamp}: {result.value.category} ({result.value.subcategory}): {result.value.description} <CardHeader>
</h4> <CardTitle
>{capitalize(discovery.category)}{#if discovery.subcategory !== ""}&nbsp;({discovery.subcategory}){/if}: {capitalize(
discovery.description
)}</CardTitle
>
</CardHeader>
<CardBody>
<CardText>
<Container>
{#if discovery.category == "creature"}
<Row>
<p>Are you feeling lucky, punk?</p>
</Row>
{:else if discovery.category == "steading"}
<Row>
<p>TODO: format steadings</p>
</Row>
{:else}
<Row>
<strong>Details:</strong>
<ul>
{#if discovery.age}<li>Age: {discovery.age.description}</li>{/if}
{#if discovery.alignment}<li>Alignment: {discovery.alignment.description}</li>{/if}
{#if discovery.aspect}<li>Aspect: {discovery.aspect.description}</li>{/if}
{#if discovery.creature}<li>Produced/Inhabited By: {discovery.creature.description}</li>{/if}
{#if discovery.element}<li>Element: {discovery.element.description}</li>{/if}
{#if discovery.magicType}<li>MagicType: {discovery.magicType.description}</li>{/if}
{#if discovery.ruination}<li>Ruination: {discovery.ruination.description}</li>{/if}
{#if discovery.size}<li>Size: {discovery.size.description}</li>{/if}
{#if discovery.steading}<li>Steading: {discovery.steading.description}</li>{/if}
{#if discovery.visibility}<li>Visibility: {discovery.visibility.description}</li>{/if}
</ul>
</Row>
{/if}
</Container>
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
{/each} {/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
h2 {
text-align: center;
}
ul {
margin-left: 2em;
}
.btn {
text-align: center;
}
</style> </style>
+103
View File
@@ -0,0 +1,103 @@
<script lang="ts">
import { Button, Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Row, Icon } from "sveltestrap";
import { format as formatDate } from "date-fns";
import { Dungeon, rollDungeon } from "./dungeons";
import { capitalize } from "lodash";
export let rollResults: { dungeon: Dungeon; timestamp: string }[] = [];
function roll(event: Event) {
let dungeon = rollDungeon();
rollResults = [{ dungeon, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
}
function getIcon(t: string, c: string): string {
return t == "discovery"
? "eye-fill"
: t == "danger"
? "exclamation-triangle-fill"
: c == "mundane"
? "exclamation-triangle"
: c == "unusual"
? "exclamation-square"
: c == "extraordinary"
? "exclamation-octagon"
: "";
}
</script>
<main>
<span class="btn">
<Button color="primary" on:click={roll}>Roll Dungeon</Button>
</span>
{#each rollResults as { dungeon, timestamp }}
<Card class="mb-3">
<CardHeader>
<CardTitle
>{capitalize(dungeon.size.description)} {dungeon.function.description} built by (a/an) {dungeon.builder.description}</CardTitle
>
</CardHeader>
<CardBody>
<CardSubtitle>
Fell to ruination from <em>{dungeon.ruination.description}</em>.
</CardSubtitle>
<CardText>
<Container>
<Row>
<strong>Common Themes ({dungeon.size.commonThemes}):</strong>
<ul>
{#each dungeon.commonThemes as theme}
<li><Icon name={getIcon("theme", theme.category)} /> {theme.category}: {theme.description}</li>
{/each}
</ul>
</Row>
<Row>
<strong>Unique Themes ({dungeon.size.uniqueThemes}):</strong>
<ul>
{#each dungeon.uniqueThemes as theme}
<li><Icon name={getIcon("theme", theme.category)} /> {theme.category}: {theme.description}</li>
{/each}
</ul>
</Row>
<Row>
<strong>Common Areas ({dungeon.size.commonAreas}):</strong>
<ul>
{#each dungeon.commonAreas as area}
<li><Icon name={getIcon(area.type, area.category)} /> {area.type}/{area.category}: {area.description}</li>
{/each}
</ul>
</Row>
<Row>
<strong>Unique Areas ({dungeon.size.uniqueAreas}):</strong>
<ul>
{#each dungeon.uniqueAreas as area}
<li><Icon name={getIcon(area.type, area.category)} /> {area.type}/{area.category}: {area.description}</li>
{/each}
</ul>
</Row>
</Container>
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
{/each}
</main>
<style>
main {
text-align: left;
}
h2 {
text-align: center;
}
ul {
margin-left: 2em;
}
.btn {
text-align: center;
}
.card-subtitle {
padding-bottom: 1em;
}
</style>
+18 -20
View File
@@ -1,46 +1,44 @@
<script lang="ts"> <script lang="ts">
import { Button, Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Col, Row } from "sveltestrap"; import { Button, Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Col, Row } from "sveltestrap";
import * as _ from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { rollFollower, Follower } from "./followers"; import { rollFollower, Follower } from "./followers";
export let rollResults: { value: Follower; timestamp: string }[] = []; export let rollResults: { follower: Follower; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let follower = rollFollower(); let follower = rollFollower();
rollResults = [{ value: follower, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; rollResults = [{ follower, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
} }
</script> </script>
<main> <main>
<h2>Random Follower</h2>
<span class="btn"> <span class="btn">
<Button color="primary" on:click={roll}>Roll Followers</Button> <Button color="primary" on:click={roll}>Roll Followers</Button>
</span> </span>
{#each rollResults as result} {#each rollResults as { follower, timestamp }}
<Card class="mb-3"> <Card class="mb-3">
<CardHeader> <CardHeader>
<CardTitle>{result.value.name} ({result.value.gender})</CardTitle> <CardTitle>{follower.name} ({follower.gender})</CardTitle>
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<CardSubtitle> <CardSubtitle>
From <em>{result.value.homeSteading.homesteadName}</em> in <em>{result.value.homeSteading.kingdomName}</em> From <em>{follower.homeSteading.homesteadName}</em> in <em>{follower.homeSteading.kingdomName}</em>
</CardSubtitle> </CardSubtitle>
<CardText> <CardText>
<Container> <Container>
<Row> <Row>
<strong>Quality:</strong> <strong>Quality:</strong>
<p> <p>
They are <em>{result.value.quality.description}</em> (Quality: {result.value.quality.value}). They They are <em>{follower.quality.description}</em> (Quality: {follower.quality.value}). They
<em>{result.value.background.description}</em>. <em>{follower.background.description}</em>.
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Tags:</strong> <strong>Tags:</strong>
<ul> <ul>
{#each result.value.tags as tag} {#each follower.tags as tag}
<li>{tag.name}: {tag.description}</li> <li>{tag.name}: {tag.description}</li>
{/each} {/each}
</ul> </ul>
@@ -48,7 +46,7 @@
<Row> <Row>
<strong>Moves:</strong> <strong>Moves:</strong>
<ul> <ul>
{#each result.value.moves as move} {#each follower.moves as move}
<li>{move.description}</li> <li>{move.description}</li>
{/each} {/each}
</ul> </ul>
@@ -56,44 +54,44 @@
<Row> <Row>
<strong>Loyalty:</strong> <strong>Loyalty:</strong>
<p> <p>
They have a loyalty score of {result.value.loyalty.value}{#if !!result.value.loyalty.description} They have a loyalty score of {follower.loyalty.value}{#if !!follower.loyalty.description}
and <em>{result.value.loyalty.description}</em>{/if}. and <em>{follower.loyalty.description}</em>{/if}.
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Instinct:</strong> <strong>Instinct:</strong>
<p> <p>
When left to their own devices, they will <em>{result.value.instinct.description}</em>. When left to their own devices, they will <em>{follower.instinct.description}</em>.
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Cost:</strong> <strong>Cost:</strong>
<p> <p>
They are motivated by <em>{result.value.cost.name}</em>. They will want <em>{result.value.cost.description}</em> They are motivated by <em>{follower.cost.name}</em>. They will want <em>{follower.cost.description}</em>
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Hit Points:</strong> <strong>Hit Points:</strong>
<p> <p>
They are <em>{result.value.hitPoints.description}</em> and have {result.value.hitPoints.value} HP. They are <em>{follower.hitPoints.description}</em> and have {follower.hitPoints.value} HP.
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Armor & Shield:</strong> <strong>Armor & Shield:</strong>
<p> <p>
They are equipped with <em>{result.value.armor.description}</em> ({result.value.armor.value} armor). They are equipped with <em>{follower.armor.description}</em> ({follower.armor.value} armor).
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Damage:</strong> <strong>Damage:</strong>
<p> <p>
In a fight, they <em>{result.value.damage.description}</em> dealing <em>d{result.value.damage.value}</em> damage. In a fight, they <em>{follower.damage.description}</em> dealing <em>d{follower.damage.value}</em> damage.
</p> </p>
</Row> </Row>
<Row> <Row>
<strong>Load & Gear:</strong> <strong>Load & Gear:</strong>
<ul> <ul>
{#each result.value.loadAndGear.gear as gear} {#each follower.loadAndGear.gear as gear}
<li>{gear}</li> <li>{gear}</li>
{/each} {/each}
</ul> </ul>
@@ -101,7 +99,7 @@
</Container> </Container>
</CardText> </CardText>
</CardBody> </CardBody>
<CardFooter>{result.timestamp}</CardFooter> <CardFooter>{timestamp}</CardFooter>
</Card> </Card>
{/each} {/each}
</main> </main>
+8 -12
View File
@@ -1,25 +1,21 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash"; import { capitalize } from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { Button, Icon } from "sveltestrap"; import { Button, Icon } from "sveltestrap";
import { kingdoms } from "./kingdoms"; import { kingdoms, rollCategory } from "./kingdoms";
let rollResults: { value: string; icon: string; timestamp: string }[] = []; let rollResults: { value: string; icon: string; timestamp: string }[] = [];
let kingdom = "arpad"; let kingdom = "arpad";
let categories: string[]; let categories: string[];
function addResult(value: string, category: string) { function roll(category: string) {
let value = rollCategory(kingdom, category);
let icon = { male: "person-fill", female: "person", steading: "house-door-fill", mount: "bicycle" }[category] || ""; let icon = { male: "person-fill", female: "person", steading: "house-door-fill", mount: "bicycle" }[category] || "";
rollResults = [{ value, icon, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; rollResults = [{ value, icon, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
} }
function rollName(category: string) {
let values = kingdoms[kingdom][category];
addResult(_.sample(values), category);
}
$: categories = kingdoms[kingdom].categories; $: categories = kingdoms[kingdom].categories;
</script> </script>
@@ -35,12 +31,12 @@
{#each categories as category} {#each categories as category}
<span class="btn"> <span class="btn">
<Button color="primary" on:click={() => rollName(category)}>Roll {_.capitalize(category)}</Button> <Button color="primary" on:click={() => roll(category)}>Roll {capitalize(category)}</Button>
</span> </span>
{/each} {/each}
{#each rollResults as result} {#each rollResults as { value, icon, timestamp }}
<h4>{result.timestamp}: <Icon name={result.icon} /> {result.value}</h4> <h4>{timestamp}: <Icon name={icon} /> {value}</h4>
{/each} {/each}
</main> </main>
+85
View File
@@ -0,0 +1,85 @@
<script lang="ts">
import {
Button,
Card,
CardHeader,
CardTitle,
CardBody,
CardSubtitle,
CardText,
CardFooter,
Container,
Col,
Row,
Icon,
} from "sveltestrap";
import { capitalize } from "lodash";
import { format as formatDate } from "date-fns";
import { Npc, rollNpc } from "./npcs";
export let rollResults: { npc: Npc; timestamp: string }[] = [];
function roll(event: Event) {
let npc = rollNpc();
rollResults = [{ npc, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
}
function getIcon(t: string, c: string): string {
return "";
}
</script>
<main>
<span class="btn">
<Button color="primary" on:click={roll}>Roll Npc</Button>
</span>
{#each rollResults as { npc, timestamp }}
<Card class="mb-3">
<CardHeader>
<CardTitle>{npc.getDescription()}</CardTitle>
</CardHeader>
<CardBody>
<CardSubtitle>
From <em>{npc.hometown}</em>.
</CardSubtitle>
<CardText>
<Container>
<Row>
<strong>Background Context:</strong>
<ul>
<li>
They are a(n) <em>{npc.context.alignment.description}</em> <em>{npc.context.description}</em> with
<em>{npc.trait.category} ({npc.context.trait.description})</em>
encountered in a(n) <em>{npc.context.category}</em> setting while they are <em>{npc.context.activity.description}</em>
</li>
</ul>
</Row>
<Row>
<strong>Follower Stats:</strong>
<ul>
<li>{npc.follower.name}</li>
</ul>
</Row>
</Container>
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
{/each}
</main>
<style>
main {
text-align: left;
}
ul {
margin-left: 2em;
}
.btn {
text-align: center;
}
.card-subtitle {
padding-bottom: 1em;
}
</style>
+10 -15
View File
@@ -1,28 +1,23 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { places } from "./places"; import { Button } from "sveltestrap";
import { bodgeString } from "./utils"; import { rollPlace } from "./places";
export let rollResults: { value: string; timestamp: string }[] = []; export let rollResults: { place: string; timestamp: string }[] = [];
function addResult(result: string) {
rollResults = [{ value: result, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
}
function roll(event: Event) { function roll(event: Event) {
let template = _.sample(places.templates); let place = rollPlace();
rollResults = [{ place, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
addResult(bodgeString(template, places));
} }
</script> </script>
<main> <main>
<h2>Random Places</h2> <span class="btn">
<button type="button" class="btn btn-primary" on:click={roll}>Roll Region</button> <Button color="primary" on:click={roll}>Roll Place</Button>
</span>
{#each rollResults as result} {#each rollResults as { place, timestamp }}
<h4>{result.timestamp}: {result.value}</h4> <h4>{timestamp}: {place}</h4>
{/each} {/each}
</main> </main>
+10 -15
View File
@@ -1,28 +1,23 @@
<script lang="ts"> <script lang="ts">
import * as _ from "lodash";
import { format as formatDate } from "date-fns"; import { format as formatDate } from "date-fns";
import { regions } from "./regions"; import { Button } from "sveltestrap";
import { bodgeString } from "./utils"; import { rollRegion } from "./regions";
export let rollResults: { value: string; timestamp: string }[] = []; export let rollResults: { region: string; timestamp: string }[] = [];
function addResult(result: string) {
rollResults = [{ value: result, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
}
function roll(event: Event) { function roll(event: Event) {
let template = _.sample(regions.templates); let region = rollRegion();
rollResults = [{ region, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
addResult(bodgeString(template, regions));
} }
</script> </script>
<main> <main>
<h2>Random Regions</h2> <span class="btn">
<button type="button" class="btn btn-primary" on:click={roll}>Roll Region</button> <Button color="primary" on:click={roll}>Roll Region</Button>
</span>
{#each rollResults as result} {#each rollResults as { region, timestamp }}
<h4>{result.timestamp}: {result.value}</h4> <h4>{timestamp}: {region}</h4>
{/each} {/each}
</main> </main>
+42 -77
View File
@@ -1,49 +1,59 @@
import { random, sample } from 'lodash'; import { random, sample } from 'lodash';
import { rollUnnaturalEntity } from './dangers'; import { rollUnnaturalEntity } from './dangers';
import { Activity, Disposition, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size } from './details'; import { Ability, Activity, Adjective, Age, Alignment, Aspect, Condition, Disposition, Feature, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size, Tag } from './details';
import { rollNpc } from './npcs'; import { Npc, rollNpc } from './npcs';
export class Creature { 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 = "") { }; 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)) { 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) { if (roll <= 4) {
return rollBeast(roll, subroll, specificroll); return rollBeast(roll, subroll, specificroll);
} else if (roll <= 6) { } else if (roll <= 6) {
creature.type = "human"; let human = new Creature(roll, subroll, specificroll);
let npc = rollNpc(); human.type = "human";
creature.description = `${npc.name} the ${npc.gender} ${npc.occupation.subcategory} from ${npc.hometown}`; human.npc = rollNpc();
creature.details = [ human.description = human.npc.getDescription(true);
rollActivity().description, human.activity = rollActivity();
rollAlignment().description, human.alignment = rollAlignment();
rollDisposition().description, human.disposition = rollDisposition();
rollNumAppearing().description, human.numAppearing = rollNumAppearing();
npc.name /* TODO: figure out how to do this */
]; return human;
} else if (roll <= 8) { } else if (roll <= 8) {
return rollHumanoid(roll, subroll, specificroll); return rollHumanoid(roll, subroll, specificroll);
} else if (roll <= 12) { } else if (roll <= 12) {
return rollMonster(); 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 { 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); let creature = new Creature(roll, subroll, specificroll);
creature.type = "beast"; creature.type = "beast";
creature.details = [ creature.activity = rollActivity();
rollActivity().description, creature.disposition = rollDisposition();
rollDisposition().description, creature.numAppearing = rollNumAppearing();
rollNumAppearing().description, creature.size = rollSize();
rollSize().description
];
if (subroll <= 7) { if (subroll <= 7) {
creature.subtype = "earthbound"; 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 { 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"); let creature = new Creature(roll, subroll, specificroll, "humanoid");
creature.details = [ creature.activity = rollActivity();
rollActivity().description, creature.alignment = rollAlignment();
rollAlignment().description, creature.disposition = rollDisposition();
rollDisposition().description, creature.numAppearing = rollNumAppearing();
rollNumAppearing().description, creature.npc = rollNpc(); /* figure out how to do this */
rollNpc().name /* figure out how to do this */
];
if (subroll <= 7) { if (subroll <= 7) {
creature.subtype = "common"; 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 { 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"); let creature = new Creature(roll, subroll, specificroll, "monster");
creature.details = [
rollActivity().description, creature.activity = rollActivity();
rollAlignment().description, creature.alignment = rollAlignment();
rollDisposition().description, creature.disposition = rollDisposition();
rollNumAppearing().description, creature.numAppearing = rollNumAppearing();
rollSize().description, creature.size = rollSize();
];
if (subroll <= 7) { if (subroll <= 7) {
creature.subtype = "unusual"; creature.subtype = "unusual";
@@ -258,45 +265,3 @@ export function rollLegendaryMonster(roll: number = random(1, 12)): string {
return ""; 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
+75 -75
View File
@@ -8,17 +8,17 @@ export class Ability {
export function rollAbility(roll: number = random(1, 12)): Ability { export function rollAbility(roll: number = random(1, 12)): Ability {
let ability = new Ability(roll); let ability = new Ability(roll);
ability.description = [ ability.description = [
"bless/curse", sample(["bless", "curse"]),
"entangle/trap/snare", sample(["entangle", "trap", "snare"]),
"poison/disease", sample(["poison", "disease"]),
"paralyze/petrify", sample(["paralyze", "petrify"]),
"mimic/camouflage", sample(["mimic", "camouflage"]),
"seduce/hypnotize", sample(["seduce", "hypnotize"]),
"dissolve/disintegrate", sample(["dissolve", "disintegrate"]),
rollMagicType().description, rollMagicType().description,
"drain life/magic", sample(["drain life", "drain magic"]),
`immunity to ${rollElement().description}`, `immunity to ${rollElement().description}`,
"read/control minds", sample(["read minds", "control minds"]),
"[ABILITY] and [ABILITY]" "[ABILITY] and [ABILITY]"
][roll - 1]; ][roll - 1];
ability.description = replace(ability.description, /\[ABILITY\]/g, () => rollAbility(random(1, 11)).description); 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 { export function rollActivity(roll: number = random(1, 12)): Activity {
let activity = new Activity(roll); let activity = new Activity(roll);
activity.description = [ activity.description = [
"laying trap/ambush", sample(["laying trap", "ambush"]),
"fighting/at war", sample(["fighting", "at war"]),
"prowling/on patrol", sample(["prowling", "on patrol"]),
"hunting/foraging", sample(["hunting", "foraging"]),
"eating/resting", sample(["eating", "resting"]),
"crafting/praying", sample(["crafting", "praying"]),
"traveling/relocating", sample(["traveling", "relocating"]),
"exploring/lost", sample(["exploring", "lost"]),
"returning home", "returning home",
"building/excavating", sample(["building", "excavating"]),
"sleeping", "sleeping",
"dying", "dying",
][roll - 1]; ][roll - 1];
@@ -59,17 +59,17 @@ export class Adjective {
export function rollAdjective(roll: number = random(1, 12)): Adjective { export function rollAdjective(roll: number = random(1, 12)): Adjective {
let adjective = new Adjective(roll); let adjective = new Adjective(roll);
adjective.description = [ adjective.description = [
"slick/slimy", sample(["slick", "slimy"]),
"rough/hard/sharp", sample(["rough", "hard", "sharp"]),
"smooth/soft/dull", sample(["smooth", "soft", "dull"]),
"corroded/rusty", sample(["corroded", "rusty"]),
"rotten/decaying", sample(["rotten", "decaying"]),
"broken/brittle", sample(["broken", "brittle"]),
"stinking/smelly", sample(["stinking", "smelly"]),
"weak/thin/drained", sample(["weak", "thin", "drained"]),
"strong/fat/full", sample(["strong", "fat", "full"]),
"pale/poor/shallow", sample(["pale", "poor", "shallow"]),
"dark/rich/deep", sample(["dark", "rich", "deep"]),
"colorful", "colorful",
][roll - 1]; ][roll - 1];
@@ -132,16 +132,16 @@ export class Aspect {
export function rollAspect(roll: number = random(1, 12)): Aspect { export function rollAspect(roll: number = random(1, 12)): Aspect {
let aspect = new Aspect(roll); let aspect = new Aspect(roll);
aspect.description = [ aspect.description = [
"power/strength", sample(["power", "strength"]),
"trickery/dexterity", sample(["trickery", "dexterity"]),
"time/constitution", sample(["time", "constitution"]),
"knowledge/intelligence", sample(["knowledge", "intelligence"]),
"nature/wisdom", sample(["nature", "wisdom"]),
"culture/charisma", sample(["culture", "charisma"]),
"war/lies/discord", sample(["war", "lies", "discord"]),
"peace/truth/balance", sample(["peace", "truth", "balance"]),
"hate/envy", sample(["hate", "envy"]),
"love/admiration", sample(["love", "admiration"]),
rollElement().description, rollElement().description,
"[ASPECT] and [ASPECT]" "[ASPECT] and [ASPECT]"
][roll - 1]; ][roll - 1];
@@ -159,19 +159,19 @@ export function rollCondition(roll: number = random(1, 12)): Condition {
let condition = new Condition(roll); let condition = new Condition(roll);
if (roll <= 1) { if (roll <= 1) {
condition.description = "being built/born"; condition.description = sample(["being built", "being born"]);
} else if (roll <= 4) { } else if (roll <= 4) {
condition.description = "intact/healthy/stable"; condition.description = sample(["intact", "healthy", "stable"]);
} else if (roll <= 7) { } else if (roll <= 7) {
condition.description = "occupied/active/alert"; condition.description = sample(["occupied", "active", "alert"]);
} else if (roll <= 9) { } else if (roll <= 9) {
condition.description = "worn/tired/weak"; condition.description = sample(["worn", "tired", "weak"]);
} else if (roll <= 10) { } else if (roll <= 10) {
condition.description = "vacant/lost"; condition.description = sample(["vacant", "lost"]);
} else if (roll <= 11) { } else if (roll <= 11) {
condition.description = "ruined/defiled/dying"; condition.description = sample(["ruined", "defiled", "dying"]);
} else if (roll <= 12) { } else if (roll <= 12) {
condition.description = "disappeared/dead"; condition.description = sample(["disappeared", "dead"]);
} }
return condition; return condition;
@@ -188,15 +188,15 @@ export function rollDisposition(roll: number = random(1, 12)): Disposition {
if (roll <= 1) { if (roll <= 1) {
disposition.description = "attacking"; disposition.description = "attacking";
} else if (roll <= 4) { } else if (roll <= 4) {
disposition.description = "hostile/aggressive"; disposition.description = sample(["hostile", "aggressive"]);
} else if (roll <= 6) { } else if (roll <= 6) {
disposition.description = "cautious/doubtful"; disposition.description = sample(["cautious", "doubtful"]);
} else if (roll <= 7) { } else if (roll <= 7) {
disposition.description = "fearful/fleeing"; disposition.description = sample(["fearful", "fleeing"]);
} else if (roll <= 10) { } else if (roll <= 10) {
disposition.description = "neutral"; disposition.description = "neutral";
} else if (roll <= 11) { } else if (roll <= 11) {
disposition.description = "curious/hopeful"; disposition.description = sample(["curious", "hopeful"]);
} else if (roll <= 12) { } else if (roll <= 12) {
disposition.description = "friendly"; disposition.description = "friendly";
} }
@@ -242,13 +242,13 @@ export function rollFeature(roll: number = random(1, 12)): Feature {
} else if (roll <= 3) { } else if (roll <= 3) {
feature.description = "winged/flying"; feature.description = "winged/flying";
} else if (roll <= 4) { } else if (roll <= 4) {
feature.description = "multiple heads/headless"; feature.description = sample(["multiple heads", "headless"]);
} else if (roll <= 5) { } else if (roll <= 5) {
feature.description = "many eyes/one eye"; feature.description = sample(["many eyes", "one eye"]);
} else if (roll <= 6) { } else if (roll <= 6) {
feature.description = "many limbs/tails"; feature.description = sample(["many limbs", "tails"]);
} else if (roll <= 7) { } else if (roll <= 7) {
feature.description = "tentacles/tendrils"; feature.description = sample(["tentacles", "tendrils"]);
} else if (roll <= 8) { } else if (roll <= 8) {
feature.description = rollAspect().description; feature.description = rollAspect().description;
} else if (roll <= 9) { } else if (roll <= 9) {
@@ -317,15 +317,15 @@ export class Oddity {
export function rollOddity(roll: number = random(1, 12)): Oddity { export function rollOddity(roll: number = random(1, 12)): Oddity {
let oddity = new Oddity(roll); let oddity = new Oddity(roll);
oddity.description = [ oddity.description = [
"weird color/smell/sound", sample(["weird color", "smell", "sound"]),
"geometric", "geometric",
"web/network/system", sample(["web", "network", "system"]),
"crystalline/glass-like", sample(["crystalline", "glass-like"]),
"fungal", "fungal",
"gaseous/smokey", sample(["gaseous", "smokey"]),
"mirage/illusion", sample(["mirage", "illusion"]),
"volcanic/explosive", sample(["volcanic", "explosive"]),
"magnetic/repellant", sample(["magnetic", "repellant"]),
"devoid of life", "devoid of life",
"unexpectedly alive", "unexpectedly alive",
"[ODDITY] and [ODDITY]", "[ODDITY] and [ODDITY]",
@@ -379,15 +379,15 @@ export function rollRuination(roll: number = random(1, 12)): Ruination {
if (roll <= 1) { if (roll <= 1) {
ruination.description = "arcane disaster"; ruination.description = "arcane disaster";
} else if (roll <= 2) { } else if (roll <= 2) {
ruination.description = "damnation/curse"; ruination.description = sample(["damnation", "curse"]);
} else if (roll <= 4) { } else if (roll <= 4) {
ruination.description = "earthquake/fire/flood"; ruination.description = sample(["earthquake", "fire", "flood"]);
} else if (roll <= 6) { } else if (roll <= 6) {
ruination.description = "plague/famine/drought"; ruination.description = sample(["plague", "famine", "drought"]);
} else if (roll <= 8) { } else if (roll <= 8) {
ruination.description = "overrun by monsters"; ruination.description = "overrun by monsters";
} else if (roll <= 10) { } else if (roll <= 10) {
ruination.description = "war/invasion"; ruination.description = sample(["war", "invasion"]);
} else if (roll <= 11) { } else if (roll <= 11) {
ruination.description = "depleted resources"; ruination.description = "depleted resources";
} else if (roll <= 12) { } else if (roll <= 12) {
@@ -463,19 +463,19 @@ export function rollTerrain(roll: number = random(1, 12)): Terrain {
let terrain = new Terrain(roll); let terrain = new Terrain(roll);
if (roll <= 1) { if (roll <= 1) {
terrain.description = "wasteland/desert"; terrain.description = sample(["wasteland", "desert"]);
} else if (roll <= 3) { } else if (roll <= 3) {
terrain.description = "flatland/plain"; terrain.description = sample(["flatland", "plain"]);
} else if (roll <= 4) { } else if (roll <= 4) {
terrain.description = "wetland/marsh/swamp"; terrain.description = sample(["wetland", "marsh", "swamp"]);
} else if (roll <= 7) { } else if (roll <= 7) {
terrain.description = "woodland/forest/jungle"; terrain.description = sample(["woodland", "forest", "jungle"]);
} else if (roll <= 9) { } else if (roll <= 9) {
terrain.description = "highland/hills"; terrain.description = sample(["highland", "hills"]);
} else if (roll <= 11) { } else if (roll <= 11) {
terrain.description = "mountains"; terrain.description = "mountains";
} else if (roll <= 12) { } else if (roll <= 12) {
terrain.description = rollOddity().description; terrain.description = `${rollOddity().description} oddity`;
} }
return terrain; return terrain;
@@ -490,15 +490,15 @@ export function rollVisibility(roll: number = random(1, 12)): Visibility {
let visibility = new Visibility(roll); let visibility = new Visibility(roll);
if (roll <= 2) { if (roll <= 2) {
visibility.description = "buried/camouflaged/nigh invisible"; visibility.description = sample(["buried", "camouflaged", "nigh invisible"]);
} else if (roll <= 6) { } else if (roll <= 6) {
visibility.description = "partly covered/overgrown/hidden"; visibility.description = sample(["partly covered", "partly overgrown", "partly hidden"]);
} else if (roll <= 9) { } else if (roll <= 9) {
visibility.description = "obvious/in plain sight"; visibility.description = sample(["obvious", "in plain sight"]);
} else if (roll <= 11) { } else if (roll <= 11) {
visibility.description = "visible at near distance"; visibility.description = "visible at near distance";
} else if (roll <= 12) { } else if (roll <= 12) {
visibility.description = "visible at great distance/focal point"; visibility.description = sample(["visible at great distance", "focal point"]);
} }
return visibility; return visibility;
+65 -30
View File
@@ -1,14 +1,23 @@
import { random, sample } from 'lodash'; import { random, sample } from 'lodash';
import { Creature, rollCreature } from './creatures'; 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 { rollDungeon } from './dungeons';
import { rollSteading, Steading } from './steadings'; import { rollSteading, Steading } from './steadings';
import { rollTreasure } from './treasures'; import { rollTreasure } from './treasures';
export class Discovery { 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 = "") { }; 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; creature?: Creature;
element?: Element;
magicType?: MagicType;
ruination?: Ruination;
size?: Size;
steading?: Steading; steading?: Steading;
visibility?: Visibility;
} }
export function rollDiscovery() { export function rollDiscovery() {
@@ -37,12 +46,18 @@ export function rollUnnaturalFeature(roll: number = random(1, 12), subroll: numb
if (subroll <= 9) { if (subroll <= 9) {
discovery.subcategory = "arcane"; discovery.subcategory = "arcane";
discovery.description = rollArcaneFeature(specificroll); discovery.description = rollArcaneFeature(specificroll);
discovery.alignment = rollAlignment();
discovery.magicType = rollMagicType();
} else if (subroll <= 11) { } else if (subroll <= 11) {
discovery.subcategory = "planar"; discovery.subcategory = "planar";
discovery.description = rollPlanarFeature(specificroll); discovery.description = rollPlanarFeature(specificroll);
discovery.alignment = rollAlignment();
discovery.element = rollElement();
} else if (subroll <= 12) { } else if (subroll <= 12) {
discovery.subcategory = "divine"; discovery.subcategory = "divine";
discovery.description = rollDivineFeature(specificroll); discovery.description = rollDivineFeature(specificroll);
discovery.alignment = rollAlignment();
discovery.aspect = rollAspect();
} }
return discovery; return discovery;
@@ -107,7 +122,9 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
if (subroll <= 2) { if (subroll <= 2) {
discovery.subcategory = "lair"; discovery.subcategory = "lair";
discovery.description = rollLair(specificroll) discovery.description = rollLair(specificroll);
discovery.creature = rollCreature();
discovery.visibility = rollVisibility();
} else if (subroll <= 4) { } else if (subroll <= 4) {
discovery.subcategory = "obstacle"; discovery.subcategory = "obstacle";
discovery.description = rollObstacle(specificroll); discovery.description = rollObstacle(specificroll);
@@ -121,8 +138,10 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
discovery.subcategory = "terrain change"; discovery.subcategory = "terrain change";
discovery.description = rollLandmark(specificroll); discovery.description = rollLandmark(specificroll);
} else if (subroll <= 12) { } else if (subroll <= 12) {
discovery.subcategory = "terrain change"; discovery.subcategory = "resource";
discovery.description = rollResource(specificroll); discovery.description = rollResource(specificroll);
discovery.size = rollSize();
discovery.visibility = rollVisibility();
} }
return discovery; return discovery;
@@ -148,9 +167,9 @@ export function rollObstacle(roll: number = random(1, 12)): string {
if (roll <= 5) { if (roll <= 5) {
return "difficult ground"; return "difficult ground";
} else if (roll <= 8) { } else if (roll <= 8) {
return "cliff/crevasse/chasm"; return sample(["cliff", "crevasse", "chasm"]);
} else if (roll <= 10) { } else if (roll <= 10) {
return "ravine/gorge"; return sample(["ravine", "gorge"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return rollOddity().description; 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 { export function rollTerrainChange(roll: number = random(1, 12)): string {
if (roll <= 4) { if (roll <= 4) {
return `limited area of ${rollTerrain()}`; return `limited area of ${rollTerrain().description}`;
} else if (roll <= 6) { } else if (roll <= 6) {
return "crevice/hole/pit/cave"; return sample(["crevice", "hole", "pit", "cave"]);
} else if (roll <= 8) { } else if (roll <= 8) {
return "altitude change"; return "altitude change";
} else if (roll <= 10) { } else if (roll <= 10) {
return "canyon/valley"; return sample(["canyon", "valley"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return "rise/peak in distance"; return sample(["rise", "peak in distance"]);
} }
return ""; return "";
@@ -176,17 +195,17 @@ export function rollTerrainChange(roll: number = random(1, 12)): string {
export function rollWaterFeature(roll: number = random(1, 12)): string { export function rollWaterFeature(roll: number = random(1, 12)): string {
if (roll <= 1) { if (roll <= 1) {
return "spring/hotspring"; return sample(["spring", "hotspring"]);
} else if (roll <= 2) { } else if (roll <= 2) {
return "waterfall/geyser"; return sample(["waterfall", "geyser"]);
} else if (roll <= 6) { } else if (roll <= 6) {
return "creek/stream/brook"; return sample(["creek", "stream", "brook"]);
} else if (roll <= 8) { } else if (roll <= 8) {
return "pond/lake"; return sample(["pond", "lake"]);
} else if (roll <= 10) { } else if (roll <= 10) {
return "river"; return "river";
} else if (roll <= 12) { } else if (roll <= 12) {
return "sea/ocean"; return sample(["sea", "ocean"]);
} }
return ""; return "";
@@ -208,15 +227,15 @@ export function rollLandmark(roll: number = random(1, 12)): string {
export function rollResource(roll: number = random(1, 12)): string { export function rollResource(roll: number = random(1, 12)): string {
if (roll <= 4) { if (roll <= 4) {
return "game/fruit/vegetable"; return sample(["game", "fruit", "vegetable"]);
} else if (roll <= 6) { } else if (roll <= 6) {
return "herb/spice/dye source"; return sample(["herb", "spice", "dye source"]);
} else if (roll <= 9) { } else if (roll <= 9) {
return "timber/stone"; return sample(["timber", "stone"]);
} else if (roll <= 11) { } else if (roll <= 11) {
return "ore (copper, iron, etc.)"; return sample(["copper ore", "iron ore", "tin ore", "silver ore"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return "precious metal/gems"; return sample(["precious metal", "precious gems"]);
} }
return ""; return "";
@@ -228,9 +247,13 @@ function rollEvidence(roll: number = random(1, 12), subroll: number = random(1,
if (subroll <= 6) { if (subroll <= 6) {
discovery.subcategory = "tracks/spoor"; discovery.subcategory = "tracks/spoor";
discovery.description = rollTracksSpoor(specificroll); discovery.description = rollTracksSpoor(specificroll);
discovery.age = rollAge();
discovery.creature = rollCreature();
} else if (subroll <= 10) { } else if (subroll <= 10) {
discovery.subcategory = "remains/debris"; discovery.subcategory = "remains/debris";
discovery.description = rollRemainsDebris(specificroll); discovery.description = rollRemainsDebris(specificroll);
discovery.age = rollAge();
discovery.visibility = rollVisibility();
} else if (subroll <= 12) { } else if (subroll <= 12) {
discovery.subcategory = "stash/cache"; discovery.subcategory = "stash/cache";
discovery.description = rollStashCache(specificroll); discovery.description = rollStashCache(specificroll);
@@ -305,15 +328,23 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
if (subroll <= 1) { if (subroll <= 1) {
discovery.subcategory = "enigmatic"; discovery.subcategory = "enigmatic";
discovery.description = rollEnigmaticStructure(specificroll); 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) { } else if (subroll <= 3) {
discovery.subcategory = "infrastructure"; discovery.subcategory = "infrastructure";
discovery.description = rollInfrastructureStructure(specificroll); discovery.description = rollInfrastructureStructure(specificroll);
discovery.creature = rollCreature(random(1, 4) + 4);
} else if (subroll <= 4) { } else if (subroll <= 4) {
discovery.subcategory = "dwelling"; discovery.subcategory = "dwelling";
discovery.description = rollDwellingStructure(specificroll); discovery.description = rollDwellingStructure(specificroll);
discovery.creature = rollCreature(random(1, 4) + 4);
} else if (subroll <= 6) { } else if (subroll <= 6) {
discovery.subcategory = "burial/religious"; discovery.subcategory = "burial/religious";
discovery.description = rollBurialReligiousStructure(specificroll); discovery.description = rollBurialReligiousStructure(specificroll);
discovery.creature = rollCreature(random(1, 4) + 4);
discovery.alignment = rollAlignment();
discovery.aspect = rollAspect();
} else if (subroll <= 8) { } else if (subroll <= 8) {
discovery.subcategory = "steading"; discovery.subcategory = "steading";
discovery.steading = rollSteading(); discovery.steading = rollSteading();
@@ -322,6 +353,10 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
} else if (subroll <= 12) { } else if (subroll <= 12) {
discovery.subcategory = "ruin"; discovery.subcategory = "ruin";
discovery.description = rollRuinStructure(specificroll); 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; return discovery;
@@ -343,15 +378,15 @@ export function rollEnigmaticStructure(roll: number = random(1, 12)): string {
export function rollInfrastructureStructure(roll: number = random(1, 12)): string { export function rollInfrastructureStructure(roll: number = random(1, 12)): string {
if (roll <= 4) { if (roll <= 4) {
return "track/path"; return sample(["track", "path"]);
} else if (roll <= 8) { } else if (roll <= 8) {
return "road"; return "road";
} else if (roll <= 10) { } else if (roll <= 10) {
return "bridge/ford"; return sample(["bridge", "ford"]);
} else if (roll <= 11) { } else if (roll <= 11) {
return "mine/quarry"; return sample(["mine", "quarry"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return "aqueduct/canal/portal"; return sample(["aqueduct", "canal", "portal"]);
} }
return ""; return "";
@@ -361,13 +396,13 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
if (roll <= 3) { if (roll <= 3) {
return "campsite"; return "campsite";
} else if (roll <= 6) { } else if (roll <= 6) {
return "hovel/hut"; return sample(["hovel", "hut"]);
} else if (roll <= 8) { } else if (roll <= 8) {
return "farm"; return "farm";
} else if (roll <= 10) { } else if (roll <= 10) {
return "inn/roadhouse"; return sample(["inn", "roadhouse"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return "tower/keep/estate"; return sample(["tower", "keep", "estate"]);
} }
return ""; return "";
@@ -375,15 +410,15 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
export function rollBurialReligiousStructure(roll: number = random(1, 12)): string { export function rollBurialReligiousStructure(roll: number = random(1, 12)): string {
if (roll <= 2) { if (roll <= 2) {
return "grave marker/barrow"; return sample(["grave marker", "grave barrow"]);
} else if (roll <= 4) { } else if (roll <= 4) {
return "graveyard/necropolis"; return sample(["graveyard", "necropolis"]);
} else if (roll <= 6) { } else if (roll <= 6) {
return "tomb/crypt"; return sample(["tomb", "crypt"]);
} else if (roll <= 9) { } else if (roll <= 9) {
return "shrine"; return "shrine";
} else if (roll <= 11) { } else if (roll <= 11) {
return "temple/retreat"; return sample(["temple", "retreat"]);
} else if (roll <= 12) { } else if (roll <= 12) {
return "great temple"; return "great temple";
} }
+335 -14
View File
@@ -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 { export class Dungeon {
size: Size; size: Size;
ruination: string; ruination: Ruination;
builder: string; builder: Builder;
function: string; function: DunFunction;
themes: string[]; commonThemes: Theme[] = [];
discovery: string; uniqueThemes: Theme[] = [];
danger: string; commonAreas: (Discovery | Danger)[] = [];
uniqueAreas: (Discovery | Danger)[] = [];
printDescription() { printDescription() {
return `${this.size.size} ${this.builder} ${this.function}`; return `${this.size.description} ${this.function.description} built by ${this.builder.description}`;
} }
} }
export class Size { 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 { export function rollDungeon(): Dungeon {
// TODO: Add the who dungeon thing
let dungeon = new Dungeon(); let dungeon = new Dungeon();
dungeon.size = new Size("huge"); dungeon.size = rollSize();
dungeon.builder = "dwarves"; dungeon.ruination = rollRuination();
dungeon.function = "mine"; 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(); 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]);
}
+8 -1
View File
@@ -1,4 +1,4 @@
import { random } from 'lodash'; import { random, sample } from 'lodash';
export class Kingdom { export class Kingdom {
constructor(public description: string = "", public subtitle: string = "") { }; 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]; let key = Object.keys(kingdoms)[roll - 1];
return kingdoms[key]; return kingdoms[key];
}
export function rollCategory(kingdom: string = "", category: string = ""): string {
if (kingdoms[kingdom] && kingdoms[kingdom][category]) {
return sample(kingdoms[kingdom][category]);
}
return "";
} }
+146 -132
View File
@@ -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 { Follower, rollFollower } from './followers';
import { kingdoms, rollKingdom } from './kingdoms'; import { kingdoms, rollKingdom } from './kingdoms';
@@ -7,11 +8,18 @@ export class Npc {
gender: "male" | "female"; gender: "male" | "female";
hometown: string; hometown: string;
context: Context; context: Context;
occupation: Occupation occupation: Occupation
trait: Trait; trait: Trait;
follower: Follower; 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 { export function rollNpc(): Npc {
@@ -31,7 +39,10 @@ export function rollNpc(): Npc {
} }
export class Context { 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 { export function rollContext(): Context {
@@ -40,71 +51,74 @@ export function rollContext(): Context {
let context = new Context(roll, subroll); let context = new Context(roll, subroll);
if (roll <= 3) { if (roll <= 3) {
context.category = "wilderness"; context.category = "wilderness";
context.subcategory = rollWildernessNpc(subroll); context.description = rollWildernessNpc(subroll);
} else if (roll <= 9) { } else if (roll <= 9) {
context.category = "rural"; context.category = "rural";
context.subcategory = rollRuralNpc(subroll); context.description = rollRuralNpc(subroll);
} else if (roll <= 12) { } else if (roll <= 12) {
context.category = "urban"; context.category = "urban";
context.subcategory = rollUrbanNpc(subroll); context.description = rollUrbanNpc(subroll);
} }
context.activity = rollActivity();
context.alignment = rollAlignment();
context.trait = rollTrait();
return context; return context;
} }
export function rollWildernessNpc(roll: number = random(1, 12)): string { export function rollWildernessNpc(roll: number = random(1, 12)): string {
return [ return [
`${rollCriminal()} -4`, `criminal ${rollCriminal()} -4`,
`${rollCriminal()} -4`, `criminal ${rollCriminal()} -4`,
"adventurer/explorer", "adventurer",
"adventurer/explorer", "explorer",
"hunter/gatherer", "hunter",
"hunter/gatherer", "gatherer",
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
"ranger/scout", "ranger",
"ranger/scout", "scout",
"soldier/mercenary", sample(["soldier", "mercenary"]),
rollOfficial(), `official ${rollOfficial()}`,
][roll - 1]; ][roll - 1];
} }
export function rollRuralNpc(roll: number = random(1, 12)): string { export function rollRuralNpc(roll: number = random(1, 12)): string {
return [ return [
"beggar/urchin", sample(["beggar", "urchin"]),
`${rollCriminal()} -1`, `criminal ${rollCriminal()} -1`,
"adventurer/explorer", sample(["adventurer", "explorer"]),
"hunter/gatherer", sample(["hunter", "gatherer"]),
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollTradeperson(), `tradeperson ${rollTradeperson()}`,
`${rollMerchant()} -1`, `merchant ${rollMerchant()} -1`,
"militia/soldier/guard", sample(["militia", "soldier", "guard"]),
rollOfficial(), `official ${rollOfficial()}`,
][roll - 1]; ][roll - 1];
} }
export function rollUrbanNpc(roll: number = random(1, 12)): string { export function rollUrbanNpc(roll: number = random(1, 12)): string {
return [ return [
"beggar/urchin", "beggar",
"beggar/urchin", "urchin",
rollCriminal(), `commoner ${rollCriminal()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollCommoner(), `commoner ${rollCommoner()}`,
rollTradeperson(), `tradeperson ${rollTradeperson()}`,
rollMerchant(), `merchant ${rollMerchant()}`,
rollSpecialist(), `specialist ${rollSpecialist()}`,
"militia/soldier/guard", sample(["militia", "soldier", "guard"]),
rollOfficial(), `official ${rollOfficial()}`,
][roll - 1]; ][roll - 1];
} }
export class Occupation { 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 { 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); let occupation = new Occupation(roll, subroll);
if (roll <= 1) { if (roll <= 1) {
occupation.category = "criminal"; occupation.category = "criminal";
occupation.subcategory = rollCriminal(subroll); occupation.description = rollCriminal(subroll);
} else if (roll <= 6) { } else if (roll <= 6) {
occupation.category = "commoner"; occupation.category = "commoner";
occupation.subcategory = rollCommoner(subroll); occupation.description = rollCommoner(subroll);
} else if (roll <= 8) { } else if (roll <= 8) {
occupation.category = "tradeperson"; occupation.category = "tradeperson";
occupation.subcategory = rollTradeperson(subroll); occupation.description = rollTradeperson(subroll);
} else if (roll <= 10) { } else if (roll <= 10) {
occupation.category = "merchant"; occupation.category = "merchant";
occupation.subcategory = rollMerchant(subroll); occupation.description = rollMerchant(subroll);
} else if (roll <= 11) { } else if (roll <= 11) {
occupation.category = "specialist"; occupation.category = "specialist";
occupation.subcategory = rollSpecialist(subroll); occupation.description = rollSpecialist(subroll);
} else if (roll <= 12) { } else if (roll <= 12) {
occupation.category = "officiail"; occupation.category = "official";
occupation.subcategory = rollOfficial(subroll); occupation.description = rollOfficial(subroll);
} }
return occupation; 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 { function rollCriminal(roll: number = random(1, 12)): string {
return [ return [
"bandit/brigand/thug", sample(["bandit", "brigand", "thug"]),
"bandit/brigand/thug", sample(["bandit", "brigand", "thug"]),
"thief", "thief",
"thief", "thief",
"bodyguard/tough", "bodyguard",
"bodyguard/tough", "tough",
"burglar", "burglar",
"burglar", "burglar",
"dealer/fence", sample(["dealer", "fence"]),
"racketeer", "racketeer",
"lieutenant", "lieutenant",
"boss" "boss"
@@ -153,66 +167,66 @@ function rollCriminal(roll: number = random(1, 12)): string {
function rollCommoner(roll: number = random(1, 12)): string { function rollCommoner(roll: number = random(1, 12)): string {
return [ return [
"housewife/husband", "housewife/husband",
"hunter/gatherer", "hunter",
"hunter/gatherer", "gatherer",
"farmer/herder", "farmer",
"farmer/herder", "herder",
"farmer/herder", sample(["farmer", "herder"]),
"laborer/servant", "laborer",
"laborer/servant", "servant",
"driver/porter/guide", sample(["driver", "porter", "guide"]),
"sailor/soldier/guard", sample(["sailor", "soldier", "guard"]),
"clergy/monk", sample(["clergy", "monk"]),
"apprentice/adventurer" sample(["apprentice", "adventurer"]),
][roll - 1]; ][roll - 1];
} }
function rollTradeperson(roll: number = random(1, 12)): string { function rollTradeperson(roll: number = random(1, 12)): string {
return [ return [
"cobbler/furrier/tailor", sample(["cobbler", "furrier", "tailor"]),
"weaver/basketmaker", sample(["weaver", "basketmaker"]),
"potter/carpenter", sample(["potter", "carpenter"]),
"mason/baker/chandler", sample(["mason", "baker", "chandler"]),
"cooper/wheelwright", sample(["cooper", "wheelwright"]),
"tanner/ropemaker", sample(["tanner", "ropemaker"]),
"smith/tinker", sample(["smith", "tinker"]),
"stablekeeper/herbalist", sample(["stablekeeper", "herbalist"]),
"vintner/jeweler", sample(["vintner", "jeweler"]),
"inkeeper/tavernkeeper", sample(["inkeeper", "tavernkeeper"]),
"artist/actor/minstrel", sample(["artist", "actor", "minstrel"]),
"armorer/weaponsmith", sample(["armorer", "weaponsmith"]),
][roll - 1]; ][roll - 1];
} }
function rollMerchant(roll: number = random(1, 12)): string { function rollMerchant(roll: number = random(1, 12)): string {
return [ return [
"general goods/outfitter", "general goods",
"general goods/outfitter", "outfitter",
"general goods/outfitter", sample(["general goods", "outfitter"]),
"raw materials", "raw materials",
"grain/livestock", sample(["grain", "livestock"]),
"ale/wine/spirits", sample(["ale", "wine", "spirits"]),
"clothing/jewelry", sample(["clothing", "jewelry"]),
"weapons/armor", sample(["weapons", "armor"]),
"spices/tobacco", sample(["spices", "tobacco"]),
"labor/slaves", sample(["labor", "slaves"]),
"books/scrolls", sample(["books", "scrolls"]),
"magic supplies/items" sample(["magic supplies", "magic items"]),
][roll - 1]; ][roll - 1];
} }
function rollSpecialist(roll: number = random(1, 12)): string { function rollSpecialist(roll: number = random(1, 12)): string {
return [ return [
"undertaker", "undertaker",
"sage/scholar/wizard", sample(["sage", "scholar", "wizard"]),
"writer/illuminator", sample(["writer", "illuminator"]),
"perfumer", "perfumer",
"architect/engineer", sample(["architect", "engineer"]),
"locksmith/clockmaker", sample(["locksmith", "clockmaker"]),
"physician/apothecary", sample(["physician", "apothecary"]),
"navigator/guide", sample(["navigator", "guide"]),
"alchemist/astrologer", sample(["alchemist", "astrologer"]),
"spy/diplomat", sample(["spy", "diplomat"]),
"cartographer", "cartographer",
"inventor" "inventor"
][roll - 1]; ][roll - 1];
@@ -222,16 +236,16 @@ function rollOfficial(roll: number = random(1, 12)): string {
return [ return [
"town crier", "town crier",
"tax collector", "tax collector",
"armiger/gentry", "armiger",
"armiger/gentry", "gentry",
"reeve/sheriff/constable", sample(["reeve", "sheriff", "constable"]),
"mayor/magistrate", sample(["mayor", "magistrate"]),
"priest/bishop/abbot", sample(["priest", "bishop", "abbot"]),
"guildmaster", "guildmaster",
"knightltemplar", "knightltemplar",
"elder/high priest", sample(["elder", "high priest"]),
"noble (baron, etc.)", "noble (baron, etc.)",
"lord/lady/king/queen", sample(["lord", "lady", "king", "queen"]),
][roll - 1]; ][roll - 1];
} }
@@ -259,15 +273,15 @@ function rollAppearance(roll: number = random(1, 12)): string {
let appearance = [ let appearance = [
"disfigured (missing teeth, eye, etc.)", "disfigured (missing teeth, eye, etc.)",
"lasting injury (bad leg, arm, etc.)", "lasting injury (bad leg, arm, etc.)",
"tattooed/pockmarked/scarred", sample(["tattooed", "pockmarked", "scarred"]),
"unkempt/shabby/grubby", sample(["unkempt", "shabby", "grubby"]),
"big/thick/brawny", sample(["big", "thick", "brawny"]),
"small/scrawny/emaciated", sample(["small", "scrawny", "emaciated"]),
"notable hair (wild, long, none, etc.)", "notable hair (wild, long, none, etc.)",
"notable nose (big, hooked, etc.)", "notable nose (big, hooked, etc.)",
"notable eyes (blue, bloodshot, etc.)", "notable eyes (blue, bloodshot, etc.)",
"clean/well-dressed/well-groomed", sample(["clean", "well-dressed", "well-groomed"]),
"attractive/handsome/stunning", sample(["attractive", "handsome", "stunning"]),
"they are [APPEARANCE] despite [a contradictory detail of your choice]" "they are [APPEARANCE] despite [a contradictory detail of your choice]"
][roll - 1]; ][roll - 1];
@@ -276,17 +290,17 @@ function rollAppearance(roll: number = random(1, 12)): string {
export function rollPersonality(roll: number = random(1, 12)): string { export function rollPersonality(roll: number = random(1, 12)): string {
let personality = [ let personality = [
"loner/alienated/antisocial", sample(["loner", "alienated", "antisocial"]),
"cruel/belligerent/bully", sample(["cruel", "belligerent", "bully"]),
"anxious/fearful/cowardly", sample(["anxious", "fearful", "cowardly"]),
"envious/covetous/greedy", sample(["envious", "covetous", "greedy"]),
"aloof/haughty/arrogant", sample(["aloof", "haughty", "arrogant"]),
"awkward/shy/self-loathing", sample(["awkward", "shy", "self-loathing"]),
"orderly/compulsive/controlling", sample(["orderly", "compulsive", "controlling"]),
"confident/impulsive/reckless", sample(["confident", "impulsive", "reckless"]),
"kind/generous/compassionate", sample(["kind", "generous", "compassionate"]),
"easygoing/relaxed/peaceful", sample(["easygoing", "relaxed", "peaceful"]),
"cheerful/happy/optimistic", sample(["cheerful", "happy", "optimistic"]),
"they are [PERSONALITY] despite [a contradictory detail of your choice]", "they are [PERSONALITY] despite [a contradictory detail of your choice]",
][roll - 1]; ][roll - 1];
@@ -295,17 +309,17 @@ export function rollPersonality(roll: number = random(1, 12)): string {
export function rollQuirk(roll: number = random(1, 12)): string { export function rollQuirk(roll: number = random(1, 12)): string {
let quirk = [ let quirk = [
"insecure/racist/xenophobic", sample(["insecure", "racist", "xenophobic"]),
"addict (sweets, drugs, sex, etc.)", sample(["addict (sweets, drugs, sex, etc.)"]),
"phobia (spiders, fire, darkness, etc.)", sample(["phobia (spiders, fire, darkness, etc.)"]),
"allergic/asthmatic/chronically ill", sample(["allergic", "asthmatic", "chronically ill"]),
"skeptic/paranoid", sample(["skeptic", "paranoid"]),
"superstitious/devout/fanatical", sample(["superstitious", "devout", "fanatical"]),
"miser/pack-rat", sample(["miser", "pack-rat"]),
"spendthrift/wastrel", sample(["spendthrift", "wastrel"]),
"smart aleck/know-it-all", sample(["smart aleck", "know-it-all"]),
"artistic/dreamer/delusional", sample(["artistic", "dreamer", "delusional"]),
"naive/idealistic", sample(["naive", "idealistic"]),
"they are [QUIRK] despite [a contradictory detail of your choice]", "they are [QUIRK] despite [a contradictory detail of your choice]",
][roll - 1]; ][roll - 1];
+11 -2
View File
@@ -1,3 +1,6 @@
import { sample } from "lodash";
import { bodgeString } from "./utils";
export const places = { export const places = {
templates: [ templates: [
'The [PLACE]', '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',], 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',], 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',], 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. };
};
export function rollPlace(): string {
let template = sample(places.templates);
let place = bodgeString(template, places);
return place;
}
+11 -2
View File
@@ -1,3 +1,6 @@
import { sample } from "lodash";
import { bodgeString } from "./utils";
export const regions = { export const regions = {
templates: [ templates: [
'[ADJECTIVE] [TERRAIN]', '[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',], 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',], 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',] 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 };
};
export function rollRegion(): string {
let template = sample(regions.templates);
let region = bodgeString(template, regions);
return region;
}
+12 -10
View File
@@ -1,17 +1,19 @@
import { random, sample } from 'lodash'; import { random, sample } from 'lodash';
import { Creature, rollCreature } from './creatures';
import type { Kingdom } from './kingdoms';
export class Steading { export class Steading {
constructor(public roll: number = 0, public category: string = "") { }; constructor(public roll: number = 0, public category: string = "", public description: string = "") { };
builtBy: string; builtBy: Creature;
description: string; kingdom: Kingdom;
kingdom: string;
problem: string; 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 { export function rollSteading(roll: number = random(1, 12)): Steading {
let steading = new 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) { if (roll <= 5) {
steading = rollVillage(); steading = rollVillage();
} else if (roll <= 8) { } else if (roll <= 8) {
@@ -28,19 +30,19 @@ export function rollSteading(roll: number = random(1, 12)): Steading {
export function rollVillage(): Steading { export function rollVillage(): Steading {
return new Steading(0, "village"); return new Steading(0, "village", "village");
} }
export function rollTown(): Steading { export function rollTown(): Steading {
return new Steading(0, "town"); return new Steading(0, "town", "town");
} }
export function rollKeep(): Steading { export function rollKeep(): Steading {
return new Steading(0, "keep"); return new Steading(0, "keep", "keep");
} }
export function rollCity(): Steading { export function rollCity(): Steading {
return new Steading(0, "city"); return new Steading(0, "city", "city");
} }