mirror of
https://github.com/RussellChamp/tpw-roller.git
synced 2026-10-28 00:22:36 +00:00
made a lot of things better
This commit is contained in:
1 parent
d5a1654b22
commit
51948299fa
21 files changed
+1122
-470
No files matched your search
@@ -1,4 +1,5 @@
|
||||
Add NPC, and Dungeons roll tables
|
||||
Put the rollers in their own accordion slots
|
||||
Add Steadings tables
|
||||
Change steadings and mounts to not show English names by default
|
||||
Make everything look nicer
|
||||
Maybe put roller button in a left nav bar and the results in the middle?
|
||||
Add a 3d dice rolling visualizer
|
||||
+38
-18
@@ -1,12 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { Accordion, AccordionHeader, AccordionItem } from "sveltestrap";
|
||||
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 DiscoveryRoller from "./rollers/DiscoveryRoller.svelte";
|
||||
import FollowerRoller from "./rollers/FollowerRoller.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";
|
||||
</script>
|
||||
|
||||
@@ -14,21 +17,38 @@
|
||||
<h1>The Perilous Wilds</h1>
|
||||
<h2>A web-app for rolling on tables and getting funny results</h2>
|
||||
<hr />
|
||||
<KingdomRoller />
|
||||
<hr />
|
||||
<RegionRoller />
|
||||
<hr />
|
||||
<PlaceRoller />
|
||||
<hr />
|
||||
<DangerRoller />
|
||||
<hr />
|
||||
<DiscoveryRoller />
|
||||
<hr />
|
||||
<Accordion>
|
||||
<AccordionItem active header="Creatures">
|
||||
<CreatureRoller />
|
||||
<hr />
|
||||
<FollowerRoller />
|
||||
<hr />
|
||||
</AccordionItem>
|
||||
<AccordionItem header="Dangers">
|
||||
<DangerRoller />
|
||||
</AccordionItem>
|
||||
<AccordionItem header="Details">
|
||||
<DetailsRoller />
|
||||
</AccordionItem>
|
||||
<AccordionItem header="Discoveries">
|
||||
<DiscoveryRoller />
|
||||
</AccordionItem>
|
||||
<AccordionItem header="Dungeons">
|
||||
<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 />
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,26 +1,67 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { capitalize } from "lodash";
|
||||
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";
|
||||
|
||||
export let rollResults: { value: Creature; timestamp: string }[] = [];
|
||||
export let rollResults: { creature: Creature; timestamp: string }[] = [];
|
||||
|
||||
function roll(event: Event) {
|
||||
let value = rollCreature();
|
||||
console.log("creature", value);
|
||||
|
||||
rollResults = [{ value, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
let creature = rollCreature();
|
||||
rollResults = [{ creature, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<h2>Random Creatures</h2>
|
||||
<button type="button" class="btn btn-primary" on:click={roll}>Roll Creature</button>
|
||||
<Button color="primary" on:click={roll}>Roll Creature</Button>
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>{result.timestamp}: {result.value.description}</h4>
|
||||
{#each rollResults as { creature, timestamp }}
|
||||
<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}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
text-align: left;
|
||||
}
|
||||
.card-subtitle {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
ul {
|
||||
margin-left: 2em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import { Icon } from "sveltestrap";
|
||||
import { Button, Icon } from "sveltestrap";
|
||||
import { Danger, rollDanger } from "./dangers";
|
||||
|
||||
export let rollResults: { danger: Danger; icon: string; timestamp: string }[] = [];
|
||||
@@ -21,12 +20,13 @@
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<h2>Random Danger</h2>
|
||||
<button type="button" class="btn btn-primary" on:click={roll}>Roll Danger</button>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={roll}>Roll Danger</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
{#each rollResults as { danger, icon, timestamp }}
|
||||
<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>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import { Button, Icon } from "sveltestrap";
|
||||
import {
|
||||
@@ -26,72 +25,72 @@
|
||||
|
||||
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];
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollActivity())}>Roll Activity</Button>
|
||||
<Button color="primary" on:click={() => roll(rollActivity())}>Roll Activity</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollAge())}>Roll Age</Button>
|
||||
<Button color="primary" on:click={() => roll(rollAge())}>Roll Age</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollAspect())}>Roll Aspect</Button>
|
||||
<Button color="primary" on:click={() => roll(rollAspect())}>Roll Aspect</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollDisposition())}>Roll Disposition</Button>
|
||||
<Button color="primary" on:click={() => roll(rollDisposition())}>Roll Disposition</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollFeature())}>Roll Feature</Button>
|
||||
<Button color="primary" on:click={() => roll(rollFeature())}>Roll Feature</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollNumAppearing())}>Roll NumAppearing</Button>
|
||||
<Button color="primary" on:click={() => roll(rollNumAppearing())}>Roll NumAppearing</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollOrientation())}>Roll Orientation</Button>
|
||||
<Button color="primary" on:click={() => roll(rollOrientation())}>Roll Orientation</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollSize())}>Roll Size</Button>
|
||||
<Button color="primary" on:click={() => roll(rollSize())}>Roll Size</Button>
|
||||
</span>
|
||||
<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 class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollTerrain())}>Roll Terrain</Button>
|
||||
<Button color="primary" on:click={() => roll(rollTerrain())}>Roll Terrain</Button>
|
||||
</span>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={() => addResult(rollVisibility())}>Roll Visibility</Button>
|
||||
<Button color="primary" on:click={() => roll(rollVisibility())}>Roll Visibility</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>{result.timestamp}: ({result.type}): {result.value}</h4>
|
||||
{#each rollResults as { type, value, timestamp }}
|
||||
<h4>{timestamp}: ({type}): {value}</h4>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,25 +1,82 @@
|
||||
<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 { Discovery, rollDiscovery } from "./discoveries";
|
||||
|
||||
export let rollResults: { value: Discovery; timestamp: string }[] = [];
|
||||
export let rollResults: { discovery: Discovery; timestamp: string }[] = [];
|
||||
|
||||
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>
|
||||
|
||||
<main>
|
||||
<h2>Random Discovery</h2>
|
||||
<button type="button" class="btn btn-primary" on:click={roll}>Roll Discovery</button>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={roll}>Roll Discovery</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>
|
||||
{result.timestamp}: {result.value.category} ({result.value.subcategory}): {result.value.description}
|
||||
</h4>
|
||||
{#each rollResults as { discovery, timestamp }}
|
||||
<Card class="mb-3">
|
||||
<CardHeader>
|
||||
<CardTitle
|
||||
>{capitalize(discovery.category)}{#if discovery.subcategory !== ""} ({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}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
main {
|
||||
text-align: left;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
ul {
|
||||
margin-left: 2em;
|
||||
}
|
||||
.btn {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -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>
|
||||
@@ -1,46 +1,44 @@
|
||||
<script lang="ts">
|
||||
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 { rollFollower, Follower } from "./followers";
|
||||
|
||||
export let rollResults: { value: Follower; timestamp: string }[] = [];
|
||||
export let rollResults: { follower: Follower; timestamp: string }[] = [];
|
||||
|
||||
function roll(event: Event) {
|
||||
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>
|
||||
|
||||
<main>
|
||||
<h2>Random Follower</h2>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={roll}>Roll Followers</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
{#each rollResults as { follower, timestamp }}
|
||||
<Card class="mb-3">
|
||||
<CardHeader>
|
||||
<CardTitle>{result.value.name} ({result.value.gender})</CardTitle>
|
||||
<CardTitle>{follower.name} ({follower.gender})</CardTitle>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<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>
|
||||
<CardText>
|
||||
<Container>
|
||||
<Row>
|
||||
<strong>Quality:</strong>
|
||||
<p>
|
||||
They are <em>{result.value.quality.description}</em> (Quality: {result.value.quality.value}). They
|
||||
<em>{result.value.background.description}</em>.
|
||||
They are <em>{follower.quality.description}</em> (Quality: {follower.quality.value}). They
|
||||
<em>{follower.background.description}</em>.
|
||||
</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Tags:</strong>
|
||||
<ul>
|
||||
{#each result.value.tags as tag}
|
||||
{#each follower.tags as tag}
|
||||
<li>{tag.name}: {tag.description}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -48,7 +46,7 @@
|
||||
<Row>
|
||||
<strong>Moves:</strong>
|
||||
<ul>
|
||||
{#each result.value.moves as move}
|
||||
{#each follower.moves as move}
|
||||
<li>{move.description}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -56,44 +54,44 @@
|
||||
<Row>
|
||||
<strong>Loyalty:</strong>
|
||||
<p>
|
||||
They have a loyalty score of {result.value.loyalty.value}{#if !!result.value.loyalty.description}
|
||||
and <em>{result.value.loyalty.description}</em>{/if}.
|
||||
They have a loyalty score of {follower.loyalty.value}{#if !!follower.loyalty.description}
|
||||
and <em>{follower.loyalty.description}</em>{/if}.
|
||||
</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Instinct:</strong>
|
||||
<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>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Cost:</strong>
|
||||
<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>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Hit Points:</strong>
|
||||
<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>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Armor & Shield:</strong>
|
||||
<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>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Damage:</strong>
|
||||
<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>
|
||||
</Row>
|
||||
<Row>
|
||||
<strong>Load & Gear:</strong>
|
||||
<ul>
|
||||
{#each result.value.loadAndGear.gear as gear}
|
||||
{#each follower.loadAndGear.gear as gear}
|
||||
<li>{gear}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -101,7 +99,7 @@
|
||||
</Container>
|
||||
</CardText>
|
||||
</CardBody>
|
||||
<CardFooter>{result.timestamp}</CardFooter>
|
||||
<CardFooter>{timestamp}</CardFooter>
|
||||
</Card>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { capitalize } from "lodash";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import { Button, Icon } from "sveltestrap";
|
||||
|
||||
import { kingdoms } from "./kingdoms";
|
||||
import { kingdoms, rollCategory } from "./kingdoms";
|
||||
|
||||
let rollResults: { value: string; icon: string; timestamp: string }[] = [];
|
||||
let kingdom = "arpad";
|
||||
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] || "";
|
||||
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;
|
||||
</script>
|
||||
|
||||
@@ -35,12 +31,12 @@
|
||||
|
||||
{#each categories as category}
|
||||
<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>
|
||||
{/each}
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>{result.timestamp}: <Icon name={result.icon} /> {result.value}</h4>
|
||||
{#each rollResults as { value, icon, timestamp }}
|
||||
<h4>{timestamp}: <Icon name={icon} /> {value}</h4>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -1,28 +1,23 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import { places } from "./places";
|
||||
import { bodgeString } from "./utils";
|
||||
import { Button } from "sveltestrap";
|
||||
import { rollPlace } from "./places";
|
||||
|
||||
export let rollResults: { value: string; timestamp: string }[] = [];
|
||||
|
||||
function addResult(result: string) {
|
||||
rollResults = [{ value: result, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
}
|
||||
export let rollResults: { place: string; timestamp: string }[] = [];
|
||||
|
||||
function roll(event: Event) {
|
||||
let template = _.sample(places.templates);
|
||||
|
||||
addResult(bodgeString(template, places));
|
||||
let place = rollPlace();
|
||||
rollResults = [{ place, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<h2>Random Places</h2>
|
||||
<button type="button" class="btn btn-primary" on:click={roll}>Roll Region</button>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={roll}>Roll Place</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>{result.timestamp}: {result.value}</h4>
|
||||
{#each rollResults as { place, timestamp }}
|
||||
<h4>{timestamp}: {place}</h4>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
<script lang="ts">
|
||||
import * as _ from "lodash";
|
||||
import { format as formatDate } from "date-fns";
|
||||
import { regions } from "./regions";
|
||||
import { bodgeString } from "./utils";
|
||||
import { Button } from "sveltestrap";
|
||||
import { rollRegion } from "./regions";
|
||||
|
||||
export let rollResults: { value: string; timestamp: string }[] = [];
|
||||
|
||||
function addResult(result: string) {
|
||||
rollResults = [{ value: result, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
}
|
||||
export let rollResults: { region: string; timestamp: string }[] = [];
|
||||
|
||||
function roll(event: Event) {
|
||||
let template = _.sample(regions.templates);
|
||||
|
||||
addResult(bodgeString(template, regions));
|
||||
let region = rollRegion();
|
||||
rollResults = [{ region, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<h2>Random Regions</h2>
|
||||
<button type="button" class="btn btn-primary" on:click={roll}>Roll Region</button>
|
||||
<span class="btn">
|
||||
<Button color="primary" on:click={roll}>Roll Region</Button>
|
||||
</span>
|
||||
|
||||
{#each rollResults as result}
|
||||
<h4>{result.timestamp}: {result.value}</h4>
|
||||
{#each rollResults as { region, timestamp }}
|
||||
<h4>{timestamp}: {region}</h4>
|
||||
{/each}
|
||||
</main>
|
||||
|
||||
|
||||
+42
-77
@@ -1,49 +1,59 @@
|
||||
import { random, sample } from 'lodash';
|
||||
import { rollUnnaturalEntity } from './dangers';
|
||||
|
||||
import { Activity, Disposition, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size } from './details';
|
||||
import { rollNpc } from './npcs';
|
||||
import { Ability, Activity, Adjective, Age, Alignment, Aspect, Condition, Disposition, Feature, NumAppearing, rollAbility, rollActivity, rollAlignment, rollDisposition, rollFeature, rollNumAppearing, rollOddity, rollSize, Size, Tag } from './details';
|
||||
import { Npc, rollNpc } from './npcs';
|
||||
|
||||
export class Creature {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public specifcroll: number = 0, public type: string = "", public subtype: string = "", public description: string = "") { };
|
||||
details: string[] = [];
|
||||
|
||||
ability?: Ability;
|
||||
activity?: Activity;
|
||||
adjective?: Adjective;
|
||||
age?: Age;
|
||||
alignment?: Alignment;
|
||||
aspect?: Aspect;
|
||||
condition?: Condition;
|
||||
disposition?: Disposition;
|
||||
feature?: Feature;
|
||||
npc?: Npc;
|
||||
numAppearing?: NumAppearing;
|
||||
size?: Size;
|
||||
tags: Tag[] = [];
|
||||
}
|
||||
|
||||
|
||||
export function rollCreature(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)) {
|
||||
let creature = new Creature(roll, subroll, specificroll);
|
||||
if (roll <= 4) {
|
||||
return rollBeast(roll, subroll, specificroll);
|
||||
} else if (roll <= 6) {
|
||||
creature.type = "human";
|
||||
let npc = rollNpc();
|
||||
creature.description = `${npc.name} the ${npc.gender} ${npc.occupation.subcategory} from ${npc.hometown}`;
|
||||
creature.details = [
|
||||
rollActivity().description,
|
||||
rollAlignment().description,
|
||||
rollDisposition().description,
|
||||
rollNumAppearing().description,
|
||||
npc.name /* TODO: figure out how to do this */
|
||||
];
|
||||
let human = new Creature(roll, subroll, specificroll);
|
||||
human.type = "human";
|
||||
human.npc = rollNpc();
|
||||
human.description = human.npc.getDescription(true);
|
||||
human.activity = rollActivity();
|
||||
human.alignment = rollAlignment();
|
||||
human.disposition = rollDisposition();
|
||||
human.numAppearing = rollNumAppearing();
|
||||
|
||||
return human;
|
||||
} else if (roll <= 8) {
|
||||
return rollHumanoid(roll, subroll, specificroll);
|
||||
} else if (roll <= 12) {
|
||||
return rollMonster();
|
||||
}
|
||||
|
||||
return creature;
|
||||
return new Creature(roll, subroll, specificroll);
|
||||
}
|
||||
|
||||
export function rollBeast(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
|
||||
let creature = new Creature(roll, subroll, specificroll);
|
||||
|
||||
creature.type = "beast";
|
||||
creature.details = [
|
||||
rollActivity().description,
|
||||
rollDisposition().description,
|
||||
rollNumAppearing().description,
|
||||
rollSize().description
|
||||
];
|
||||
creature.activity = rollActivity();
|
||||
creature.disposition = rollDisposition();
|
||||
creature.numAppearing = rollNumAppearing();
|
||||
creature.size = rollSize();
|
||||
|
||||
if (subroll <= 7) {
|
||||
creature.subtype = "earthbound";
|
||||
@@ -113,13 +123,11 @@ export function rollWaterGoingBeast(roll: number = random(1, 12)): string {
|
||||
export function rollHumanoid(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
|
||||
let creature = new Creature(roll, subroll, specificroll, "humanoid");
|
||||
|
||||
creature.details = [
|
||||
rollActivity().description,
|
||||
rollAlignment().description,
|
||||
rollDisposition().description,
|
||||
rollNumAppearing().description,
|
||||
rollNpc().name /* figure out how to do this */
|
||||
];
|
||||
creature.activity = rollActivity();
|
||||
creature.alignment = rollAlignment();
|
||||
creature.disposition = rollDisposition();
|
||||
creature.numAppearing = rollNumAppearing();
|
||||
creature.npc = rollNpc(); /* figure out how to do this */
|
||||
|
||||
if (subroll <= 7) {
|
||||
creature.subtype = "common";
|
||||
@@ -190,13 +198,12 @@ export function rollHybridHumanoid(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollMonster(roll: number = random(1, 12), subroll: number = random(1, 12), specificroll: number = random(1, 12)): Creature {
|
||||
let creature = new Creature(roll, subroll, specificroll, "monster");
|
||||
creature.details = [
|
||||
rollActivity().description,
|
||||
rollAlignment().description,
|
||||
rollDisposition().description,
|
||||
rollNumAppearing().description,
|
||||
rollSize().description,
|
||||
];
|
||||
|
||||
creature.activity = rollActivity();
|
||||
creature.alignment = rollAlignment();
|
||||
creature.disposition = rollDisposition();
|
||||
creature.numAppearing = rollNumAppearing();
|
||||
creature.size = rollSize();
|
||||
|
||||
if (subroll <= 7) {
|
||||
creature.subtype = "unusual";
|
||||
@@ -258,45 +265,3 @@ export function rollLegendaryMonster(roll: number = random(1, 12)): string {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
// MONSTER. Give every monster life!
|
||||
|
||||
// I
|
||||
// 'V
|
||||
// 48
|
||||
// UNUSUAL ......
|
||||
// 1-3
|
||||
// 4-6
|
||||
// 7-9
|
||||
// 10-12 Truai. ENTI
|
||||
// 9-10
|
||||
//
|
||||
// ASK THE FATES
|
||||
// LREATURE
|
||||
// Roll 1d12 for creature type if it hasn't already been established, then 1d12 on indicat-
|
||||
// ed subtable for specific prompt. Roll additional details as indicated, and/or at whim.
|
||||
// 1d12 QmATuRE Aim'rtoi.. DETAILS (see pages 50-53)
|
||||
// 1-4 BEAST ACTIVITY, DISPOSITION, No. APPEARING, SIZE
|
||||
// 5-6 Human ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, NPC tables
|
||||
// 7-8 HUMANOID ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, NPC tables 942 MONSTER ACTIVITY, ALIGNMENT, DISPOSITION, No. APPEARING, SIZE
|
||||
// Optional: ABILITY, ADJECTIVE, AGE, ASPECT, CONDITION, FEATURE, TAGS
|
||||
|
||||
// HUMANOID . If you roll a classic fantasy species, adapt it to your setting. 1-7 COMMON 8-10 UNCOMMON 11-12 HYBRID
|
||||
|
||||
// MONSTER. Give every monster life!
|
||||
// 1-7 UNUSUAL
|
||||
// 1-3 plant/fungus
|
||||
// 4-5 Undead Human
|
||||
// 6 Undead HUMANOID
|
||||
// 7-8 BEAST + BEAST
|
||||
// 9-10 BEAST + ABILITY
|
||||
// 1142 BEAST + FEATURE
|
||||
// 8T10.. RARE 11-12
|
||||
// 1-3 slime/ooze (4morphous) 1-3
|
||||
// 4-6 creation (Construct) 4-6
|
||||
// 7-9 BEAST + ODDITY 7-9
|
||||
// 10-12 UNNxrua1. ENTITY 10
|
||||
// II
|
||||
// 12
|
||||
// LEGENDARY
|
||||
+75
-75
@@ -8,17 +8,17 @@ export class Ability {
|
||||
export function rollAbility(roll: number = random(1, 12)): Ability {
|
||||
let ability = new Ability(roll);
|
||||
ability.description = [
|
||||
"bless/curse",
|
||||
"entangle/trap/snare",
|
||||
"poison/disease",
|
||||
"paralyze/petrify",
|
||||
"mimic/camouflage",
|
||||
"seduce/hypnotize",
|
||||
"dissolve/disintegrate",
|
||||
sample(["bless", "curse"]),
|
||||
sample(["entangle", "trap", "snare"]),
|
||||
sample(["poison", "disease"]),
|
||||
sample(["paralyze", "petrify"]),
|
||||
sample(["mimic", "camouflage"]),
|
||||
sample(["seduce", "hypnotize"]),
|
||||
sample(["dissolve", "disintegrate"]),
|
||||
rollMagicType().description,
|
||||
"drain life/magic",
|
||||
sample(["drain life", "drain magic"]),
|
||||
`immunity to ${rollElement().description}`,
|
||||
"read/control minds",
|
||||
sample(["read minds", "control minds"]),
|
||||
"[ABILITY] and [ABILITY]"
|
||||
][roll - 1];
|
||||
ability.description = replace(ability.description, /\[ABILITY\]/g, () => rollAbility(random(1, 11)).description);
|
||||
@@ -34,16 +34,16 @@ export class Activity {
|
||||
export function rollActivity(roll: number = random(1, 12)): Activity {
|
||||
let activity = new Activity(roll);
|
||||
activity.description = [
|
||||
"laying trap/ambush",
|
||||
"fighting/at war",
|
||||
"prowling/on patrol",
|
||||
"hunting/foraging",
|
||||
"eating/resting",
|
||||
"crafting/praying",
|
||||
"traveling/relocating",
|
||||
"exploring/lost",
|
||||
sample(["laying trap", "ambush"]),
|
||||
sample(["fighting", "at war"]),
|
||||
sample(["prowling", "on patrol"]),
|
||||
sample(["hunting", "foraging"]),
|
||||
sample(["eating", "resting"]),
|
||||
sample(["crafting", "praying"]),
|
||||
sample(["traveling", "relocating"]),
|
||||
sample(["exploring", "lost"]),
|
||||
"returning home",
|
||||
"building/excavating",
|
||||
sample(["building", "excavating"]),
|
||||
"sleeping",
|
||||
"dying",
|
||||
][roll - 1];
|
||||
@@ -59,17 +59,17 @@ export class Adjective {
|
||||
export function rollAdjective(roll: number = random(1, 12)): Adjective {
|
||||
let adjective = new Adjective(roll);
|
||||
adjective.description = [
|
||||
"slick/slimy",
|
||||
"rough/hard/sharp",
|
||||
"smooth/soft/dull",
|
||||
"corroded/rusty",
|
||||
"rotten/decaying",
|
||||
"broken/brittle",
|
||||
"stinking/smelly",
|
||||
"weak/thin/drained",
|
||||
"strong/fat/full",
|
||||
"pale/poor/shallow",
|
||||
"dark/rich/deep",
|
||||
sample(["slick", "slimy"]),
|
||||
sample(["rough", "hard", "sharp"]),
|
||||
sample(["smooth", "soft", "dull"]),
|
||||
sample(["corroded", "rusty"]),
|
||||
sample(["rotten", "decaying"]),
|
||||
sample(["broken", "brittle"]),
|
||||
sample(["stinking", "smelly"]),
|
||||
sample(["weak", "thin", "drained"]),
|
||||
sample(["strong", "fat", "full"]),
|
||||
sample(["pale", "poor", "shallow"]),
|
||||
sample(["dark", "rich", "deep"]),
|
||||
"colorful",
|
||||
][roll - 1];
|
||||
|
||||
@@ -132,16 +132,16 @@ export class Aspect {
|
||||
export function rollAspect(roll: number = random(1, 12)): Aspect {
|
||||
let aspect = new Aspect(roll);
|
||||
aspect.description = [
|
||||
"power/strength",
|
||||
"trickery/dexterity",
|
||||
"time/constitution",
|
||||
"knowledge/intelligence",
|
||||
"nature/wisdom",
|
||||
"culture/charisma",
|
||||
"war/lies/discord",
|
||||
"peace/truth/balance",
|
||||
"hate/envy",
|
||||
"love/admiration",
|
||||
sample(["power", "strength"]),
|
||||
sample(["trickery", "dexterity"]),
|
||||
sample(["time", "constitution"]),
|
||||
sample(["knowledge", "intelligence"]),
|
||||
sample(["nature", "wisdom"]),
|
||||
sample(["culture", "charisma"]),
|
||||
sample(["war", "lies", "discord"]),
|
||||
sample(["peace", "truth", "balance"]),
|
||||
sample(["hate", "envy"]),
|
||||
sample(["love", "admiration"]),
|
||||
rollElement().description,
|
||||
"[ASPECT] and [ASPECT]"
|
||||
][roll - 1];
|
||||
@@ -159,19 +159,19 @@ export function rollCondition(roll: number = random(1, 12)): Condition {
|
||||
let condition = new Condition(roll);
|
||||
|
||||
if (roll <= 1) {
|
||||
condition.description = "being built/born";
|
||||
condition.description = sample(["being built", "being born"]);
|
||||
} else if (roll <= 4) {
|
||||
condition.description = "intact/healthy/stable";
|
||||
condition.description = sample(["intact", "healthy", "stable"]);
|
||||
} else if (roll <= 7) {
|
||||
condition.description = "occupied/active/alert";
|
||||
condition.description = sample(["occupied", "active", "alert"]);
|
||||
} else if (roll <= 9) {
|
||||
condition.description = "worn/tired/weak";
|
||||
condition.description = sample(["worn", "tired", "weak"]);
|
||||
} else if (roll <= 10) {
|
||||
condition.description = "vacant/lost";
|
||||
condition.description = sample(["vacant", "lost"]);
|
||||
} else if (roll <= 11) {
|
||||
condition.description = "ruined/defiled/dying";
|
||||
condition.description = sample(["ruined", "defiled", "dying"]);
|
||||
} else if (roll <= 12) {
|
||||
condition.description = "disappeared/dead";
|
||||
condition.description = sample(["disappeared", "dead"]);
|
||||
}
|
||||
|
||||
return condition;
|
||||
@@ -188,15 +188,15 @@ export function rollDisposition(roll: number = random(1, 12)): Disposition {
|
||||
if (roll <= 1) {
|
||||
disposition.description = "attacking";
|
||||
} else if (roll <= 4) {
|
||||
disposition.description = "hostile/aggressive";
|
||||
disposition.description = sample(["hostile", "aggressive"]);
|
||||
} else if (roll <= 6) {
|
||||
disposition.description = "cautious/doubtful";
|
||||
disposition.description = sample(["cautious", "doubtful"]);
|
||||
} else if (roll <= 7) {
|
||||
disposition.description = "fearful/fleeing";
|
||||
disposition.description = sample(["fearful", "fleeing"]);
|
||||
} else if (roll <= 10) {
|
||||
disposition.description = "neutral";
|
||||
} else if (roll <= 11) {
|
||||
disposition.description = "curious/hopeful";
|
||||
disposition.description = sample(["curious", "hopeful"]);
|
||||
} else if (roll <= 12) {
|
||||
disposition.description = "friendly";
|
||||
}
|
||||
@@ -242,13 +242,13 @@ export function rollFeature(roll: number = random(1, 12)): Feature {
|
||||
} else if (roll <= 3) {
|
||||
feature.description = "winged/flying";
|
||||
} else if (roll <= 4) {
|
||||
feature.description = "multiple heads/headless";
|
||||
feature.description = sample(["multiple heads", "headless"]);
|
||||
} else if (roll <= 5) {
|
||||
feature.description = "many eyes/one eye";
|
||||
feature.description = sample(["many eyes", "one eye"]);
|
||||
} else if (roll <= 6) {
|
||||
feature.description = "many limbs/tails";
|
||||
feature.description = sample(["many limbs", "tails"]);
|
||||
} else if (roll <= 7) {
|
||||
feature.description = "tentacles/tendrils";
|
||||
feature.description = sample(["tentacles", "tendrils"]);
|
||||
} else if (roll <= 8) {
|
||||
feature.description = rollAspect().description;
|
||||
} else if (roll <= 9) {
|
||||
@@ -317,15 +317,15 @@ export class Oddity {
|
||||
export function rollOddity(roll: number = random(1, 12)): Oddity {
|
||||
let oddity = new Oddity(roll);
|
||||
oddity.description = [
|
||||
"weird color/smell/sound",
|
||||
sample(["weird color", "smell", "sound"]),
|
||||
"geometric",
|
||||
"web/network/system",
|
||||
"crystalline/glass-like",
|
||||
sample(["web", "network", "system"]),
|
||||
sample(["crystalline", "glass-like"]),
|
||||
"fungal",
|
||||
"gaseous/smokey",
|
||||
"mirage/illusion",
|
||||
"volcanic/explosive",
|
||||
"magnetic/repellant",
|
||||
sample(["gaseous", "smokey"]),
|
||||
sample(["mirage", "illusion"]),
|
||||
sample(["volcanic", "explosive"]),
|
||||
sample(["magnetic", "repellant"]),
|
||||
"devoid of life",
|
||||
"unexpectedly alive",
|
||||
"[ODDITY] and [ODDITY]",
|
||||
@@ -379,15 +379,15 @@ export function rollRuination(roll: number = random(1, 12)): Ruination {
|
||||
if (roll <= 1) {
|
||||
ruination.description = "arcane disaster";
|
||||
} else if (roll <= 2) {
|
||||
ruination.description = "damnation/curse";
|
||||
ruination.description = sample(["damnation", "curse"]);
|
||||
} else if (roll <= 4) {
|
||||
ruination.description = "earthquake/fire/flood";
|
||||
ruination.description = sample(["earthquake", "fire", "flood"]);
|
||||
} else if (roll <= 6) {
|
||||
ruination.description = "plague/famine/drought";
|
||||
ruination.description = sample(["plague", "famine", "drought"]);
|
||||
} else if (roll <= 8) {
|
||||
ruination.description = "overrun by monsters";
|
||||
} else if (roll <= 10) {
|
||||
ruination.description = "war/invasion";
|
||||
ruination.description = sample(["war", "invasion"]);
|
||||
} else if (roll <= 11) {
|
||||
ruination.description = "depleted resources";
|
||||
} else if (roll <= 12) {
|
||||
@@ -463,19 +463,19 @@ export function rollTerrain(roll: number = random(1, 12)): Terrain {
|
||||
let terrain = new Terrain(roll);
|
||||
|
||||
if (roll <= 1) {
|
||||
terrain.description = "wasteland/desert";
|
||||
terrain.description = sample(["wasteland", "desert"]);
|
||||
} else if (roll <= 3) {
|
||||
terrain.description = "flatland/plain";
|
||||
terrain.description = sample(["flatland", "plain"]);
|
||||
} else if (roll <= 4) {
|
||||
terrain.description = "wetland/marsh/swamp";
|
||||
terrain.description = sample(["wetland", "marsh", "swamp"]);
|
||||
} else if (roll <= 7) {
|
||||
terrain.description = "woodland/forest/jungle";
|
||||
terrain.description = sample(["woodland", "forest", "jungle"]);
|
||||
} else if (roll <= 9) {
|
||||
terrain.description = "highland/hills";
|
||||
terrain.description = sample(["highland", "hills"]);
|
||||
} else if (roll <= 11) {
|
||||
terrain.description = "mountains";
|
||||
} else if (roll <= 12) {
|
||||
terrain.description = rollOddity().description;
|
||||
terrain.description = `${rollOddity().description} oddity`;
|
||||
}
|
||||
|
||||
return terrain;
|
||||
@@ -490,15 +490,15 @@ export function rollVisibility(roll: number = random(1, 12)): Visibility {
|
||||
let visibility = new Visibility(roll);
|
||||
|
||||
if (roll <= 2) {
|
||||
visibility.description = "buried/camouflaged/nigh invisible";
|
||||
visibility.description = sample(["buried", "camouflaged", "nigh invisible"]);
|
||||
} else if (roll <= 6) {
|
||||
visibility.description = "partly covered/overgrown/hidden";
|
||||
visibility.description = sample(["partly covered", "partly overgrown", "partly hidden"]);
|
||||
} else if (roll <= 9) {
|
||||
visibility.description = "obvious/in plain sight";
|
||||
visibility.description = sample(["obvious", "in plain sight"]);
|
||||
} else if (roll <= 11) {
|
||||
visibility.description = "visible at near distance";
|
||||
} else if (roll <= 12) {
|
||||
visibility.description = "visible at great distance/focal point";
|
||||
visibility.description = sample(["visible at great distance", "focal point"]);
|
||||
}
|
||||
|
||||
return visibility;
|
||||
|
||||
+65
-30
@@ -1,14 +1,23 @@
|
||||
import { random, sample } from 'lodash';
|
||||
import { Creature, rollCreature } from './creatures';
|
||||
import { rollAlignment, rollElement, rollMagicType, rollOddity, rollTerrain } from './details';
|
||||
import { Age, Alignment, Aspect, Element, MagicType, rollAge, rollAlignment, rollAspect, rollElement, rollMagicType, rollOddity, rollRuination, rollSize, rollTerrain, rollVisibility, Ruination, Size, Visibility } from './details';
|
||||
import { rollDungeon } from './dungeons';
|
||||
import { rollSteading, Steading } from './steadings';
|
||||
import { rollTreasure } from './treasures';
|
||||
|
||||
export class Discovery {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public specificroll: number = 0, public category: string = "", public subcategory: string = "", public description: string = "") { };
|
||||
|
||||
age?: Age;
|
||||
alignment?: Alignment;
|
||||
aspect?: Aspect;
|
||||
creature?: Creature;
|
||||
element?: Element;
|
||||
magicType?: MagicType;
|
||||
ruination?: Ruination;
|
||||
size?: Size;
|
||||
steading?: Steading;
|
||||
visibility?: Visibility;
|
||||
}
|
||||
|
||||
export function rollDiscovery() {
|
||||
@@ -37,12 +46,18 @@ export function rollUnnaturalFeature(roll: number = random(1, 12), subroll: numb
|
||||
if (subroll <= 9) {
|
||||
discovery.subcategory = "arcane";
|
||||
discovery.description = rollArcaneFeature(specificroll);
|
||||
discovery.alignment = rollAlignment();
|
||||
discovery.magicType = rollMagicType();
|
||||
} else if (subroll <= 11) {
|
||||
discovery.subcategory = "planar";
|
||||
discovery.description = rollPlanarFeature(specificroll);
|
||||
discovery.alignment = rollAlignment();
|
||||
discovery.element = rollElement();
|
||||
} else if (subroll <= 12) {
|
||||
discovery.subcategory = "divine";
|
||||
discovery.description = rollDivineFeature(specificroll);
|
||||
discovery.alignment = rollAlignment();
|
||||
discovery.aspect = rollAspect();
|
||||
}
|
||||
|
||||
return discovery;
|
||||
@@ -107,7 +122,9 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
|
||||
|
||||
if (subroll <= 2) {
|
||||
discovery.subcategory = "lair";
|
||||
discovery.description = rollLair(specificroll)
|
||||
discovery.description = rollLair(specificroll);
|
||||
discovery.creature = rollCreature();
|
||||
discovery.visibility = rollVisibility();
|
||||
} else if (subroll <= 4) {
|
||||
discovery.subcategory = "obstacle";
|
||||
discovery.description = rollObstacle(specificroll);
|
||||
@@ -121,8 +138,10 @@ export function rollNaturalFeature(roll: number = random(1, 12), subroll: number
|
||||
discovery.subcategory = "terrain change";
|
||||
discovery.description = rollLandmark(specificroll);
|
||||
} else if (subroll <= 12) {
|
||||
discovery.subcategory = "terrain change";
|
||||
discovery.subcategory = "resource";
|
||||
discovery.description = rollResource(specificroll);
|
||||
discovery.size = rollSize();
|
||||
discovery.visibility = rollVisibility();
|
||||
}
|
||||
|
||||
return discovery;
|
||||
@@ -148,9 +167,9 @@ export function rollObstacle(roll: number = random(1, 12)): string {
|
||||
if (roll <= 5) {
|
||||
return "difficult ground";
|
||||
} else if (roll <= 8) {
|
||||
return "cliff/crevasse/chasm";
|
||||
return sample(["cliff", "crevasse", "chasm"]);
|
||||
} else if (roll <= 10) {
|
||||
return "ravine/gorge";
|
||||
return sample(["ravine", "gorge"]);
|
||||
} else if (roll <= 12) {
|
||||
return rollOddity().description;
|
||||
}
|
||||
@@ -160,15 +179,15 @@ export function rollObstacle(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollTerrainChange(roll: number = random(1, 12)): string {
|
||||
if (roll <= 4) {
|
||||
return `limited area of ${rollTerrain()}`;
|
||||
return `limited area of ${rollTerrain().description}`;
|
||||
} else if (roll <= 6) {
|
||||
return "crevice/hole/pit/cave";
|
||||
return sample(["crevice", "hole", "pit", "cave"]);
|
||||
} else if (roll <= 8) {
|
||||
return "altitude change";
|
||||
} else if (roll <= 10) {
|
||||
return "canyon/valley";
|
||||
return sample(["canyon", "valley"]);
|
||||
} else if (roll <= 12) {
|
||||
return "rise/peak in distance";
|
||||
return sample(["rise", "peak in distance"]);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -176,17 +195,17 @@ export function rollTerrainChange(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollWaterFeature(roll: number = random(1, 12)): string {
|
||||
if (roll <= 1) {
|
||||
return "spring/hotspring";
|
||||
return sample(["spring", "hotspring"]);
|
||||
} else if (roll <= 2) {
|
||||
return "waterfall/geyser";
|
||||
return sample(["waterfall", "geyser"]);
|
||||
} else if (roll <= 6) {
|
||||
return "creek/stream/brook";
|
||||
return sample(["creek", "stream", "brook"]);
|
||||
} else if (roll <= 8) {
|
||||
return "pond/lake";
|
||||
return sample(["pond", "lake"]);
|
||||
} else if (roll <= 10) {
|
||||
return "river";
|
||||
} else if (roll <= 12) {
|
||||
return "sea/ocean";
|
||||
return sample(["sea", "ocean"]);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -208,15 +227,15 @@ export function rollLandmark(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollResource(roll: number = random(1, 12)): string {
|
||||
if (roll <= 4) {
|
||||
return "game/fruit/vegetable";
|
||||
return sample(["game", "fruit", "vegetable"]);
|
||||
} else if (roll <= 6) {
|
||||
return "herb/spice/dye source";
|
||||
return sample(["herb", "spice", "dye source"]);
|
||||
} else if (roll <= 9) {
|
||||
return "timber/stone";
|
||||
return sample(["timber", "stone"]);
|
||||
} else if (roll <= 11) {
|
||||
return "ore (copper, iron, etc.)";
|
||||
return sample(["copper ore", "iron ore", "tin ore", "silver ore"]);
|
||||
} else if (roll <= 12) {
|
||||
return "precious metal/gems";
|
||||
return sample(["precious metal", "precious gems"]);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -228,9 +247,13 @@ function rollEvidence(roll: number = random(1, 12), subroll: number = random(1,
|
||||
if (subroll <= 6) {
|
||||
discovery.subcategory = "tracks/spoor";
|
||||
discovery.description = rollTracksSpoor(specificroll);
|
||||
discovery.age = rollAge();
|
||||
discovery.creature = rollCreature();
|
||||
} else if (subroll <= 10) {
|
||||
discovery.subcategory = "remains/debris";
|
||||
discovery.description = rollRemainsDebris(specificroll);
|
||||
discovery.age = rollAge();
|
||||
discovery.visibility = rollVisibility();
|
||||
} else if (subroll <= 12) {
|
||||
discovery.subcategory = "stash/cache";
|
||||
discovery.description = rollStashCache(specificroll);
|
||||
@@ -305,15 +328,23 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
|
||||
if (subroll <= 1) {
|
||||
discovery.subcategory = "enigmatic";
|
||||
discovery.description = rollEnigmaticStructure(specificroll);
|
||||
discovery.age = rollAge(random(1, 8) + 4);
|
||||
discovery.size = rollSize(random(1, 8) + 4);
|
||||
discovery.visibility = rollVisibility();
|
||||
} else if (subroll <= 3) {
|
||||
discovery.subcategory = "infrastructure";
|
||||
discovery.description = rollInfrastructureStructure(specificroll);
|
||||
discovery.creature = rollCreature(random(1, 4) + 4);
|
||||
} else if (subroll <= 4) {
|
||||
discovery.subcategory = "dwelling";
|
||||
discovery.description = rollDwellingStructure(specificroll);
|
||||
discovery.creature = rollCreature(random(1, 4) + 4);
|
||||
} else if (subroll <= 6) {
|
||||
discovery.subcategory = "burial/religious";
|
||||
discovery.description = rollBurialReligiousStructure(specificroll);
|
||||
discovery.creature = rollCreature(random(1, 4) + 4);
|
||||
discovery.alignment = rollAlignment();
|
||||
discovery.aspect = rollAspect();
|
||||
} else if (subroll <= 8) {
|
||||
discovery.subcategory = "steading";
|
||||
discovery.steading = rollSteading();
|
||||
@@ -322,6 +353,10 @@ export function rollStructure(roll: number = random(1, 12), subroll: number = ra
|
||||
} else if (subroll <= 12) {
|
||||
discovery.subcategory = "ruin";
|
||||
discovery.description = rollRuinStructure(specificroll);
|
||||
discovery.creature = rollCreature(random(1, 4) + 4);
|
||||
discovery.age = rollAge(random(1, 8) + 4);
|
||||
discovery.ruination = rollRuination();
|
||||
discovery.visibility = rollVisibility();
|
||||
}
|
||||
|
||||
return discovery;
|
||||
@@ -343,15 +378,15 @@ export function rollEnigmaticStructure(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollInfrastructureStructure(roll: number = random(1, 12)): string {
|
||||
if (roll <= 4) {
|
||||
return "track/path";
|
||||
return sample(["track", "path"]);
|
||||
} else if (roll <= 8) {
|
||||
return "road";
|
||||
} else if (roll <= 10) {
|
||||
return "bridge/ford";
|
||||
return sample(["bridge", "ford"]);
|
||||
} else if (roll <= 11) {
|
||||
return "mine/quarry";
|
||||
return sample(["mine", "quarry"]);
|
||||
} else if (roll <= 12) {
|
||||
return "aqueduct/canal/portal";
|
||||
return sample(["aqueduct", "canal", "portal"]);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -361,13 +396,13 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
|
||||
if (roll <= 3) {
|
||||
return "campsite";
|
||||
} else if (roll <= 6) {
|
||||
return "hovel/hut";
|
||||
return sample(["hovel", "hut"]);
|
||||
} else if (roll <= 8) {
|
||||
return "farm";
|
||||
} else if (roll <= 10) {
|
||||
return "inn/roadhouse";
|
||||
return sample(["inn", "roadhouse"]);
|
||||
} else if (roll <= 12) {
|
||||
return "tower/keep/estate";
|
||||
return sample(["tower", "keep", "estate"]);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -375,15 +410,15 @@ export function rollDwellingStructure(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollBurialReligiousStructure(roll: number = random(1, 12)): string {
|
||||
if (roll <= 2) {
|
||||
return "grave marker/barrow";
|
||||
return sample(["grave marker", "grave barrow"]);
|
||||
} else if (roll <= 4) {
|
||||
return "graveyard/necropolis";
|
||||
return sample(["graveyard", "necropolis"]);
|
||||
} else if (roll <= 6) {
|
||||
return "tomb/crypt";
|
||||
return sample(["tomb", "crypt"]);
|
||||
} else if (roll <= 9) {
|
||||
return "shrine";
|
||||
} else if (roll <= 11) {
|
||||
return "temple/retreat";
|
||||
return sample(["temple", "retreat"]);
|
||||
} else if (roll <= 12) {
|
||||
return "great temple";
|
||||
}
|
||||
|
||||
+334
-13
@@ -1,27 +1,348 @@
|
||||
import { random, replace, sample, times } from "lodash";
|
||||
import { Creature, rollCreature, rollHumanoid, rollMonster } from "./creatures";
|
||||
import { rollElement, rollOddity } from "./details";
|
||||
|
||||
export class Dungeon {
|
||||
size: Size;
|
||||
ruination: string;
|
||||
builder: string;
|
||||
function: string;
|
||||
themes: string[];
|
||||
discovery: string;
|
||||
danger: string;
|
||||
ruination: Ruination;
|
||||
builder: Builder;
|
||||
function: DunFunction;
|
||||
commonThemes: Theme[] = [];
|
||||
uniqueThemes: Theme[] = [];
|
||||
commonAreas: (Discovery | Danger)[] = [];
|
||||
uniqueAreas: (Discovery | Danger)[] = [];
|
||||
|
||||
printDescription() {
|
||||
return `${this.size.size} ${this.builder} ${this.function}`;
|
||||
return `${this.size.description} ${this.function.description} built by ${this.builder.description}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class Size {
|
||||
constructor(public size: string = "", public themes: string = "", public areas: string = "") { };
|
||||
constructor(public roll: number = 0, public description: string = "", public commonThemes: number = 0, public uniqueThemes: number = 0, public commonAreas: number = 0, public uniqueAreas: number = 0) { };
|
||||
}
|
||||
|
||||
export class Ruination {
|
||||
constructor(public roll: number = 0, public description: string = "") { };
|
||||
}
|
||||
|
||||
export class Builder {
|
||||
constructor(public roll: number = 0, public description: string = "") { };
|
||||
}
|
||||
|
||||
export class DunFunction {
|
||||
constructor(public roll: number = 0, public description: string = "") { };
|
||||
}
|
||||
|
||||
export class Theme {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
|
||||
}
|
||||
|
||||
export class Discovery {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
|
||||
type: string = "discovery";
|
||||
}
|
||||
|
||||
export class Danger {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
|
||||
type: string = "danger";
|
||||
creature?: Creature;
|
||||
}
|
||||
|
||||
export function rollDungeon(): Dungeon {
|
||||
// TODO: Add the who dungeon thing
|
||||
let dungeon = new Dungeon();
|
||||
dungeon.size = new Size("huge");
|
||||
dungeon.builder = "dwarves";
|
||||
dungeon.function = "mine";
|
||||
dungeon.size = rollSize();
|
||||
dungeon.ruination = rollRuination();
|
||||
dungeon.builder = rollBuilder();
|
||||
dungeon.function = rollDunFunction();
|
||||
times(dungeon.size.commonThemes, () => dungeon.commonThemes.push(rollTheme()));
|
||||
times(dungeon.size.uniqueThemes, () => dungeon.uniqueThemes.push(rollTheme()));
|
||||
times(dungeon.size.commonAreas, () => dungeon.commonAreas.push(sample([rollDiscovery, rollDanger])()));
|
||||
times(dungeon.size.uniqueAreas, () => dungeon.uniqueAreas.push(sample([rollDiscovery, rollDanger])()));
|
||||
|
||||
return new Dungeon();
|
||||
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]);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { random } from 'lodash';
|
||||
import { random, sample } from 'lodash';
|
||||
|
||||
export class Kingdom {
|
||||
constructor(public description: string = "", public subtitle: string = "") { };
|
||||
@@ -53,3 +53,10 @@ export function rollKingdom(roll: number = random(1, 4)): Kingdom {
|
||||
|
||||
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
@@ -1,4 +1,5 @@
|
||||
import { random, sample } from 'lodash';
|
||||
import { capitalize, random, sample } from 'lodash';
|
||||
import { Activity, Alignment, rollActivity, rollAlignment } from './details';
|
||||
import { Follower, rollFollower } from './followers';
|
||||
import { kingdoms, rollKingdom } from './kingdoms';
|
||||
|
||||
@@ -7,11 +8,18 @@ export class Npc {
|
||||
|
||||
gender: "male" | "female";
|
||||
hometown: string;
|
||||
|
||||
context: Context;
|
||||
occupation: Occupation
|
||||
trait: Trait;
|
||||
follower: Follower;
|
||||
|
||||
getDescription(fullDesc: boolean = false) {
|
||||
let str = `${this.name} the ${this.gender} ${capitalize(this.occupation.category)} (${this.occupation.description})`;
|
||||
str += fullDesc ? ` from ${this.hometown}` : '';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function rollNpc(): Npc {
|
||||
@@ -31,7 +39,10 @@ export function rollNpc(): Npc {
|
||||
}
|
||||
|
||||
export class Context {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public subcategory: string = "") { };
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
|
||||
activity?: Activity;
|
||||
alignment?: Alignment;
|
||||
trait?: Trait;
|
||||
}
|
||||
|
||||
export function rollContext(): Context {
|
||||
@@ -40,71 +51,74 @@ export function rollContext(): Context {
|
||||
let context = new Context(roll, subroll);
|
||||
if (roll <= 3) {
|
||||
context.category = "wilderness";
|
||||
context.subcategory = rollWildernessNpc(subroll);
|
||||
context.description = rollWildernessNpc(subroll);
|
||||
} else if (roll <= 9) {
|
||||
context.category = "rural";
|
||||
context.subcategory = rollRuralNpc(subroll);
|
||||
context.description = rollRuralNpc(subroll);
|
||||
} else if (roll <= 12) {
|
||||
context.category = "urban";
|
||||
context.subcategory = rollUrbanNpc(subroll);
|
||||
context.description = rollUrbanNpc(subroll);
|
||||
}
|
||||
context.activity = rollActivity();
|
||||
context.alignment = rollAlignment();
|
||||
context.trait = rollTrait();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export function rollWildernessNpc(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
`${rollCriminal()} -4`,
|
||||
`${rollCriminal()} -4`,
|
||||
"adventurer/explorer",
|
||||
"adventurer/explorer",
|
||||
"hunter/gatherer",
|
||||
"hunter/gatherer",
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
"ranger/scout",
|
||||
"ranger/scout",
|
||||
"soldier/mercenary",
|
||||
rollOfficial(),
|
||||
`criminal ${rollCriminal()} -4`,
|
||||
`criminal ${rollCriminal()} -4`,
|
||||
"adventurer",
|
||||
"explorer",
|
||||
"hunter",
|
||||
"gatherer",
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
"ranger",
|
||||
"scout",
|
||||
sample(["soldier", "mercenary"]),
|
||||
`official ${rollOfficial()}`,
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
export function rollRuralNpc(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"beggar/urchin",
|
||||
`${rollCriminal()} -1`,
|
||||
"adventurer/explorer",
|
||||
"hunter/gatherer",
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollTradeperson(),
|
||||
`${rollMerchant()} -1`,
|
||||
"militia/soldier/guard",
|
||||
rollOfficial(),
|
||||
sample(["beggar", "urchin"]),
|
||||
`criminal ${rollCriminal()} -1`,
|
||||
sample(["adventurer", "explorer"]),
|
||||
sample(["hunter", "gatherer"]),
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`tradeperson ${rollTradeperson()}`,
|
||||
`merchant ${rollMerchant()} -1`,
|
||||
sample(["militia", "soldier", "guard"]),
|
||||
`official ${rollOfficial()}`,
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
export function rollUrbanNpc(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"beggar/urchin",
|
||||
"beggar/urchin",
|
||||
rollCriminal(),
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollCommoner(),
|
||||
rollTradeperson(),
|
||||
rollMerchant(),
|
||||
rollSpecialist(),
|
||||
"militia/soldier/guard",
|
||||
rollOfficial(),
|
||||
"beggar",
|
||||
"urchin",
|
||||
`commoner ${rollCriminal()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`commoner ${rollCommoner()}`,
|
||||
`tradeperson ${rollTradeperson()}`,
|
||||
`merchant ${rollMerchant()}`,
|
||||
`specialist ${rollSpecialist()}`,
|
||||
sample(["militia", "soldier", "guard"]),
|
||||
`official ${rollOfficial()}`,
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
export class Occupation {
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public subcategory: string = "") { };
|
||||
constructor(public roll: number = 0, public subroll: number = 0, public category: string = "", public description: string = "") { };
|
||||
}
|
||||
|
||||
export function rollOccupation(roll: number = random(1, 12), subroll: number = random(1, 12)): Occupation {
|
||||
@@ -112,22 +126,22 @@ export function rollOccupation(roll: number = random(1, 12), subroll: number = r
|
||||
let occupation = new Occupation(roll, subroll);
|
||||
if (roll <= 1) {
|
||||
occupation.category = "criminal";
|
||||
occupation.subcategory = rollCriminal(subroll);
|
||||
occupation.description = rollCriminal(subroll);
|
||||
} else if (roll <= 6) {
|
||||
occupation.category = "commoner";
|
||||
occupation.subcategory = rollCommoner(subroll);
|
||||
occupation.description = rollCommoner(subroll);
|
||||
} else if (roll <= 8) {
|
||||
occupation.category = "tradeperson";
|
||||
occupation.subcategory = rollTradeperson(subroll);
|
||||
occupation.description = rollTradeperson(subroll);
|
||||
} else if (roll <= 10) {
|
||||
occupation.category = "merchant";
|
||||
occupation.subcategory = rollMerchant(subroll);
|
||||
occupation.description = rollMerchant(subroll);
|
||||
} else if (roll <= 11) {
|
||||
occupation.category = "specialist";
|
||||
occupation.subcategory = rollSpecialist(subroll);
|
||||
occupation.description = rollSpecialist(subroll);
|
||||
} else if (roll <= 12) {
|
||||
occupation.category = "officiail";
|
||||
occupation.subcategory = rollOfficial(subroll);
|
||||
occupation.category = "official";
|
||||
occupation.description = rollOfficial(subroll);
|
||||
}
|
||||
|
||||
return occupation;
|
||||
@@ -135,15 +149,15 @@ export function rollOccupation(roll: number = random(1, 12), subroll: number = r
|
||||
|
||||
function rollCriminal(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"bandit/brigand/thug",
|
||||
"bandit/brigand/thug",
|
||||
sample(["bandit", "brigand", "thug"]),
|
||||
sample(["bandit", "brigand", "thug"]),
|
||||
"thief",
|
||||
"thief",
|
||||
"bodyguard/tough",
|
||||
"bodyguard/tough",
|
||||
"bodyguard",
|
||||
"tough",
|
||||
"burglar",
|
||||
"burglar",
|
||||
"dealer/fence",
|
||||
sample(["dealer", "fence"]),
|
||||
"racketeer",
|
||||
"lieutenant",
|
||||
"boss"
|
||||
@@ -153,66 +167,66 @@ function rollCriminal(roll: number = random(1, 12)): string {
|
||||
function rollCommoner(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"housewife/husband",
|
||||
"hunter/gatherer",
|
||||
"hunter/gatherer",
|
||||
"farmer/herder",
|
||||
"farmer/herder",
|
||||
"farmer/herder",
|
||||
"laborer/servant",
|
||||
"laborer/servant",
|
||||
"driver/porter/guide",
|
||||
"sailor/soldier/guard",
|
||||
"clergy/monk",
|
||||
"apprentice/adventurer"
|
||||
"hunter",
|
||||
"gatherer",
|
||||
"farmer",
|
||||
"herder",
|
||||
sample(["farmer", "herder"]),
|
||||
"laborer",
|
||||
"servant",
|
||||
sample(["driver", "porter", "guide"]),
|
||||
sample(["sailor", "soldier", "guard"]),
|
||||
sample(["clergy", "monk"]),
|
||||
sample(["apprentice", "adventurer"]),
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
function rollTradeperson(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"cobbler/furrier/tailor",
|
||||
"weaver/basketmaker",
|
||||
"potter/carpenter",
|
||||
"mason/baker/chandler",
|
||||
"cooper/wheelwright",
|
||||
"tanner/ropemaker",
|
||||
"smith/tinker",
|
||||
"stablekeeper/herbalist",
|
||||
"vintner/jeweler",
|
||||
"inkeeper/tavernkeeper",
|
||||
"artist/actor/minstrel",
|
||||
"armorer/weaponsmith",
|
||||
sample(["cobbler", "furrier", "tailor"]),
|
||||
sample(["weaver", "basketmaker"]),
|
||||
sample(["potter", "carpenter"]),
|
||||
sample(["mason", "baker", "chandler"]),
|
||||
sample(["cooper", "wheelwright"]),
|
||||
sample(["tanner", "ropemaker"]),
|
||||
sample(["smith", "tinker"]),
|
||||
sample(["stablekeeper", "herbalist"]),
|
||||
sample(["vintner", "jeweler"]),
|
||||
sample(["inkeeper", "tavernkeeper"]),
|
||||
sample(["artist", "actor", "minstrel"]),
|
||||
sample(["armorer", "weaponsmith"]),
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
function rollMerchant(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"general goods/outfitter",
|
||||
"general goods/outfitter",
|
||||
"general goods/outfitter",
|
||||
"general goods",
|
||||
"outfitter",
|
||||
sample(["general goods", "outfitter"]),
|
||||
"raw materials",
|
||||
"grain/livestock",
|
||||
"ale/wine/spirits",
|
||||
"clothing/jewelry",
|
||||
"weapons/armor",
|
||||
"spices/tobacco",
|
||||
"labor/slaves",
|
||||
"books/scrolls",
|
||||
"magic supplies/items"
|
||||
sample(["grain", "livestock"]),
|
||||
sample(["ale", "wine", "spirits"]),
|
||||
sample(["clothing", "jewelry"]),
|
||||
sample(["weapons", "armor"]),
|
||||
sample(["spices", "tobacco"]),
|
||||
sample(["labor", "slaves"]),
|
||||
sample(["books", "scrolls"]),
|
||||
sample(["magic supplies", "magic items"]),
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
function rollSpecialist(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"undertaker",
|
||||
"sage/scholar/wizard",
|
||||
"writer/illuminator",
|
||||
sample(["sage", "scholar", "wizard"]),
|
||||
sample(["writer", "illuminator"]),
|
||||
"perfumer",
|
||||
"architect/engineer",
|
||||
"locksmith/clockmaker",
|
||||
"physician/apothecary",
|
||||
"navigator/guide",
|
||||
"alchemist/astrologer",
|
||||
"spy/diplomat",
|
||||
sample(["architect", "engineer"]),
|
||||
sample(["locksmith", "clockmaker"]),
|
||||
sample(["physician", "apothecary"]),
|
||||
sample(["navigator", "guide"]),
|
||||
sample(["alchemist", "astrologer"]),
|
||||
sample(["spy", "diplomat"]),
|
||||
"cartographer",
|
||||
"inventor"
|
||||
][roll - 1];
|
||||
@@ -222,16 +236,16 @@ function rollOfficial(roll: number = random(1, 12)): string {
|
||||
return [
|
||||
"town crier",
|
||||
"tax collector",
|
||||
"armiger/gentry",
|
||||
"armiger/gentry",
|
||||
"reeve/sheriff/constable",
|
||||
"mayor/magistrate",
|
||||
"priest/bishop/abbot",
|
||||
"armiger",
|
||||
"gentry",
|
||||
sample(["reeve", "sheriff", "constable"]),
|
||||
sample(["mayor", "magistrate"]),
|
||||
sample(["priest", "bishop", "abbot"]),
|
||||
"guildmaster",
|
||||
"knightltemplar",
|
||||
"elder/high priest",
|
||||
sample(["elder", "high priest"]),
|
||||
"noble (baron, etc.)",
|
||||
"lord/lady/king/queen",
|
||||
sample(["lord", "lady", "king", "queen"]),
|
||||
][roll - 1];
|
||||
}
|
||||
|
||||
@@ -259,15 +273,15 @@ function rollAppearance(roll: number = random(1, 12)): string {
|
||||
let appearance = [
|
||||
"disfigured (missing teeth, eye, etc.)",
|
||||
"lasting injury (bad leg, arm, etc.)",
|
||||
"tattooed/pockmarked/scarred",
|
||||
"unkempt/shabby/grubby",
|
||||
"big/thick/brawny",
|
||||
"small/scrawny/emaciated",
|
||||
sample(["tattooed", "pockmarked", "scarred"]),
|
||||
sample(["unkempt", "shabby", "grubby"]),
|
||||
sample(["big", "thick", "brawny"]),
|
||||
sample(["small", "scrawny", "emaciated"]),
|
||||
"notable hair (wild, long, none, etc.)",
|
||||
"notable nose (big, hooked, etc.)",
|
||||
"notable eyes (blue, bloodshot, etc.)",
|
||||
"clean/well-dressed/well-groomed",
|
||||
"attractive/handsome/stunning",
|
||||
sample(["clean", "well-dressed", "well-groomed"]),
|
||||
sample(["attractive", "handsome", "stunning"]),
|
||||
"they are [APPEARANCE] despite [a contradictory detail of your choice]"
|
||||
][roll - 1];
|
||||
|
||||
@@ -276,17 +290,17 @@ function rollAppearance(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollPersonality(roll: number = random(1, 12)): string {
|
||||
let personality = [
|
||||
"loner/alienated/antisocial",
|
||||
"cruel/belligerent/bully",
|
||||
"anxious/fearful/cowardly",
|
||||
"envious/covetous/greedy",
|
||||
"aloof/haughty/arrogant",
|
||||
"awkward/shy/self-loathing",
|
||||
"orderly/compulsive/controlling",
|
||||
"confident/impulsive/reckless",
|
||||
"kind/generous/compassionate",
|
||||
"easygoing/relaxed/peaceful",
|
||||
"cheerful/happy/optimistic",
|
||||
sample(["loner", "alienated", "antisocial"]),
|
||||
sample(["cruel", "belligerent", "bully"]),
|
||||
sample(["anxious", "fearful", "cowardly"]),
|
||||
sample(["envious", "covetous", "greedy"]),
|
||||
sample(["aloof", "haughty", "arrogant"]),
|
||||
sample(["awkward", "shy", "self-loathing"]),
|
||||
sample(["orderly", "compulsive", "controlling"]),
|
||||
sample(["confident", "impulsive", "reckless"]),
|
||||
sample(["kind", "generous", "compassionate"]),
|
||||
sample(["easygoing", "relaxed", "peaceful"]),
|
||||
sample(["cheerful", "happy", "optimistic"]),
|
||||
"they are [PERSONALITY] despite [a contradictory detail of your choice]",
|
||||
][roll - 1];
|
||||
|
||||
@@ -295,17 +309,17 @@ export function rollPersonality(roll: number = random(1, 12)): string {
|
||||
|
||||
export function rollQuirk(roll: number = random(1, 12)): string {
|
||||
let quirk = [
|
||||
"insecure/racist/xenophobic",
|
||||
"addict (sweets, drugs, sex, etc.)",
|
||||
"phobia (spiders, fire, darkness, etc.)",
|
||||
"allergic/asthmatic/chronically ill",
|
||||
"skeptic/paranoid",
|
||||
"superstitious/devout/fanatical",
|
||||
"miser/pack-rat",
|
||||
"spendthrift/wastrel",
|
||||
"smart aleck/know-it-all",
|
||||
"artistic/dreamer/delusional",
|
||||
"naive/idealistic",
|
||||
sample(["insecure", "racist", "xenophobic"]),
|
||||
sample(["addict (sweets, drugs, sex, etc.)"]),
|
||||
sample(["phobia (spiders, fire, darkness, etc.)"]),
|
||||
sample(["allergic", "asthmatic", "chronically ill"]),
|
||||
sample(["skeptic", "paranoid"]),
|
||||
sample(["superstitious", "devout", "fanatical"]),
|
||||
sample(["miser", "pack-rat"]),
|
||||
sample(["spendthrift", "wastrel"]),
|
||||
sample(["smart aleck", "know-it-all"]),
|
||||
sample(["artistic", "dreamer", "delusional"]),
|
||||
sample(["naive", "idealistic"]),
|
||||
"they are [QUIRK] despite [a contradictory detail of your choice]",
|
||||
][roll - 1];
|
||||
|
||||
|
||||
+10
-1
@@ -1,3 +1,6 @@
|
||||
import { sample } from "lodash";
|
||||
import { bodgeString } from "./utils";
|
||||
|
||||
export const places = {
|
||||
templates: [
|
||||
'The [PLACE]',
|
||||
@@ -10,5 +13,11 @@ export const places = {
|
||||
place: ['Barrier', 'Beach', 'Bowl', 'Camp', 'Cave', 'Circle', 'City', 'Cliff', 'Crater', 'Crossing', 'Crypt', 'Den', 'Ditch', 'Falls', 'Fence', 'Field', 'Fort', 'Gate', 'Grove', 'Hill', 'Hole', 'Hut', 'Keep', 'Lake', 'Marsh', 'Meadow', 'Mountain', 'Pit', 'Post', 'Ridge', 'Ring', 'Rise', 'Road', 'Rock', 'Ruin', 'Shrine', 'Spire', 'Spring', 'Stone', 'Tangle', 'Thmple', 'Throne', 'Tomb', 'Tower', 'Town', 'Tree', 'Vale', 'Valley', 'Village', 'Wall',],
|
||||
adjective: ['Ancient', 'Ashen', 'Black', 'Bloody', 'Blue', 'Bright', 'Broken', 'Burning', 'Clouded', 'Copper', 'Cracked', 'Dark', 'Dead', 'Doomed', 'Endless', 'Fallen', 'Far', 'Fearsome', 'Floating', 'Forbidden', 'Frozen', 'Ghostly', 'Gloomy', 'Golden', 'Grim', 'Hidden', 'High', 'Iron', 'Jagged', 'Lonely', 'Lost', 'Low', 'Near', 'Petrified', 'Red', 'Screaming', 'Sharp', 'Shattered', 'Shifting', 'Shining', 'Shivering', 'Shrouded', 'Silver', 'Stalwart', 'Stoney', 'Sunken', 'Thorny', 'Thundering', 'White', 'Withered',],
|
||||
noun: ['[Name]', 'Arm', 'Ash', 'Blood', 'Child', 'Cinder', 'Corpse', 'Crystal', 'Dagger', 'Death', 'Demon', 'Devil', 'Doom', 'Eye', 'Fear', 'Finger', 'Fire', 'Foot', 'Ghost', 'Giant', 'Goblin', 'God', 'Gold', 'Hand', 'Head', 'Heart', 'Hero', 'Hope', 'King', 'Knave', 'Knight', 'Muck', 'Mud', 'Priest', 'Queen', 'Sailor', 'Silver', 'Skull', 'Smoke', 'Souls', 'Spear', 'Spirit', 'Stone', 'Sword', 'Thief', 'Troll', 'Warrior', 'Water', 'Witch', 'Wizard',],
|
||||
// * Choose a name appropriate to your setting; or, if you have a name list, roll one up.
|
||||
};
|
||||
|
||||
export function rollPlace(): string {
|
||||
let template = sample(places.templates);
|
||||
let place = bodgeString(template, places);
|
||||
|
||||
return place;
|
||||
}
|
||||
+10
-1
@@ -1,3 +1,6 @@
|
||||
import { sample } from "lodash";
|
||||
import { bodgeString } from "./utils";
|
||||
|
||||
export const regions = {
|
||||
templates: [
|
||||
'[ADJECTIVE] [TERRAIN]',
|
||||
@@ -10,5 +13,11 @@ export const regions = {
|
||||
terrain: ['Bay', 'Bluffs', 'Bog', 'Cliffs', 'Desert', 'Downs', 'Dunes', 'Expanse', 'Fells', 'Fen', 'Flats', 'Foothills', 'Forest', 'Groves', 'Heath', 'Heights', 'Hills', 'Hollows', 'Jungle', 'Lake', 'Lowland', 'March', 'Marsh', 'Meadows', 'Moor', 'Morass', 'Mounds', 'Mountains', 'Peaks', 'Plains', 'Prairie', 'Quagmire', 'Range', 'Reach', 'Sands', 'Savanna', 'Scarps', 'Sea', 'Slough', 'Sound', 'Steppe', 'Swamp', 'Sweep', 'Teeth', 'Thicket', 'Upland', 'Wall', 'Waste', 'Wasteland', 'Woods',],
|
||||
adjective: ['Ageless', 'Ashen', 'Black', 'Blessed', 'Blighted', 'Blue', 'Broken', 'Burning', 'Cold', 'Cursed', 'Dark', 'Dead', 'Deadly', 'Deep', 'Desolate', 'Diamond', 'Dim', 'Dismal', 'Dun', 'Eerie', 'Endless', 'Fallen', 'Far', 'Fell', 'Flaming', 'Forgotten', 'Forsaken', 'Frozen', 'Glittering', 'Golden', 'Green', 'Grim', 'Holy', 'Impassable', 'Jagged', 'Light', 'Long', 'Misty', 'Perilous', 'Purple', 'Red', 'Savage', 'Shadowy', 'Shattered', 'Shifting', 'Shining', 'Silver', 'White', 'Wicked', 'Yellow',],
|
||||
noun: ['[NAME]', 'Ash', 'Bone', 'Darkness', 'Dead', 'Death', 'Desolation', 'Despair', 'Devil', 'Doom', 'Dragon', 'Fate', 'Fear', 'Fire', 'Fury', 'Ghost', 'Giant', 'God', 'Gold', 'Heaven', 'Hell', 'Honor', 'Hope', 'Horror', 'King', 'Life', 'Light', 'Lord', 'Mist', 'Peril', 'Queen', 'Rain', 'Refuge', 'Regret', 'Savior', 'Shadow', 'Silver', 'Skull', 'Sky', 'Smoke', 'Snake', 'Sorrow', 'Storm', 'Sun', 'Thorn', 'Thunder', 'Traitor', 'Troll', 'Victory', 'Witch',]
|
||||
// * Choose a name appropriate to your setting; or, if you have a name list, roll one up. Dw THE MAP
|
||||
};
|
||||
|
||||
export function rollRegion(): string {
|
||||
let template = sample(regions.templates);
|
||||
let region = bodgeString(template, regions);
|
||||
|
||||
return region;
|
||||
}
|
||||
+12
-10
@@ -1,17 +1,19 @@
|
||||
import { random, sample } from 'lodash';
|
||||
import { Creature, rollCreature } from './creatures';
|
||||
import type { Kingdom } from './kingdoms';
|
||||
|
||||
export class Steading {
|
||||
constructor(public roll: number = 0, public category: string = "") { };
|
||||
builtBy: string;
|
||||
description: string;
|
||||
kingdom: string;
|
||||
constructor(public roll: number = 0, public category: string = "", public description: string = "") { };
|
||||
builtBy: Creature;
|
||||
kingdom: Kingdom;
|
||||
problem: string;
|
||||
}
|
||||
|
||||
// This section is gonna need a lot of work
|
||||
// TODO: This section is gonna need a lot of work
|
||||
export function rollSteading(roll: number = random(1, 12)): Steading {
|
||||
let steading = new Steading();
|
||||
// STEADING Choose or roll 1d4 + 4 on the first CREATURE table(page 49) to see who builtit.
|
||||
steading.builtBy = rollCreature(random(1, 4) + 4);
|
||||
|
||||
if (roll <= 5) {
|
||||
steading = rollVillage();
|
||||
} else if (roll <= 8) {
|
||||
@@ -28,19 +30,19 @@ export function rollSteading(roll: number = random(1, 12)): Steading {
|
||||
|
||||
|
||||
export function rollVillage(): Steading {
|
||||
return new Steading(0, "village");
|
||||
return new Steading(0, "village", "village");
|
||||
}
|
||||
|
||||
export function rollTown(): Steading {
|
||||
return new Steading(0, "town");
|
||||
return new Steading(0, "town", "town");
|
||||
}
|
||||
|
||||
export function rollKeep(): Steading {
|
||||
return new Steading(0, "keep");
|
||||
return new Steading(0, "keep", "keep");
|
||||
}
|
||||
|
||||
export function rollCity(): Steading {
|
||||
return new Steading(0, "city");
|
||||
return new Steading(0, "city", "city");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user