Create a renderer for Candela Obscura character sheets #275
|
@ -0,0 +1,14 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
build:
|
||||
cmds:
|
||||
- cargo build
|
||||
|
||||
test:
|
||||
cmds:
|
||||
- cargo watch -x test
|
||||
|
||||
server:
|
||||
cmds:
|
||||
- cargo watch -x run
|
|
@ -0,0 +1,7 @@
|
|||
version: '3'
|
||||
|
||||
tasks:
|
||||
dev:
|
||||
cmds:
|
||||
- npm run start
|
||||
|
|
@ -16,4 +16,40 @@
|
|||
width: 33%;
|
||||
}
|
||||
|
||||
.action-group {
|
||||
position: relative;
|
||||
border: 2px solid black;
|
||||
border-radius: 4px;
|
||||
|
||||
padding-left: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.action-group:before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
right: 2px;
|
||||
bottom: 2px;
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.action-group > h1 {
|
||||
margin: 4px;
|
||||
margin-left: -4px;
|
||||
padding-left: 4px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.action-group__action {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.action-group__dots {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export type Guage = {
|
|||
}
|
||||
|
||||
export type Action = {
|
||||
guilded: boolean,
|
||||
gilded: boolean,
|
||||
score: number,
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ export type ActionGroup = {
|
|||
}
|
||||
|
||||
type Nerve = {
|
||||
type_: "nerve",
|
||||
drives: Guage,
|
||||
resistances: Guage,
|
||||
move: Action,
|
||||
|
@ -28,6 +29,7 @@ type Nerve = {
|
|||
}
|
||||
|
||||
type Cunning = {
|
||||
type_: "cunning",
|
||||
drives: Guage,
|
||||
resistances: Guage,
|
||||
sway: Action,
|
||||
|
@ -36,6 +38,7 @@ type Cunning = {
|
|||
}
|
||||
|
||||
type Intuition = {
|
||||
type_: "intuition",
|
||||
drives: Guage,
|
||||
resistances: Guage,
|
||||
survey: Action,
|
||||
|
@ -62,11 +65,6 @@ interface CharsheetProps {
|
|||
sheet: Charsheet,
|
||||
}
|
||||
|
||||
interface ActionDriveProps {
|
||||
groupName: string,
|
||||
group: Nerve | Cunning | Intuition,
|
||||
}
|
||||
|
||||
interface GuageProps {
|
||||
current: number,
|
||||
max: number,
|
||||
|
@ -76,15 +74,67 @@ const GuageElement = ({ current, max }: GuageProps) => {
|
|||
|
||||
}
|
||||
|
||||
const ActionDriveElement = ({ groupName, group }: ActionDriveProps) => {
|
||||
|
||||
if ("move" in group) {
|
||||
return <div> -- Nerve -- </div>;
|
||||
} else if ("sway" in group) {
|
||||
return <div> -- Cunning -- </div>;
|
||||
} else {
|
||||
return <div> -- Intuition -- </div>;
|
||||
function assertNever(value: never) {
|
||||
throw new Error("Unexpected value: " + value);
|
||||
}
|
||||
|
||||
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> Nerve </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> Cunning </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> Intuition </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">
|
||||
<h1> {title} </h1>
|
||||
{elements}
|
||||
</div>)
|
||||
}
|
||||
|
||||
const CharsheetElement_ = ({ sheet }: CharsheetProps) => {
|
||||
|
@ -104,9 +154,9 @@ const CharsheetElement_ = ({ sheet }: CharsheetProps) => {
|
|||
</div >
|
||||
<div className="charsheet__body">
|
||||
<div>
|
||||
<ActionDriveElement groupName="Nerve" group={sheet.nerve} />
|
||||
<ActionDriveElement groupName="Cunning" group={sheet.cunning} />
|
||||
<ActionDriveElement groupName="Intuition" group={sheet.intuition} />
|
||||
<ActionGroupElement group={sheet.nerve} />
|
||||
<ActionGroupElement group={sheet.cunning} />
|
||||
<ActionGroupElement group={sheet.intuition} />
|
||||
</div>
|
||||
<div> Role and Specialty </div>
|
||||
<div> Marks, Scars, Relationships </div>
|
||||
|
@ -125,26 +175,29 @@ export const CharsheetElement = () => {
|
|||
question: 'What were the contents of that book?',
|
||||
role: 'Slink',
|
||||
nerve: {
|
||||
type_: "nerve",
|
||||
drives: { current: 2, max: 2 },
|
||||
resistances: { current: 0, max: 3 },
|
||||
move: { guilded: false, score: 0 },
|
||||
strike: { guilded: false, score: 0 },
|
||||
control: { guilded: true, score: 0 },
|
||||
},
|
||||
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: { guilded: false, score: 0 },
|
||||
read: { guilded: false, score: 0 },
|
||||
hide: { guilded: false, score: 0 },
|
||||
},
|
||||
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: { guilded: false, score: 0 },
|
||||
focus: { guilded: false, score: 0 },
|
||||
sense: { guilded: false, score: 0 },
|
||||
}
|
||||
survey: { gilded: false, score: 0 },
|
||||
focus: { gilded: false, score: 0 },
|
||||
sense: { gilded: false, score: 0 },
|
||||
} as Intuition
|
||||
};
|
||||
|
||||
return <CharsheetElement_ sheet={sheet} />
|
||||
|
|
Loading…
Reference in New Issue