165 lines
5.9 KiB
TypeScript
165 lines
5.9 KiB
TypeScript
import React from 'react';
|
|
import { assertNever } from '../../utils';
|
|
import './Charsheet.css';
|
|
import { DriveGuage } from './DriveGuage/DriveGuage';
|
|
import { Charsheet, Nerve, Cunning, Intuition } from './types';
|
|
|
|
interface CharsheetProps {
|
|
sheet: Charsheet,
|
|
}
|
|
|
|
interface ActionElementProps {
|
|
name: string,
|
|
gilded: boolean,
|
|
value: number,
|
|
}
|
|
|
|
const ActionElement = ({ name, gilded, value }: ActionElementProps) => {
|
|
let dots = [];
|
|
for (let i = 0; i < value; i++) {
|
|
dots.push("\u25ef");
|
|
}
|
|
let diamond = gilded ? "\u25c6" : "\u25c7";
|
|
return (<div>
|
|
<h2 className="action-group__action"> {diamond} {name} </h2>
|
|
<div className="action-group__dots"> {dots} </div>
|
|
</div>);
|
|
}
|
|
|
|
interface ActionGroupElementProps {
|
|
group: Nerve | Cunning | Intuition;
|
|
}
|
|
|
|
const ActionGroupElement = ({ group }: ActionGroupElementProps) => {
|
|
var title;
|
|
var elements = [];
|
|
|
|
switch (group.type_) {
|
|
case "nerve": {
|
|
title = <div className="action-group__header"> Nerve <DriveGuage current={group.drives.current} max={group.drives.max} /> </div>
|
|
elements.push(<ActionElement name="Move" gilded={group.move.gilded} value={group.move.score} />);
|
|
elements.push(<ActionElement name="Strike" gilded={group.strike.gilded} value={group.strike.score} />);
|
|
elements.push(<ActionElement name="Control" gilded={group.control.gilded} value={group.control.score} />);
|
|
break
|
|
}
|
|
case "cunning": {
|
|
title = <div className="action-group__header"> Cunning <DriveGuage current={group.drives.current} max={group.drives.max} /> </div>
|
|
elements.push(<ActionElement name="Sway" gilded={group.sway.gilded} value={group.sway.score} />);
|
|
elements.push(<ActionElement name="Read" gilded={group.read.gilded} value={group.read.score} />);
|
|
elements.push(<ActionElement name="Hide" gilded={group.hide.gilded} value={group.hide.score} />);
|
|
break
|
|
}
|
|
case "intuition": {
|
|
title = <div className="action-group__header"> Intuition <DriveGuage current={group.drives.current} max={group.drives.max} /> </div>
|
|
elements.push(<ActionElement name="Survey" gilded={group.survey.gilded} value={group.survey.score} />);
|
|
elements.push(<ActionElement name="Focus" gilded={group.focus.gilded} value={group.focus.score} />);
|
|
elements.push(<ActionElement name="Sense" gilded={group.sense.gilded} value={group.sense.score} />);
|
|
break
|
|
}
|
|
default: {
|
|
assertNever(group);
|
|
}
|
|
}
|
|
|
|
return (<div className="action-group">
|
|
{title}
|
|
{elements}
|
|
</div>)
|
|
}
|
|
|
|
interface AbilitiesElementProps {
|
|
role: string
|
|
role_abilities: string[]
|
|
specialty: string
|
|
specialty_abilities: string[]
|
|
}
|
|
|
|
const AbilitiesElement = ({ role, role_abilities, specialty, specialty_abilities }: AbilitiesElementProps) => {
|
|
return (<div>
|
|
<h1> ROLE: {role} </h1>
|
|
<ul>
|
|
{role_abilities.map((ability) => <li>{ability}</li>)}
|
|
</ul>
|
|
<h1> SPECIALTY: {role} </h1>
|
|
<ul>
|
|
{specialty_abilities.map((ability) => <li>{ability}</li>)}
|
|
</ul>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export const CharsheetElement = ({ sheet }: CharsheetProps) => {
|
|
return (<div>
|
|
<div className="charsheet__header">
|
|
<div> Candela Obscura </div>
|
|
<div>
|
|
<p> {sheet.name} </p>
|
|
<p> {sheet.pronouns} </p>
|
|
<p> {sheet.circle} </p>
|
|
</div>
|
|
<div>
|
|
<p> {sheet.style} </p>
|
|
<p> {sheet.catalyst} </p>
|
|
<p> {sheet.question} </p>
|
|
</div>
|
|
</div >
|
|
<div className="charsheet__body">
|
|
<div>
|
|
<ActionGroupElement group={sheet.nerve} />
|
|
<ActionGroupElement group={sheet.cunning} />
|
|
<ActionGroupElement group={sheet.intuition} />
|
|
</div>
|
|
<div> <AbilitiesElement {...sheet} /> </div>
|
|
<div> Marks, Scars, Relationships </div>
|
|
</div>
|
|
</div>);
|
|
}
|
|
|
|
/*
|
|
export const CharsheetElement = () => {
|
|
const sheet = {
|
|
type_: 'Candela',
|
|
name: "Soren Jensen",
|
|
pronouns: 'he/him',
|
|
circle: 'Circle of the Bluest Sky',
|
|
style: 'dapper gentleman',
|
|
catalyst: 'a cursed book',
|
|
question: 'What were the contents of that book?',
|
|
nerve: {
|
|
type_: "nerve",
|
|
drives: { current: 1, max: 2 },
|
|
resistances: { current: 0, max: 3 },
|
|
move: { gilded: false, score: 2 },
|
|
strike: { gilded: false, score: 1 },
|
|
control: { gilded: true, score: 0 },
|
|
} as Nerve,
|
|
cunning: {
|
|
type_: "cunning",
|
|
drives: { current: 1, max: 1 },
|
|
resistances: { current: 0, max: 3 },
|
|
sway: { gilded: false, score: 0 },
|
|
read: { gilded: false, score: 0 },
|
|
hide: { gilded: false, score: 0 },
|
|
} as Cunning,
|
|
intuition: {
|
|
type_: "intuition",
|
|
drives: { current: 0, max: 0 },
|
|
resistances: { current: 0, max: 3 },
|
|
survey: { gilded: false, score: 0 },
|
|
focus: { gilded: false, score: 0 },
|
|
sense: { gilded: false, score: 0 },
|
|
} as Intuition,
|
|
role: 'Slink',
|
|
role_abilities: [
|
|
'Scout: If you have time to observe a location, you can spend 1 Intuition to ask a question: What do I notice here that others do not see? What in this place might be of use to us? What path should we follow?',
|
|
],
|
|
specialty: 'Detective',
|
|
specialty_abilities: [
|
|
"Mind Palace: When you want to figure out how two clues might relate or what path they should point you towards, burn 1 Intution resistance. The GM will give you the information you've deduced.",
|
|
],
|
|
};
|
|
|
|
return <CharsheetElement_ sheet={sheet} />
|
|
}
|
|
*/
|