Initial block-out: Hench data model + playbooks
This commit is contained in:
parent
753052aac3
commit
ac59cc57df
12
README.md
12
README.md
@ -1 +1,11 @@
|
||||
# hench
|
||||
# HENCH
|
||||
|
||||
An implementation of *HENCH (2025)* by Chloe Herd (myself) and Cassandra Grove.
|
||||
|
||||
## Current Release Version:
|
||||
N/A (still in development).
|
||||
|
||||
## Next Target Release Version:
|
||||
Draft 0
|
||||
|
||||
Discord Link: N/A
|
15
hench.mjs
Normal file
15
hench.mjs
Normal file
@ -0,0 +1,15 @@
|
||||
import { HenchDataModel } from "./module/data-models.mjs";
|
||||
|
||||
import { HenchDebugSheet } from "./module/sheets/hench-debug.mjs";
|
||||
|
||||
Hooks.once("init", () => {
|
||||
CONFIG.Actor.dataModels = {
|
||||
hench: HenchDataModel,
|
||||
};
|
||||
|
||||
Actors.unregisterSheet('core', ActorSheet);
|
||||
Actors.registerSheet('henchDebug', HenchDebugSheet, {
|
||||
makeDefault: true,
|
||||
label: 'Hench Debug Sheet',
|
||||
});
|
||||
});
|
105
module/data-models.mjs
Normal file
105
module/data-models.mjs
Normal file
@ -0,0 +1,105 @@
|
||||
const { HTMLField, SchemaField, NumberField, StringField, BooleanField, FilePathField, ArrayField } = foundry.data.fields;
|
||||
|
||||
import { nullPlaybookKey, playbookKeys, lookupPlaybook } from './playbooks.mjs';
|
||||
|
||||
const textField = () => new StringField({ required: true, blank: true });
|
||||
|
||||
const promptField = () => new SchemaField({
|
||||
question: textField(),
|
||||
answer: textField()
|
||||
});
|
||||
|
||||
const harmField = () => new SchemaField({
|
||||
marked: new BooleanField({ required: true }),
|
||||
description: textField(),
|
||||
});
|
||||
|
||||
export class HenchDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
return {
|
||||
name: textField(),
|
||||
look: textField(),
|
||||
detailAnswers: new SchemaField({
|
||||
one: textField(),
|
||||
two: textField(),
|
||||
}),
|
||||
customInclination: textField(),
|
||||
harm: new SchemaField({
|
||||
levelOne: new SchemaField({
|
||||
one: harmField(),
|
||||
two: harmField(),
|
||||
}),
|
||||
levelTwo: new SchemaField({
|
||||
one: harmField(),
|
||||
two: harmField(),
|
||||
}),
|
||||
levelThree: new SchemaField({
|
||||
one: harmField(),
|
||||
}),
|
||||
levelFour: new SchemaField({
|
||||
one: harmField(),
|
||||
}),
|
||||
}),
|
||||
stress: new NumberField({ required: true, integer: true, min: 0, initial: 0, max: 12 }),
|
||||
experience: new NumberField({ required: true, integer: true, min: 0, initial: 0, max: 5 }),
|
||||
|
||||
playbook: new StringField({ required: true, blank: false, initial: nullPlaybookKey, options: playbookKeys }),
|
||||
};
|
||||
}
|
||||
|
||||
static migrateData(source) {
|
||||
// No migrations yet - base case.
|
||||
|
||||
return super.migrateData(source);
|
||||
}
|
||||
|
||||
get dead() {
|
||||
return !!this.harm.levelFour.marked;
|
||||
}
|
||||
|
||||
get playbookDetails() {
|
||||
return lookupPlaybook(this.playbook);
|
||||
}
|
||||
|
||||
// TODO IMPLEMENT advancements
|
||||
get gearLimit() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
get hasPlaybookSelected() {
|
||||
return this.playbook !== nullPlaybookKey;
|
||||
}
|
||||
|
||||
get detailQuestions() {
|
||||
return this.playbookDetails?.detailQuestions;
|
||||
}
|
||||
|
||||
get inclinations() {
|
||||
const base = this.playbookDetails?.inclinations ?? {};
|
||||
|
||||
return {
|
||||
...base,
|
||||
custom: this.customInclination
|
||||
};
|
||||
}
|
||||
|
||||
get missionPlanningQuestions() {
|
||||
return this.playbookDetails?.missionPlanningQuestions;
|
||||
}
|
||||
|
||||
get expTriggers() {
|
||||
const fromPlaybook = this.playbookDetails?.expTrigger;
|
||||
|
||||
let triggers = {
|
||||
one: "You acted on your inclinations.",
|
||||
two: "You made the boss proud.",
|
||||
three: "Your home life interfered with the mission."
|
||||
};
|
||||
|
||||
if(fromPlaybook) {
|
||||
triggers.four = fromPlaybook;
|
||||
}
|
||||
|
||||
return triggers;
|
||||
}
|
||||
}
|
132
module/playbooks.mjs
Normal file
132
module/playbooks.mjs
Normal file
@ -0,0 +1,132 @@
|
||||
export const nullPlaybookKey = "NONE";
|
||||
|
||||
export const playbookKeys = [
|
||||
nullPlaybookKey,
|
||||
"SUPERFAN",
|
||||
"BADASS",
|
||||
"LABMAN",
|
||||
"DEMOTED",
|
||||
"OUTCAST",
|
||||
"USURPER",
|
||||
"TIMECARD",
|
||||
];
|
||||
|
||||
const playbooks = {
|
||||
NONE: null,
|
||||
SUPERFAN: {
|
||||
detailQuestions: {
|
||||
one: "What's the coolest thing you've ever done?",
|
||||
two: "What's your favorite story about the boss? ",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Drawing on your knowledge of comic lore",
|
||||
two: "Acting with naive optimism",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "You've read an issue about the target. Choose a power or a weakness of the target, and explain it.",
|
||||
two: "Confidently state a poorly thought out plan to achieve the goal.",
|
||||
three: "Ask the boss: is the target really as cool as it's made out to be?",
|
||||
},
|
||||
expTrigger: "You faced the grim realities of the job.",
|
||||
},
|
||||
BADASS: {
|
||||
detailQuestions: {
|
||||
one: "Have you killed on the job? If so, what was your first? ",
|
||||
two: "How did the boss earn your respect?",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Applying brute force",
|
||||
two: "Making a threat",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "You've fought the target before. State where they left a scar, and how they did it.",
|
||||
two: "The target is an old friend. State how you met, and how it ended.",
|
||||
three: "Ask the boss: can we kill the target?",
|
||||
},
|
||||
expTrigger: "Your strength couldn't solve the problem at hand.",
|
||||
},
|
||||
LABMAM: {
|
||||
detailQuestions: {
|
||||
one: "What was your first invention? ",
|
||||
two: "What secret project does the boss fund? Why is it doomed? ",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Using your intellect",
|
||||
two: "Doing something unexpected",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "Present your new prototype weapon, which the target is probably weak to.",
|
||||
two: "State a fact about the target's defense systems.",
|
||||
three: "Ask the boss: what secret research is the target hiding?",
|
||||
},
|
||||
expTrigger: "Your invention failed fantastically.",
|
||||
},
|
||||
DEMOTED: {
|
||||
detailQuestions: {
|
||||
one: "What was your old villain name? Why are you just a hench, now?",
|
||||
two: "What leverage does the boss have on you?",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Acting with excessive flair",
|
||||
two: "Attempting to reclaim your status",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "The target's clearly a rookie. State an obvious flaw with their approach or gimmick.",
|
||||
two: "You've bested the target before. State how, and why you can't just do that again.",
|
||||
three: "Ask the boss: why hasn't the Guild taken out the target?",
|
||||
},
|
||||
expTrigger: "Your old tricks weren't cut out for the job.",
|
||||
},
|
||||
OUTCAST: {
|
||||
detailQuestions: {
|
||||
one: "Why has society rejected you? ",
|
||||
two: "Why has the boss taken you in? ",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Attempting to impress someone",
|
||||
two: "Acting against all social norms",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "The target has treated you cruelly. State when, and how.",
|
||||
two: "You and the target have something in common. State what, and how that makes you feel.",
|
||||
three: "Ask the boss: Why do you hate the target?",
|
||||
},
|
||||
expTrigger: "An attempt at connection was rejected.",
|
||||
},
|
||||
USURPER: {
|
||||
detailQuestions: {
|
||||
one: "What is your ultimate ambition? ",
|
||||
two: "What habit of the boss infuriates you the most? ",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Acting on hidden agendas.",
|
||||
two: "Putting yourself before anyone else.",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "Describe how the target is uniquely equipped to defeat the boss.",
|
||||
two: "Describe how you are uniquely equipped to defeat the target.",
|
||||
three: "Ask the boss: are you really prepared for this mission?",
|
||||
},
|
||||
expTrigger: "You had to act selflessly.",
|
||||
},
|
||||
TIMECARD: {
|
||||
detailQuestions: {
|
||||
one: "Who relies on you? ",
|
||||
two: "How did the boss convince you to take the job?",
|
||||
},
|
||||
inclinations: {
|
||||
one: "Invoking rules or regulations.",
|
||||
two: "Taking the laziest approach.",
|
||||
},
|
||||
missionPlanningQuestions: {
|
||||
one: "State something that, by Guild rule, the target cannot do to you this mission.",
|
||||
two: "State something you refuse to do this mission.",
|
||||
three: "Ask the boss: How can we get a bonus on this job?",
|
||||
},
|
||||
expTrigger: "You had to act above and beyond your usual duties.",
|
||||
},
|
||||
};
|
||||
|
||||
export function lookupPlaybook(key) {
|
||||
return playbooks[key];
|
||||
}
|
11
module/sheets/hench-debug.mjs
Normal file
11
module/sheets/hench-debug.mjs
Normal file
@ -0,0 +1,11 @@
|
||||
export class HenchDebugSheet extends ActorSheet {
|
||||
/** @override */
|
||||
get template() {
|
||||
return `systems/hench/templates/hench-debug.hbs`;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
getData() {
|
||||
return super.getData();
|
||||
}
|
||||
}
|
33
system.json
Normal file
33
system.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"id": "hench",
|
||||
"title": "HENCH",
|
||||
"description": "HENCH (2025)",
|
||||
"version": "0.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "11",
|
||||
"verified": "11"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"id": "walcutt",
|
||||
"name": "walcutt",
|
||||
"discord": "walcutt"
|
||||
}
|
||||
],
|
||||
"esmodules": [
|
||||
"hench.mjs"
|
||||
],
|
||||
"styles": [],
|
||||
"packs": [],
|
||||
"languages": [],
|
||||
"documentTypes": {
|
||||
"Actor": {
|
||||
"hench": {},
|
||||
"boss": {}
|
||||
},
|
||||
"Item": {
|
||||
"move": {}
|
||||
}
|
||||
},
|
||||
"url": "https://github.com/walcutt/hench"
|
||||
}
|
71
templates/hench-debug.hbs
Normal file
71
templates/hench-debug.hbs
Normal file
@ -0,0 +1,71 @@
|
||||
<form>
|
||||
<h1> {{ actor.name }} </h1>
|
||||
|
||||
<h2> Explicit Details: </h2>
|
||||
|
||||
<div id="hench-explicit-details">
|
||||
<p>Name: {{ actor.system.name }}</p>
|
||||
<p>Look: {{ actor.system.look }}</p>
|
||||
<h3> Detail Answers: </h3>
|
||||
<div>
|
||||
<p>Answer 1: {{ actor.system.detailAnswers.one }}</p>
|
||||
<p>Answer 2: {{ actor.system.detailAnswers.two }}</p>
|
||||
</div>
|
||||
<p>Custom Inclination: {{ actor.system.customInclination }}</p>
|
||||
<h3> Harm: </h3>
|
||||
<div>
|
||||
<h4>Level 1:</h4>
|
||||
<div>
|
||||
<p>1 {{#if actor.system.harm.levelOne.one.marked }} X {{ else }} O {{/if}}: {{actor.system.harm.levelOne.one.description }}</p>
|
||||
<p>1 {{#if actor.system.harm.levelOne.two.marked }} X {{ else }} O {{/if}}: {{actor.system.harm.levelOne.two.description }}</p>
|
||||
</div>
|
||||
<h4>Level 2:</h4>
|
||||
<div>
|
||||
<p>1 {{#if actor.system.harm.levelTwo.one.marked }} X {{ else }} O {{/if}}: {{ actor.system.harm.levelTwo.one.description }}</p>
|
||||
<p>1 {{#if actor.system.harm.levelTwo.two.marked }} X {{ else }} O {{/if}}: {{ actor.system.harm.levelTwo.two.description }}</p>
|
||||
</div>
|
||||
<h4>Level 3:</h4>
|
||||
<div>
|
||||
<p>1 {{#if actor.system.harm.levelThree.one.marked }} X {{ else }} O {{/if}}: {{actor.system.harm.levelThree.one.description }}</p>
|
||||
</div>
|
||||
<h4>Level 3:</h4>
|
||||
<div>
|
||||
<p>1 {{#if actor.system.harm.levelFour.one.marked }} X {{ else }} O {{/if}}: {{actor.system.harm.levelFour.one.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>Stress: {{ actor.system.stress }}</p>
|
||||
<p>Experience: {{ actor.system.experience }}</p>
|
||||
<p>Playbook: {{ actor.system.playbook }}</p>
|
||||
</div>
|
||||
|
||||
<h2>Implicit Details:</h2>
|
||||
<div>
|
||||
<p>Is Dead: {{ actor.system.dead }}</p>
|
||||
<p>Gear Limit: {{ actor.system.gearLimit }}</p>
|
||||
<p>Has playbook selected: {{ actor.system.hasPlaybookSelected }}</p>
|
||||
<h3> Detail Questions: </h3>
|
||||
<div>
|
||||
<p>Question 1: {{ actor.system.detailQuestions.one }}</p>
|
||||
<p>Question 2: {{ actor.system.detailQuestions.two }}</p>
|
||||
</div>
|
||||
<h3> Inclinations: </h3>
|
||||
<div>
|
||||
<p>Inclination 1: {{ actor.system.inclinations.one }}</p>
|
||||
<p>Inclination 2: {{ actor.system.inclinations.two }}</p>
|
||||
<p>Inclination 3: {{ actor.system.inclinations.custom }}</p>
|
||||
</div>
|
||||
<h3>Mission Planning</h3>
|
||||
<div>
|
||||
<p>Question 1: {{ actor.system.missionPlanningQuestions.one }}</p>
|
||||
<p>Question 2: {{ actor.system.missionPlanningQuestions.two }}</p>
|
||||
<p>Question 3: {{ actor.system.missionPlanningQuestions.three }}</p>
|
||||
</div>
|
||||
<h3>Experience Triggers:</h3>
|
||||
<div>
|
||||
<p>Trigger 1: {{ actor.system.expTriggers.one }}</p>
|
||||
<p>Trigger 2: {{ actor.system.expTriggers.two }}</p>
|
||||
<p>Trigger 3: {{ actor.system.expTriggers.three }}</p>
|
||||
<p>Trigger 4: {{ actor.system.expTriggers.four }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
10
todo.md
Normal file
10
todo.md
Normal file
@ -0,0 +1,10 @@
|
||||
- [] Define Move Model
|
||||
- [] Define Hench Model
|
||||
- [] Define Boss Model
|
||||
- [x] Define Prompt Model (DEFUNCT)
|
||||
- [] Define Storyline Model
|
||||
- [] ? Define Table Model
|
||||
- [] Design Hench sheet
|
||||
- [] Design Boss sheet
|
||||
- [] Implement Hench sheet
|
||||
- [] Implement Boss sheet
|
Loading…
x
Reference in New Issue
Block a user