add lots of cool features

add side nav
add clipboard
add remove
This commit is contained in:
RussellChamp committed 2021-08-21 16:02:35 -04:00
1 parent 5949b6ad33
commit 9e8a22cd62
28 files changed
+428 -303

No files matched your search

+1
View File
@@ -2,4 +2,5 @@ Add Steadings tables
Change steadings and mounts to not show English names by default Change steadings and mounts to not show English names by default
Make everything look nicer Make everything look nicer
Maybe put roller button in a left nav bar and the results in the middle? Maybe put roller button in a left nav bar and the results in the middle?
Add a copy-to-clipboard option
Add a 3d dice rolling visualizer Add a 3d dice rolling visualizer
+67 -45
View File
@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { Accordion, AccordionHeader, AccordionItem } from "sveltestrap"; import { format as formatDate } from "date-fns";
import { Accordion, AccordionHeader, AccordionItem, Container, Row, Col } from "sveltestrap";
import SoundOptions from "./components/SoundOptions.svelte"; import SoundOptions from "./components/SoundOptions.svelte";
import CreatureRoller from "./components/CreatureRoller.svelte"; import CreatureRoller from "./components/CreatureRoller.svelte";
@@ -14,16 +15,26 @@
import RegionRoller from "./components/RegionRoller.svelte"; import RegionRoller from "./components/RegionRoller.svelte";
import SteadingRoller from "./components/SteadingRoller.svelte"; import SteadingRoller from "./components/SteadingRoller.svelte";
import Footer from "./components/Footer.svelte"; import Footer from "./components/Footer.svelte";
import MultiCard from "./components/MultiCard.svelte";
import { RollCard } from "./types/RollCard";
let rollThemBones = new Audio("https://soundbible.com/mp3/Shake And Roll Dice-SoundBible.com-591494296.mp3"); let rollThemBones = new Audio("https://soundbible.com/mp3/Shake And Roll Dice-SoundBible.com-591494296.mp3");
let playSounds = true; let playSounds = localStorage?.getItem("playSounds") != "false";
let timeout: NodeJS.Timeout; let timeout: NodeJS.Timeout;
let cards: RollCard[] = [];
function setSoundOptions(event: any) { function setSoundOptions(event: CustomEvent<{ soundEnabled: boolean }>) {
playSounds = event.detail.soundEnabled; playSounds = event.detail.soundEnabled;
localStorage?.setItem("playSounds", String(playSounds));
} }
function handleRoll(event: any) { function handleRoll(event: CustomEvent<{ type: string; value: any }>) {
let timestamp = formatDate(new Date(), "P kk:mm:ss");
cards = [new RollCard(event?.detail?.type, event?.detail?.value, timestamp), ...cards];
playAudio();
}
function playAudio() {
clearTimeout(timeout); clearTimeout(timeout);
rollThemBones.pause(); rollThemBones.pause();
rollThemBones.currentTime = 0; rollThemBones.currentTime = 0;
@@ -40,50 +51,57 @@
}, playTime); }, playTime);
} }
} }
function remove(event: CustomEvent<RollCard>) {
cards = cards.filter((c) => c.timestamp != event.detail.timestamp);
}
</script> </script>
<main> <main>
<h1>The Perilous Wilds</h1> <Container fluid={true}>
<h2>A web-app for rolling on tables and getting funny results</h2> <Row>
<hr /> <h1>The Perilous Wilds</h1>
<SoundOptions on:soundToggle={setSoundOptions} /> <h2>A web-app for rolling on tables and getting funny results</h2>
<hr /> <hr />
<Accordion> </Row>
<AccordionItem active header="Creatures"> <Row>
<CreatureRoller on:roll={handleRoll} /> <Col sm="3">
</AccordionItem> <div class="sidebar">
<AccordionItem header="Dangers"> <h3>Rollers:</h3>
<DangerRoller on:roll={handleRoll} /> <hr />
</AccordionItem> <CreatureRoller on:roll={handleRoll} />
<AccordionItem header="Details"> <DangerRoller on:roll={handleRoll} />
<DetailsRoller on:roll={handleRoll} /> <DiscoveryRoller on:roll={handleRoll} />
</AccordionItem> <DungeonRoller on:roll={handleRoll} />
<AccordionItem header="Discoveries"> <FollowerRoller on:roll={handleRoll} />
<DiscoveryRoller on:roll={handleRoll} /> <NpcRoller on:roll={handleRoll} />
</AccordionItem> <PlaceRoller on:roll={handleRoll} />
<AccordionItem header="Dungeons"> <RegionRoller on:roll={handleRoll} />
<DungeonRoller on:roll={handleRoll} /> <SteadingRoller on:roll={handleRoll} />
</AccordionItem>
<AccordionItem header="Followers"> <h3>Kingdom:</h3>
<FollowerRoller on:roll={handleRoll} /> <KingdomRoller on:roll={handleRoll} />
</AccordionItem>
<AccordionItem header="Kingdoms"> <h3>Details:</h3>
<KingdomRoller on:roll={handleRoll} /> <DetailsRoller on:roll={handleRoll} />
</AccordionItem>
<AccordionItem header="NPCs"> <hr />
<NpcRoller on:roll={handleRoll} />
</AccordionItem> <h3>Options</h3>
<AccordionItem header="Places"> <SoundOptions soundEnabled={playSounds} on:soundToggle={setSoundOptions} />
<PlaceRoller on:roll={handleRoll} /> </div>
</AccordionItem> </Col>
<AccordionItem header="Regions"> <Col sm="9">
<RegionRoller on:roll={handleRoll} /> <h3>Results:</h3>
</AccordionItem> {#each cards as card}
<AccordionItem header="Steadings"> <MultiCard {card} on:remove={remove} />
<SteadingRoller on:roll={handleRoll} /> {/each}
</AccordionItem> </Col>
</Accordion> </Row>
<Footer /> <Row>
<Footer />
</Row>
</Container>
</main> </main>
<style> <style>
@@ -101,6 +119,10 @@
font-weight: 100; font-weight: 100;
} }
.sidebar {
background-color: rgba(0, 0, 0, 0.03);
}
@media (min-width: 640px) { @media (min-width: 640px) {
main { main {
max-width: none; max-width: none;
+26
View File
@@ -0,0 +1,26 @@
<script lang="ts">
import { capitalize } from "lodash";
import { Button, Icon, Tooltip } from "sveltestrap";
export let dataType: string;
export let data: any;
function handleClick() {
if (data) {
prompt(`${capitalize(dataType)} data`, JSON.stringify(data));
// This won't work until I support a https connection
// navigator.clipboard.writeText(JSON.stringify(data));
}
}
</script>
<main>
<Button id="copyHelper" color="secondary" on:click={handleClick}>
<Icon name="clipboard-data" />
</Button>
<Tooltip target="copyHelper" placement="top">Copy to Clipboard</Tooltip>
</main>
<style>
</style>
+43 -7
View File
@@ -1,23 +1,55 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from "svelte";
import { capitalize } from "lodash"; import { capitalize } from "lodash";
import { Card, CardHeader, CardTitle, CardBody, CardSubtitle, CardText, CardFooter, Container, Row } from "sveltestrap"; import {
Card,
CardHeader,
CardTitle,
CardBody,
CardSubtitle,
CardText,
CardFooter,
Container,
Row,
Button,
Icon,
Tooltip,
} from "sveltestrap";
import ClipboardHelper from "./ClipboardHelper.svelte";
import NpcCard from "./NpcCard.svelte"; import NpcCard from "./NpcCard.svelte";
import DieIcon from "./DieIcon.svelte"; import DieIcon from "./DieIcon.svelte";
import type { Creature } from "../rollers/creatures"; import type { Creature } from "../rollers/creatures";
const dispatch = createEventDispatcher();
export let creature: Creature; export let creature: Creature;
export let timestamp: string; export let timestamp: string;
function remove() {
dispatch("remove");
}
</script> </script>
<main> <main>
<Card class="mb-3"> <Card class="mb-3">
<CardHeader> <CardHeader>
<CardTitle> <CardTitle>
{capitalize(creature.type)}<DieIcon value={creature.roll} /> <div class="title">
{#if creature.subtype !== ""}({creature.subtype})<DieIcon value={creature.subroll} />{/if}: {capitalize( <div class="description">
creature.description {capitalize(creature.type)}<DieIcon value={creature.roll} />
)}<DieIcon value={creature.specificroll} /> {#if creature.subtype !== ""}({creature.subtype})<DieIcon value={creature.subroll} />{/if}: {capitalize(
creature.description
)}<DieIcon value={creature.specificroll} />
</div>
<div class="buttons">
<ClipboardHelper data={creature} dataType="creature" />
<Button id="remove" outline color="danger" on:click={remove}>
<Icon name="x" />
</Button>
<Tooltip target="remove" placement="top">Remove Item</Tooltip>
</div>
</div>
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardBody> <CardBody>
@@ -72,8 +104,12 @@
main { main {
text-align: left; text-align: left;
} }
.card-subtitle { .title {
padding-bottom: 1em; display: flex;
justify-content: space-between;
}
.title .buttons {
display: flex;
} }
ul { ul {
margin-left: 2em; margin-left: 2em;
+2 -13
View File
@@ -1,30 +1,19 @@
<script lang="ts"> <script lang="ts">
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import CreatureCard from "./CreatureCard.svelte"; import { rollCreature } from "../rollers/creatures";
import { Creature, rollCreature } from "../rollers/creatures";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let rollResults: { creature: Creature; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let creature = rollCreature(); let creature = rollCreature();
rollResults = [{ creature, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "creature", value: creature });
dispatch("roll");
} }
</script> </script>
<main> <main>
<Button color="primary" on:click={roll}>Roll Creature</Button> <Button color="primary" on:click={roll}>Roll Creature</Button>
{#each rollResults as { creature, timestamp }}
<CreatureCard {creature} {timestamp} />
{/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
</style> </style>
+41
View File
@@ -0,0 +1,41 @@
<script lang="ts">
import { capitalize } from "lodash";
import { Card, CardHeader, CardTitle, CardBody, CardText, CardFooter, Icon } from "sveltestrap";
import type { Danger } from "../rollers/dangers";
import DieIcon from "./DieIcon.svelte";
export let danger: Danger;
export let timestamp: string;
let icon = "";
$: icon =
danger.category == "unnatural entity"
? "person-square"
: danger.category == "hazard"
? "lightning-fill"
: danger.category == "creature"
? "emoji-neutral"
: "";
</script>
<main>
<Card class="mb-3">
<CardHeader>
<CardTitle>
{capitalize(danger.category)}<DieIcon value={danger.roll} />
{#if danger.subcategory !== ""}({danger.subcategory})<DieIcon value={danger.subroll} />{/if}: {capitalize(
danger.description
)}<DieIcon value={danger.specificroll} />
</CardTitle>
</CardHeader>
<CardBody>
<CardText>
<Icon name={icon} />: {danger.description}
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
</main>
<style>
</style>
+4 -24
View File
@@ -1,38 +1,18 @@
<script lang="ts"> <script lang="ts">
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button, Icon } from "sveltestrap"; import { Button } from "sveltestrap";
import { Danger, rollDanger } from "../rollers/dangers"; import { rollDanger } from "../rollers/dangers";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { danger: Danger; icon: string; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let danger = rollDanger(); let danger = rollDanger();
let icon = dispatch("roll", { type: "danger", value: danger });
danger.category == "unnatural entity"
? "person-square"
: danger.category == "hazard"
? "lightning-fill"
: danger.category == "creature"
? "emoji-neutral"
: "";
rollResults = [{ danger, icon, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults];
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Danger</Button>
<Button color="primary" on:click={roll}>Roll Danger</Button>
</span>
{#each rollResults as { danger, icon, timestamp }}
<h4>
{timestamp}: {danger.category} ({danger.subcategory}) <Icon name={icon} />: {danger.description}
</h4>
{/each}
</main> </main>
<style> <style>
+28
View File
@@ -0,0 +1,28 @@
<script lang="ts">
import { capitalize } from "lodash";
import { Card, CardHeader, CardTitle, CardBody, CardText, CardFooter } from "sveltestrap";
import type { Detail } from "../rollers/details";
import DieIcon from "./DieIcon.svelte";
export let detail: Detail;
export let timestamp: string;
</script>
<main>
<Card class="mb-3">
<CardHeader>
<CardTitle>
{capitalize(detail.type)}
</CardTitle>
</CardHeader>
<CardBody>
<CardText>
{detail.description}<DieIcon value={detail.roll} />
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
</main>
<style>
</style>
+23 -73
View File
@@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button, Icon } from "sveltestrap"; import { Button } from "sveltestrap";
import { import {
Detail,
rollAbility, rollAbility,
rollActivity, rollActivity,
rollAdjective, rollAdjective,
@@ -24,83 +24,33 @@
rollVisibility, rollVisibility,
} from "../rollers/details"; } from "../rollers/details";
import DieIcon from "./DieIcon.svelte";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let rollResults: { type: string; roll: number; value: string; timestamp: string }[] = []; function roll(value: Detail) {
dispatch("roll", { type: "detail", value });
function roll(item: { type: string; description: string; roll: number }) {
rollResults = [
{ type: item.type, roll: item.roll, value: item.description, timestamp: formatDate(new Date(), "P kk:mm:ss") },
...rollResults,
];
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={() => roll(rollAbility())}>Roll Ability</Button>
<Button color="primary" on:click={() => roll(rollAbility())}>Roll Ability</Button> <Button color="primary" on:click={() => roll(rollActivity())}>Roll Activity</Button>
</span> <Button color="primary" on:click={() => roll(rollAdjective())}>Roll Adjective</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollAge())}>Roll Age</Button>
<Button color="primary" on:click={() => roll(rollActivity())}>Roll Activity</Button> <Button color="primary" on:click={() => roll(rollAlignment())}>Roll Alignment</Button>
</span> <Button color="primary" on:click={() => roll(rollAspect())}>Roll Aspect</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollCondition())}>Roll Condition</Button>
<Button color="primary" on:click={() => roll(rollAdjective())}>Roll Adjective</Button> <Button color="primary" on:click={() => roll(rollDisposition())}>Roll Disposition</Button>
</span> <Button color="primary" on:click={() => roll(rollElement())}>Roll Element</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollFeature())}>Roll Feature</Button>
<Button color="primary" on:click={() => roll(rollAge())}>Roll Age</Button> <Button color="primary" on:click={() => roll(rollMagicType())}>Roll MagicType</Button>
</span> <Button color="primary" on:click={() => roll(rollNumAppearing())}>Roll NumAppearing</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollOddity())}>Roll Oddity</Button>
<Button color="primary" on:click={() => roll(rollAlignment())}>Roll Alignment</Button> <Button color="primary" on:click={() => roll(rollOrientation())}>Roll Orientation</Button>
</span> <Button color="primary" on:click={() => roll(rollRuination())}>Roll Ruination</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollSize())}>Roll Size</Button>
<Button color="primary" on:click={() => roll(rollAspect())}>Roll Aspect</Button> <Button color="primary" on:click={() => roll(rollTag())}>Roll Tag</Button>
</span> <Button color="primary" on:click={() => roll(rollTerrain())}>Roll Terrain</Button>
<span class="btn"> <Button color="primary" on:click={() => roll(rollVisibility())}>Roll Visibility</Button>
<Button color="primary" on:click={() => roll(rollCondition())}>Roll Condition</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollDisposition())}>Roll Disposition</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollElement())}>Roll Element</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollFeature())}>Roll Feature</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollMagicType())}>Roll MagicType</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollNumAppearing())}>Roll NumAppearing</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollOddity())}>Roll Oddity</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollOrientation())}>Roll Orientation</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollRuination())}>Roll Ruination</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollSize())}>Roll Size</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollTag())}>Roll Tag</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollTerrain())}>Roll Terrain</Button>
</span>
<span class="btn">
<Button color="primary" on:click={() => roll(rollVisibility())}>Roll Visibility</Button>
</span>
{#each rollResults as { type, roll, value, timestamp }}
<h4>{timestamp}: ({type}): {value}<DieIcon value={roll} /></h4>
{/each}
</main> </main>
<style> <style>
+3 -24
View File
@@ -1,40 +1,19 @@
<script lang="ts"> <script lang="ts">
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import DiscoveryCard from "./DiscoveryCard.svelte"; import { rollDiscovery } from "../rollers/discoveries";
import { Discovery, rollDiscovery } from "../rollers/discoveries";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { discovery: Discovery; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let discovery = rollDiscovery(); let discovery = rollDiscovery();
rollResults = [{ discovery, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "discovery", value: discovery });
dispatch("roll");
}
function getIcon(t: string, c: string): string {
return "";
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Discovery</Button>
<Button color="primary" on:click={roll}>Roll Discovery</Button>
</span>
{#each rollResults as { discovery, timestamp }}
<DiscoveryCard {discovery} {timestamp} />
{/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
.btn {
text-align: center;
}
</style> </style>
+1 -3
View File
@@ -25,9 +25,7 @@
<main> <main>
<Card class="mb-3"> <Card class="mb-3">
<CardHeader> <CardHeader>
<CardTitle <CardTitle>{capitalize(dungeon.size.description)} {dungeon.function.description} built by {dungeon.builder.description}</CardTitle>
>{capitalize(dungeon.size.description)} {dungeon.function.description} built by (a/an) {dungeon.builder.description}</CardTitle
>
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<CardSubtitle> <CardSubtitle>
+3 -20
View File
@@ -1,37 +1,20 @@
<script lang="ts"> <script lang="ts">
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import DungeonCard from "./DungeonCard.svelte"; import { rollDungeon } from "../rollers/dungeons";
import { Dungeon, rollDungeon } from "../rollers/dungeons";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { dungeon: Dungeon; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let dungeon = rollDungeon(); let dungeon = rollDungeon();
rollResults = [{ dungeon, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "dungeon", value: dungeon });
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Dungeon</Button>
<Button color="primary" on:click={roll}>Roll Dungeon</Button>
</span>
{#each rollResults as { dungeon, timestamp }}
<DungeonCard {dungeon} {timestamp} />
{/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
.btn {
text-align: center;
}
</style> </style>
+3 -20
View File
@@ -1,37 +1,20 @@
<script lang="ts"> <script lang="ts">
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import FollowerCard from "./FollowerCard.svelte"; import { rollFollower } from "../rollers/followers";
import { rollFollower, Follower } from "../rollers/followers";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { follower: Follower; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let follower = rollFollower(); let follower = rollFollower();
rollResults = [{ follower, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "follower", value: follower });
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Follower</Button>
<Button color="primary" on:click={roll}>Roll Followers</Button>
</span>
{#each rollResults as { follower, timestamp }}
<FollowerCard {follower} {timestamp} />
{/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
.btn {
text-align: center;
}
</style> </style>
+31
View File
@@ -0,0 +1,31 @@
<script lang="ts">
import { capitalize } from "lodash";
import { Card, CardHeader, CardTitle, CardBody, CardText, CardFooter, Icon } from "sveltestrap";
import type { Kingdom, KingdomItem } from "../rollers/kingdoms";
export let item: KingdomItem;
export let timestamp: string;
let icon = "";
$: icon = String({ male: "person-fill", female: "person", steading: "house-door-fill", mount: "bicycle" }[item?.category] || "");
</script>
<main>
<Card class="mb-3">
<CardHeader>
<CardTitle>
{capitalize(item.category)} from {item.kingdom.description}
</CardTitle>
</CardHeader>
<CardBody>
<CardText>
<Icon name={icon} />
{item.description}
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
</main>
<style>
</style>
+15 -22
View File
@@ -1,47 +1,40 @@
<script lang="ts"> <script lang="ts">
import { capitalize } from "lodash"; import { capitalize } from "lodash";
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button, Icon } from "sveltestrap"; import { Button } from "sveltestrap";
import { kingdoms, rollCategory } from "../rollers/kingdoms"; import { KingdomItem, kingdoms, rollCategory } from "../rollers/kingdoms";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let rollResults: { value: string; icon: string; timestamp: string }[] = [];
let kingdom = "arpad"; let kingdom = "arpad";
let categories: string[]; let categories: string[];
function roll(category: string) { function roll(category: string) {
let value = rollCategory(kingdom, category); 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]; dispatch("roll", { type: "kingdom", value: new KingdomItem(kingdoms[kingdom], category, value) });
dispatch("roll");
} }
$: categories = kingdoms[kingdom].categories; $: categories = kingdoms[kingdom].categories;
</script> </script>
<main> <main>
<h2> <select bind:value={kingdom}>
<select bind:value={kingdom}> {#each Object.keys(kingdoms) as k}
{#each Object.keys(kingdoms) as k} <option value={k}>{kingdoms[k].description}</option>
<option value={k}>{kingdoms[k].description}</option> {/each}
{/each} </select>
</select>
</h2> <div>{kingdoms[kingdom].subtitle}</div>
<h3>{kingdoms[kingdom].subtitle}</h3>
{#each categories as category} {#each categories as category}
<span class="btn"> <Button color="primary" on:click={() => roll(category)}>Roll {capitalize(category)}</Button>
<Button color="primary" on:click={() => roll(category)}>Roll {capitalize(category)}</Button>
</span>
{/each}
{#each rollResults as { value, icon, timestamp }}
<h4>{timestamp}: <Icon name={icon} /> {value}</h4>
{/each} {/each}
</main> </main>
<style> <style>
select {
font-size: 0.8em;
}
</style> </style>
+55
View File
@@ -0,0 +1,55 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import CreatureCard from "./CreatureCard.svelte";
import DangerCard from "./DangerCard.svelte";
import DetailsCard from "./DetailsCard.svelte";
import DiscoveryCard from "./DiscoveryCard.svelte";
import DungeonCard from "./DungeonCard.svelte";
import FollowerCard from "./FollowerCard.svelte";
import KingdomCard from "./KingdomCard.svelte";
import NpcCard from "./NpcCard.svelte";
import PlaceCard from "./PlaceCard.svelte";
import RegionCard from "./RegionCard.svelte";
import SteadingCard from "./SteadingCard.svelte";
import type { RollCard } from "../types/RollCard";
const dispatch = createEventDispatcher();
export let card: RollCard;
function remove() {
dispatch("remove", card);
}
</script>
<main>
{#if card.type == "creature"}
<CreatureCard creature={card.value} timestamp={card.timestamp} on:remove={remove} />
{:else if card.type == "danger"}
<DangerCard danger={card.value} timestamp={card.timestamp} />
{:else if card.type == "detail"}
<DetailsCard detail={card.value} timestamp={card.timestamp} />
{:else if card.type == "discovery"}
<DiscoveryCard discovery={card.value} timestamp={card.timestamp} />
{:else if card.type == "dungeon"}
<DungeonCard dungeon={card.value} timestamp={card.timestamp} />
{:else if card.type == "follower"}
<FollowerCard follower={card.value} timestamp={card.timestamp} />
{:else if card.type == "kingdom"}
<KingdomCard item={card.value} timestamp={card.timestamp} />
{:else if card.type == "npc"}
<NpcCard npc={card.value} timestamp={card.timestamp} />
{:else if card.type == "place"}
<PlaceCard place={card.value} timestamp={card.timestamp} />
{:else if card.type == "region"}
<RegionCard region={card.value} timestamp={card.timestamp} />
{:else if card.type == "steading"}
<SteadingCard steading={card.value} timestamp={card.timestamp} />
{:else}
<h3>Card type not supported: {card.type}</h3>
{/if}
</main>
<style>
</style>
+3 -20
View File
@@ -1,37 +1,20 @@
<script lang="ts"> <script lang="ts">
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import NpcCard from "./NpcCard.svelte"; import { rollNpc } from "../rollers/npcs";
import { Npc, rollNpc } from "../rollers/npcs";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { npc: Npc; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let npc = rollNpc(); let npc = rollNpc();
rollResults = [{ npc, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "npc", value: npc });
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Npc</Button>
<Button color="primary" on:click={roll}>Roll Npc</Button>
</span>
{#each rollResults as { npc, timestamp }}
<NpcCard {npc} {timestamp} />
{/each}
</main> </main>
<style> <style>
main {
text-align: left;
}
.btn {
text-align: center;
}
</style> </style>
+24
View File
@@ -0,0 +1,24 @@
<script lang="ts">
import { Card, CardHeader, CardTitle, CardBody, CardText, CardFooter } from "sveltestrap";
import type { Place } from "../rollers/places";
export let place: Place;
export let timestamp: string;
</script>
<main>
<Card class="mb-3">
<CardHeader>
<CardTitle>Place</CardTitle>
</CardHeader>
<CardBody>
<CardText>
{place}
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
</main>
<style>
</style>
+2 -12
View File
@@ -1,28 +1,18 @@
<script lang="ts"> <script lang="ts">
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { rollPlace } from "../rollers/places"; import { rollPlace } from "../rollers/places";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { place: string; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let place = rollPlace(); let place = rollPlace();
rollResults = [{ place, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "place", value: place });
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Place</Button>
<Button color="primary" on:click={roll}>Roll Place</Button>
</span>
{#each rollResults as { place, timestamp }}
<h4>{timestamp}: {place}</h4>
{/each}
</main> </main>
<style> <style>
+24
View File
@@ -0,0 +1,24 @@
<script lang="ts">
import { Card, CardHeader, CardTitle, CardBody, CardText, CardFooter } from "sveltestrap";
import type { Region } from "../rollers/regions";
export let region: Region;
export let timestamp: string;
</script>
<main>
<Card class="mb-3">
<CardHeader>
<CardTitle>Region</CardTitle>
</CardHeader>
<CardBody>
<CardText>
{region}
</CardText>
</CardBody>
<CardFooter>{timestamp}</CardFooter>
</Card>
</main>
<style>
</style>
+2 -12
View File
@@ -1,28 +1,18 @@
<script lang="ts"> <script lang="ts">
import { format as formatDate } from "date-fns";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button } from "sveltestrap"; import { Button } from "sveltestrap";
import { rollRegion } from "../rollers/regions"; import { rollRegion } from "../rollers/regions";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let rollResults: { region: string; timestamp: string }[] = [];
function roll(event: Event) { function roll(event: Event) {
let region = rollRegion(); let region = rollRegion();
rollResults = [{ region, timestamp: formatDate(new Date(), "P kk:mm:ss") }, ...rollResults]; dispatch("roll", { type: "region", value: region });
dispatch("roll");
} }
</script> </script>
<main> <main>
<span class="btn"> <Button color="primary" on:click={roll}>Roll Region</Button>
<Button color="primary" on:click={roll}>Roll Region</Button>
</span>
{#each rollResults as { region, timestamp }}
<h4>{timestamp}: {region}</h4>
{/each}
</main> </main>
<style> <style>
+1 -1
View File
@@ -2,8 +2,8 @@
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
import { Button, Icon } from "sveltestrap"; import { Button, Icon } from "sveltestrap";
export let soundEnabled: boolean;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let soundEnabled = true;
function toggleSound() { function toggleSound() {
soundEnabled = !soundEnabled; soundEnabled = !soundEnabled;
+6
View File
@@ -1,5 +1,11 @@
import { random, replace, sample, sampleSize } from "lodash"; import { random, replace, sample, sampleSize } from "lodash";
// This is the general implemenetation of details.
// We are not doing strict class inheritance because that way leads to pain
export class Detail {
constructor(public type: string, public roll: number, public description: string) { }
}
export class Ability { export class Ability {
type: string = "ability"; type: string = "ability";
constructor(public roll: number = 0, public description = "") { }; constructor(public roll: number = 0, public description = "") { };
+6 -6
View File
@@ -102,21 +102,21 @@ function rollBuilder(roll: number = random(1, 12)): Builder {
if (roll <= 1) { if (roll <= 1) {
return new Builder(roll, sample(["aliens", "precursors"])); return new Builder(roll, sample(["aliens", "precursors"]));
} else if (roll <= 2) { } else if (roll <= 2) {
return new Builder(roll, sample(["demigod", "demon"])); return new Builder(roll, sample(["a demigod", "a demon"]));
} else if (roll <= 3) { } else if (roll <= 3) {
return new Builder(roll, "natural(caves, etc.)"); return new Builder(roll, "natural means (caves, etc.)");
} else if (roll <= 5) { } else if (roll <= 5) {
return new Builder(roll, sample(["religious order", "cult"])); return new Builder(roll, sample(["a religious order", "a cult"]));
} else if (roll <= 6) { } else if (roll <= 6) {
return new Builder(roll, rollHumanoid().description); return new Builder(roll, `a ${rollHumanoid().description}`);
} else if (roll <= 8) { } else if (roll <= 8) {
return new Builder(roll, sample(["dwarves", "gnomes"])); return new Builder(roll, sample(["dwarves", "gnomes"]));
} else if (roll <= 10) { } else if (roll <= 10) {
return new Builder(roll, "elves"); return new Builder(roll, "elves");
} else if (roll <= 11) { } else if (roll <= 11) {
return new Builder(roll, sample(["wizard", "madman"])); return new Builder(roll, sample(["a wizard", "a madman"]));
} else if (roll <= 12) { } else if (roll <= 12) {
return new Builder(roll, sample(["monarch", "warlord"])); return new Builder(roll, sample(["a monarch", "a warlord"]));
} }
return new Builder(roll); return new Builder(roll);
+4
View File
@@ -9,6 +9,10 @@ export class Kingdom {
mount: string[]; mount: string[];
} }
export class KingdomItem {
constructor(public kingdom: Kingdom, public category: string = "", public description: string = "") { };
}
export const kingdoms: { [kingdom: string]: Kingdom } = { export const kingdoms: { [kingdom: string]: Kingdom } = {
arpad: { arpad: {
description: 'The Kingdom of Arpad', description: 'The Kingdom of Arpad',
+3 -1
View File
@@ -1,6 +1,8 @@
import { sample } from "lodash"; import { sample } from "lodash";
import { bodgeString } from "./utils"; import { bodgeString } from "./utils";
export type Place = string;
export const places = { export const places = {
templates: [ templates: [
'The [PLACE]', 'The [PLACE]',
@@ -15,7 +17,7 @@ export const places = {
noun: ['[Name]', 'Arm', 'Ash', 'Blood', 'Child', 'Cinder', 'Corpse', 'Crystal', 'Dagger', 'Death', 'Demon', 'Devil', 'Doom', 'Eye', 'Fear', 'Finger', 'Fire', 'Foot', 'Ghost', 'Giant', 'Goblin', 'God', 'Gold', 'Hand', 'Head', 'Heart', 'Hero', 'Hope', 'King', 'Knave', 'Knight', 'Muck', 'Mud', 'Priest', 'Queen', 'Sailor', 'Silver', 'Skull', 'Smoke', 'Souls', 'Spear', 'Spirit', 'Stone', 'Sword', 'Thief', 'Troll', 'Warrior', 'Water', 'Witch', 'Wizard',], noun: ['[Name]', 'Arm', 'Ash', 'Blood', 'Child', 'Cinder', 'Corpse', 'Crystal', 'Dagger', 'Death', 'Demon', 'Devil', 'Doom', 'Eye', 'Fear', 'Finger', 'Fire', 'Foot', 'Ghost', 'Giant', 'Goblin', 'God', 'Gold', 'Hand', 'Head', 'Heart', 'Hero', 'Hope', 'King', 'Knave', 'Knight', 'Muck', 'Mud', 'Priest', 'Queen', 'Sailor', 'Silver', 'Skull', 'Smoke', 'Souls', 'Spear', 'Spirit', 'Stone', 'Sword', 'Thief', 'Troll', 'Warrior', 'Water', 'Witch', 'Wizard',],
}; };
export function rollPlace(): string { export function rollPlace(): Place {
let template = sample(places.templates); let template = sample(places.templates);
let place = bodgeString(template, places); let place = bodgeString(template, places);
+2
View File
@@ -1,6 +1,8 @@
import { sample } from "lodash"; import { sample } from "lodash";
import { bodgeString } from "./utils"; import { bodgeString } from "./utils";
export type Region = string;
export const regions = { export const regions = {
templates: [ templates: [
'[ADJECTIVE] [TERRAIN]', '[ADJECTIVE] [TERRAIN]',
+5
View File
@@ -0,0 +1,5 @@
// Generic type to hold data for multiple different card types
// Maybe down the road I'll just make the other types inherit this
export class RollCard {
constructor(public type: string, public value: any, public timestamp: string) { };
}