Add rest dice tracking for the Sync actors

This commit is contained in:
Oliver-Akins 2024-02-08 23:25:55 -07:00
parent 4544516c5c
commit 1002b1387c
8 changed files with 186 additions and 24 deletions

View file

@ -1,37 +1,47 @@
const statDice = [ `d4`, `d6`, `d8`, `d10`, `d12`, `d20` ]; export const statDice = [ `d4`, `d6`, `d8`, `d10`, `d12`, `d20` ];
const trainingLevels = [``, `locked`, `+2`, `+4`]; export const trainingLevels = [``, `locked`, `+2`, `+4`];
const damageTypes = [ `slashing`, `piercing`, `smashing`, `gun`, `neon`, `shadow`, `solar` ]; export const damageTypes = [ `slashing`, `piercing`, `smashing`, `gun`, `neon`, `shadow`, `solar` ];
const ammoTypes = [`quivers`, `mags`, `cells`]; export const ammoTypes = [`quivers`, `mags`, `cells`];
const stats = [ `build`, `meta`, `presence`, `hands`, `tilt`, `rng` ]; export const stats = [ `build`, `meta`, `presence`, `hands`, `tilt`, `rng` ];
const buildSkills = [ `defense`, `magic`, `melee`, `platforming`, `strength`, ]; export const buildSkills = [ `defense`, `magic`, `melee`, `platforming`, `strength`, ];
const metaSkills = [ `alchemy`, `arcanum`, `dreams`, `lore`, `navigation`, ]; export const metaSkills = [ `alchemy`, `arcanum`, `dreams`, `lore`, `navigation`, ];
const presenceSkills = [ `animal_handling`, `perception`, `sneak`, `speech`, `vibes`, ]; export const presenceSkills = [ `animal_handling`, `perception`, `sneak`, `speech`, `vibes`, ];
const handsSkills = [ `accuracy`, `crafting`, `engineering`, `explosives`, `piloting`, ]; export const handsSkills = [ `accuracy`, `crafting`, `engineering`, `explosives`, `piloting`, ];
const allSkills = [ export const allSkills = [
...buildSkills, ...buildSkills,
...metaSkills, ...metaSkills,
...presenceSkills, ...presenceSkills,
...handsSkills, ...handsSkills,
]; ];
const skills = { export const skills = {
build: buildSkills, build: buildSkills,
meta: metaSkills, meta: metaSkills,
presence: presenceSkills, presence: presenceSkills,
hands: handsSkills, hands: handsSkills,
}; };
const itemTiers = [ export const itemTiers = [
`simple`, `greater`, `simple`, `greater`,
`rare`, `legendary` `rare`, `legendary`
]; ];
export const syncMilestones = [
{ value: 20, andReturn: true },
{ value: 40, andReturn: false },
{ value: 60, andReturn: true },
{ value: 80, andReturn: false },
{ value: 100, andReturn: true },
];
export const syncDice = "1d20";
export default { export default {
stats, stats,
statDice, statDice,
@ -45,4 +55,6 @@ export default {
allSkills, allSkills,
skills, skills,
itemTiers, itemTiers,
syncMilestones,
syncDice,
}; };

View file

@ -1,11 +1,13 @@
import PlayerActor from "./Player.mjs"; import PlayerActor from "./Player.mjs";
import MobActor from "./Mob.mjs"; import MobActor from "./Mob.mjs";
import SyncActor from "./Sync.mjs";
/** @extends {Actor} */ /** @extends {Actor} */
export class ActorHandler extends Actor { export class ActorHandler extends Actor {
proxyTargets = { proxyTargets = {
player: PlayerActor, player: PlayerActor,
mob: MobActor, mob: MobActor,
sync: SyncActor,
}; };
constructor(data, ctx) { constructor(data, ctx) {
@ -89,4 +91,10 @@ export class ActorHandler extends Actor {
}; };
return true; return true;
}; };
_preUpdate(...args) {
return this.proxyFunction("_preUpdate", ...args);
};
useRestDie() { return this.proxyFunction("useRestDie"); };
}; };

View file

@ -0,0 +1,60 @@
import { syncMilestones, syncDice } from "../../config.mjs";
/** @this {Actor} */
async function useRestDie() {
let addToSync = await (new Roll(syncDice)).evaluate();
await addToSync.toMessage({
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
flavor: `Sync Restoration`,
});
this.update({
"system.rest_dice": this.system.rest_dice - 1,
"system.value": this.system.value + addToSync.total,
});
};
/** @this {Actor} */
async function _preUpdate(data, options) {
if (options.diff) {
if (data.system?.value != null) {
let currentSync = this.system.value;
let newSync = data.system.value;
let minSync = Math.min(currentSync, newSync);
let maxSync = Math.max(currentSync, newSync);
let milestones = syncMilestones.filter(
m => minSync < m.value && m.value <= maxSync
);
if (milestones.length > 0) data.system.rest_dice ??= this.system.rest_dice;
for (const milestone of milestones) {
// Damage
if (newSync < currentSync) {
if (!this.system.milestones_hit.has(milestone.value)) {
data.system.rest_dice += 1;
this.system.milestones_hit.add(milestone.value);
};
}
// Healing
else if (newSync > currentSync) {
if (
this.system.milestones_hit.has(milestone.value)
&& milestone.andReturn
&& milestone.value <= newSync
) {
this.system.milestones_hit.delete(milestone.value);
};
};
};
data.system.milestones_hit = [ ...this.system.milestones_hit ];
};
};
};
export default {
_preUpdate,
useRestDie,
};

View file

@ -3,10 +3,18 @@ export class SyncData extends foundry.abstract.TypeDataModel {
const fields = foundry.data.fields; const fields = foundry.data.fields;
return { return {
value: new fields.NumberField({ value: new fields.NumberField({
required: true,
integer: true, integer: true,
initial: 100, initial: 100,
}), }),
rest_dice: new fields.NumberField({
integer: true,
initial: 0,
min: 0,
}),
milestones_hit: new fields.SetField(
new fields.NumberField({ integer: true, }),
{ initial: [] },
),
}; };
}; };
}; };

View file

@ -6,7 +6,7 @@ export class AbstractSyncSheet extends GenericActorSheet {
super.defaultOptions, super.defaultOptions,
{ {
width: 200, width: 200,
height: 200, height: 275,
} }
); );
opts.classes.push( opts.classes.push(
@ -22,11 +22,12 @@ export class AbstractSyncSheet extends GenericActorSheet {
ctx.system = actor.system; ctx.system = actor.system;
ctx.flags = actor.flags; ctx.flags = actor.flags;
console.groupCollapsed(`SyncSheet.getData`);
console.log(`ctx`, ctx);
console.log(`actor`, actor);
console.groupEnd();
return ctx; return ctx;
}; };
activateListeners(html) {
super.activateListeners(html);
html.find(`.use-rest-die`)
.on(`click`, this.actor.useRestDie.bind(this.actor));
};
}; };

View file

@ -1,5 +1,7 @@
@use "../vars.scss" as *; @use "../vars.scss" as *;
@use "sass:color" as color;
.dotdungeon.dotdungeon.dotdungeon.dotdungeon > .window-content { .dotdungeon.dotdungeon.dotdungeon.dotdungeon > .window-content {
button { button {
border-radius: 4px; border-radius: 4px;
@ -21,31 +23,52 @@
&.confirm { &.confirm {
background: $colour-confirm; background: $colour-confirm;
color: $text-on-confirm; color: $text-on-confirm;
&:hover, &:focus-visible {
&:hover:not(:disabled),
&:focus-visible {
background: transparent; background: transparent;
color: $colour-confirm; color: $colour-confirm;
border-color: $colour-confirm; border-color: $colour-confirm;
} }
&:disabled {
background: color.adjust($colour-confirm, $lightness: -10%);
color: color.adjust($text-on-confirm, $lightness: -15%);
}
} }
&.neutral { &.neutral {
background: $colour-neutral; background: $colour-neutral;
color: $text-on-neutral; color: $text-on-neutral;
&:hover, &:focus-visible {
&:hover:not(:disabled),
&:focus-visible {
background: transparent; background: transparent;
color: $colour-neutral; color: $colour-neutral;
border-color: $colour-neutral; border-color: $colour-neutral;
} }
&:disabled {
background: color.adjust($colour-neutral, $lightness: -10%);
color: color.adjust($text-on-neutral, $lightness: -15%);
}
} }
&.danger { &.danger {
background: $colour-danger; background: $colour-danger;
color: $text-on-danger; color: $text-on-danger;
&:hover, &:focus-visible {
&:hover:not(:disabled),
&:focus-visible {
background: transparent; background: transparent;
color: $colour-danger; color: $colour-danger;
border-color: $colour-danger; border-color: $colour-danger;
} }
&:disabled {
background: color.adjust($colour-danger, $lightness: -10%);
color: color.adjust($text-on-danger, $lightness: -15%);
}
} }
&.reduced-padding { &.reduced-padding {

View file

@ -23,6 +23,22 @@
width: 60%; width: 60%;
text-align: center; text-align: center;
} }
.rest-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4px;
.button-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
align-items: center;
text-align: center;
}
}
} }
&--sync-sheet { &--sync-sheet {

View file

@ -17,4 +17,38 @@
value="{{system.value}}" value="{{system.value}}"
> >
</label> </label>
<div class="rest-container">
Rest Dice:
<div class="button-row">
<button
type="button"
class="neutral equal-padding"
data-decrement="system.rest_dice"
{{disabled (eq system.rest_dice 0)}}
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.minus }}}
</div>
</button>
<span class="value">
{{system.rest_dice}}
</span>
<button
type="button"
class="neutral equal-padding"
data-increment="system.rest_dice"
>
<div aria-hidden="true" class="icon icon--14">
{{{ icons.create }}}
</div>
</button>
</div>
<button
type="button"
class="confirm use-rest-die"
{{disabled (eq system.rest_dice 0)}}
>
Use a Rest Dice
</button>
</div>
</form> </form>