Add the Aspect sheet and update some translation keys for the actor sheet

This commit is contained in:
Oliver-Akins 2023-12-15 23:55:47 -07:00
parent c0d677cd77
commit 763a0982d5
22 changed files with 1277 additions and 84 deletions

View file

@ -1,15 +1,48 @@
@import url("https://fonts.googleapis.com/css2?family=Pixelify+Sans&display=swap");
.dotdungeon > .window-content ::-webkit-scrollbar {
width: 10px;
}
.dotdungeon > .window-content ::-webkit-scrollbar-thumb {
border-radius: 5px;
}
.dotdungeon > .window-content h2, .dotdungeon > .window-content h3, .dotdungeon > .window-content h4, .dotdungeon > .window-content h5, .dotdungeon > .window-content h6 {
all: initial;
display: block;
box-sizing: border-box;
display: block;
font-family: "Pixelify Sans", sans-serif;
margin: 0;
}
.dotdungeon > .window-content label {
display: block;
}
.dotdungeon > .window-content button, .dotdungeon > .window-content button:hover {
all: initial;
display: block;
box-sizing: border-box;
font-family: inherit;
cursor: pointer;
}
.dotdungeon > .window-content input[type=text],
.dotdungeon > .window-content input[type=number],
.dotdungeon > .window-content textarea {
all: initial;
display: block;
box-sizing: border-box;
padding: 5px 7px;
border-width: 2px;
border-radius: 4px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.4);
background-color: rgba(0, 0, 0, 0.1);
}
.dotdungeon > .window-content input[type=text]:focus, .dotdungeon > .window-content input[type=text]:active,
.dotdungeon > .window-content input[type=number]:focus,
.dotdungeon > .window-content input[type=number]:active,
.dotdungeon > .window-content textarea:focus,
.dotdungeon > .window-content textarea:active {
border-color: rgb(0, 0, 0);
}
.dotdungeon > .window-content select, .dotdungeon > .window-content select:hover {
cursor: pointer;
}
@ -158,5 +191,19 @@
visibility: hidden;
}
}
.dotdungeon .item--aspect {
padding: 4px;
}
.dotdungeon .item--aspect input[type=text] {
font-family: sans-serif;
font-size: 1.5em;
height: 1.5em;
width: 100%;
}
.dotdungeon .item--aspect textarea {
font-family: sans-serif;
width: 100%;
resize: vertical;
}
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../styles/root.scss%22,%22../styles/mixins/_foundry.scss%22,%22../styles/vars.scss%22,%22../styles/sheets/partials/stat.scss%22,%22../styles/sheets/partials/skill.scss%22,%22../styles/sheets/actor/mvp.scss%22,%22../styles/mixins/_breakpoints.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAGQ;AAIP;ECNA;EDQC;EACA,aEVW;EFWX;;AAGD;ECbA;EDeC;EACA;;AAGD;EACC;;;AAKF;EACC;;AAEA;EACC;EACA,YE9BW;;;ACDb;EACC;EACA;EACA;;ACHD;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;;;ACdF;EACC;EACA,qBACC;EASD;EACA;EACA;EACA;;AAGC;EACC;;AAED;EACC;;AACA;EACC;EACA;EACA;EACA;EACA;;AAGF;EACC;;AAEA;EACC;EACA;EACA;;AAGF;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAKH;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA,aH5FS;EG6FT;;AAGD;EAEC,QADO;EAEP,OAFO;EAGP;;;ACnGH;ED4GC;IACC;IACA;IACA,qBACC;;EAiBF;IACC;;EAGC;IACC;;;AChIJ;EDyIC;IACC;IACA;IACA,qBACC;;EAaF;IACC;;EAGC;IACC;IACA%22,%22file%22:%22root.css%22%7D */
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../styles/root.scss%22,%22../styles/mixins/_foundry.scss%22,%22../styles/_vars.scss%22,%22../styles/mixins/_partials.scss%22,%22../styles/sheets/partials/stat.scss%22,%22../styles/sheets/partials/skill.scss%22,%22../styles/sheets/actor/mvp.scss%22,%22../styles/mixins/_breakpoints.scss%22,%22../styles/sheets/items/aspect.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAIQ;AAKP;EACC;;AAED;EACC;;AAGD;ECfA;EACA;EACA;EDeC;EACA,aEnBW;EFoBX;;AAGD;EACC;;AAGD;EC1BA;EACA;EACA;ED0BC;EACA;;AAGD;AAAA;AAAA;EChCA;EACA;EACA;EDkCC;EGpCD;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAEC;;AHgCD;EACC;;;AAKF;EACC;;AAEA;EACC;EACA,YElDW;;;AEFb;EACC;EACA;EACA;;ACHD;EACC;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;;;ACdF;EACC;EACA,qBACC;EASD;EACA;EACA;EACA;;AAGC;EACC;;AAED;EACC;;AACA;EACC;EACA;EACA;EACA;EACA;;AAGF;EACC;;AAEA;EACC;EACA;EACA;;AAGF;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAKH;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA,aJ5FS;EI6FT;;AAGD;EAEC,QADO;EAEP,OAFO;EAGP;;;ACnGH;ED4GC;IACC;IACA;IACA,qBACC;;EAiBF;IACC;;EAGC;IACC;;;AChIJ;EDyIC;IACC;IACA;IACA,qBACC;;EAaF;IACC;;EAGC;IACC;IACA;;;AErKL;EACC;;AAEA;EACC,aNLU;EMMV;EACA;EACA;;AAGD;EACC,aNZU;EMaV;EACA%22,%22file%22:%22root.css%22%7D */

View file

@ -109,4 +109,4 @@
}
}
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../../../styles/sheets/actor/mvp.scss%22,%22../../../styles/vars.scss%22,%22../../../styles/mixins/_breakpoints.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAIC;EACC;EACA,qBACC;EASD;EACA;EACA;EACA;;AAGC;EACC;;AAED;EACC;;AACA;EACC;EACA;EACA;EACA;EACA;;AAGF;EACC;;AAEA;EACC;EACA;EACA;;AAGF;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAKH;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA,aC5FS;ED6FT;;AAGD;EAEC,QADO;EAEP,OAFO;EAGP;;;AEnGH;EF4GC;IACC;IACA;IACA,qBACC;;EAiBF;IACC;;EAGC;IACC;;;AEhIJ;EFyIC;IACC;IACA;IACA,qBACC;;EAaF;IACC;;EAGC;IACC;IACA%22,%22file%22:%22mvp.css%22%7D */
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../../../styles/sheets/actor/mvp.scss%22,%22../../../styles/_vars.scss%22,%22../../../styles/mixins/_breakpoints.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAIC;EACC;EACA,qBACC;EASD;EACA;EACA;EACA;;AAGC;EACC;;AAED;EACC;;AACA;EACC;EACA;EACA;EACA;EACA;;AAGF;EACC;;AAEA;EACC;EACA;EACA;;AAGF;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAED;EACC;;AAKH;EACC;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA;EACA,aC5FS;ED6FT;;AAGD;EAEC,QADO;EAEP,OAFO;EAGP;;;AEnGH;EF4GC;IACC;IACA;IACA,qBACC;;EAiBF;IACC;;EAGC;IACC;;;AEhIJ;EFyIC;IACC;IACA;IACA,qBACC;;EAaF;IACC;;EAGC;IACC;IACA%22,%22file%22:%22mvp.css%22%7D */

View file

@ -0,0 +1,16 @@
.dotdungeon .item--aspect {
padding: 4px;
}
.dotdungeon .item--aspect input[type=text] {
font-family: sans-serif;
font-size: 1.5em;
height: 1.5em;
width: 100%;
}
.dotdungeon .item--aspect textarea {
font-family: sans-serif;
width: 100%;
resize: vertical;
}
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%22../../../styles/sheets/items/aspect.scss%22,%22../../../styles/_vars.scss%22%5D,%22names%22:%5B%5D,%22mappings%22:%22AAEA;EACC;;AAEA;EACC,aCLU;EDMV;EACA;EACA;;AAGD;EACC,aCZU;EDaV;EACA%22,%22file%22:%22aspect.css%22%7D */

View file

@ -1,3 +0,0 @@
/*# sourceMappingURL=data:application/json;charset=utf-8,%7B%22version%22:3,%22sourceRoot%22:%22%22,%22sources%22:%5B%5D,%22names%22:%5B%5D,%22mappings%22:%22%22,%22file%22:%22vars.css%22%7D */

View file

@ -2,54 +2,60 @@
"dotdungeon.sheet.PlayerSheet": "PC Sheet",
"dotdungeon.sheet.AspectSheet": "Aspect Sheet",
"dotdungeon.panel.avatar": "Avatar",
"dotdungeon.panel.statistics": "Statistics",
"dotdungeon.panel.skills": "Skills",
"dotdungeon.panel.backpack": "Backpack",
"dotdungeon.panel.sync": "Sync",
"dotdungeon.panel.aspect": "Aspect",
"dotdungeon.panel.weapons": "Weapons",
"dotdungeon.panel.roles": "Roles",
"dotdungeon.panel.spells": "Spells",
"dotdungeon.panel.mounts": "Mounts",
"dotdungeon.panel.summons": "Summons",
"dotdungeon.panel.storage": "Storage",
"dotdungeon.actor.pc.panel.avatar": "Avatar",
"dotdungeon.actor.pc.panel.statistics": "Stats",
"dotdungeon.actor.pc.panel.skills": "Skills",
"dotdungeon.actor.pc.panel.backpack": "Backpack",
"dotdungeon.actor.pc.panel.sync": "Sync",
"dotdungeon.actor.pc.panel.aspect": "Aspect",
"dotdungeon.actor.pc.panel.weapons": "Weapons",
"dotdungeon.actor.pc.panel.roles": "Roles",
"dotdungeon.actor.pc.panel.spells": "Spells",
"dotdungeon.actor.pc.panel.mounts": "Mounts",
"dotdungeon.actor.pc.panel.summons": "Summons",
"dotdungeon.actor.pc.panel.storage": "Storage",
"dotdungeon.stat.build": "Build",
"dotdungeon.stat.meta": "Meta",
"dotdungeon.stat.presence": "Presence",
"dotdungeon.stat.hands": "Hands",
"dotdungeon.stat.tilt": "Tilt",
"dotdungeon.stat.rng": "RNG",
"dotdungeon.actor.pc.stat.build": "Build",
"dotdungeon.actor.pc.stat.meta": "Meta",
"dotdungeon.actor.pc.stat.presence": "Presence",
"dotdungeon.actor.pc.stat.hands": "Hands",
"dotdungeon.actor.pc.stat.tilt": "Tilt",
"dotdungeon.actor.pc.stat.rng": "RNG",
"dotdungeon.skills.build": "Build",
"dotdungeon.skill.defense": "Defense",
"dotdungeon.skill.magic": "Magic",
"dotdungeon.skill.melee": "Melee",
"dotdungeon.skill.platforming": "Platforming",
"dotdungeon.skill.strength": "Strength",
"dotdungeon.actor.pc.skills.build": "Build",
"dotdungeon.actor.pc.skill.defense": "Defense",
"dotdungeon.actor.pc.skill.magic": "Magic",
"dotdungeon.actor.pc.skill.melee": "Melee",
"dotdungeon.actor.pc.skill.platforming": "Platforming",
"dotdungeon.actor.pc.skill.strength": "Strength",
"dotdungeon.skills.meta": "Meta",
"dotdungeon.skill.alchemy": "Alchemy",
"dotdungeon.skill.arcanum": "Arcanum",
"dotdungeon.skill.dreams": "Dreams",
"dotdungeon.skill.lore": "Lore",
"dotdungeon.skill.navigation": "Navigation",
"dotdungeon.actor.pc.skills.meta": "Meta",
"dotdungeon.actor.pc.skill.alchemy": "Alchemy",
"dotdungeon.actor.pc.skill.arcanum": "Arcanum",
"dotdungeon.actor.pc.skill.dreams": "Dreams",
"dotdungeon.actor.pc.skill.lore": "Lore",
"dotdungeon.actor.pc.skill.navigation": "Navigation",
"dotdungeon.skills.presence": "Presence",
"dotdungeon.skill.animal_handling": "Animal Handling",
"dotdungeon.skill.perception": "Perception",
"dotdungeon.skill.sneak": "Sneak",
"dotdungeon.skill.speech": "Speech",
"dotdungeon.skill.vibes": "Vibes",
"dotdungeon.actor.pc.skills.presence": "Presence",
"dotdungeon.actor.pc.skill.animal_handling": "Animal Handling",
"dotdungeon.actor.pc.skill.perception": "Perception",
"dotdungeon.actor.pc.skill.sneak": "Sneak",
"dotdungeon.actor.pc.skill.speech": "Speech",
"dotdungeon.actor.pc.skill.vibes": "Vibes",
"dotdungeon.skills.hands": "Hands",
"dotdungeon.skill.accuracy": "Accuracy",
"dotdungeon.skill.crafting": "Crafting",
"dotdungeon.skill.engineering": "Engineering",
"dotdungeon.skill.explosives": "Explosives",
"dotdungeon.skill.piloting": "Piloting",
"dotdungeon.actor.pc.skills.hands": "Hands",
"dotdungeon.actor.pc.skill.accuracy": "Accuracy",
"dotdungeon.actor.pc.skill.crafting": "Crafting",
"dotdungeon.actor.pc.skill.engineering": "Engineering",
"dotdungeon.actor.pc.skill.explosives": "Explosives",
"dotdungeon.actor.pc.skill.piloting": "Piloting",
"dotdungeon.aria.skill-dropdown": "Your expertise level in the {skill} skill"
"dotdungeon.item.aspect.name": "Name",
"dotdungeon.item.aspect.duration": "Duration (seconds)",
"dotdungeon.item.aspect.description": "Description",
"dotdungeon.item.aspect.send-to-chat": "Send Aspect to Chat",
"dotdungeon.aria.skill-dropdown": "Your expertise level in the {skill} skill",
"dotdungeon.aria.aspect-description": "The information on how the aspect works"
}

View file

@ -9,7 +9,8 @@ export const partials = [
export async function registerHandlebarsHelpers() {
Handlebars.registerHelper({
"dotdungeon-array": createArray
"dotdungeon-array": createArray,
"dotdungeon-toFriendlyDuration": toFriendlyDuration,
});
};
@ -33,4 +34,30 @@ export async function preloadHandlebarsTemplates() {
function createArray(...args) {
return args.slice(0, -1);
};
};
const secondsInAMinute = 60;
const secondsInAnHour = 60 * secondsInAMinute;
/**
* Converts a duration into a more human-friendly format
* @param {number} duration The length of time in seconds
* @returns The human-friendly time string
*/
function toFriendlyDuration(duration) {
let friendly = ``;
if (duration >= secondsInAnHour) {
let hours = Math.floor(duration / secondsInAnHour);
friendly += `${hours}h`;
duration -= hours * secondsInAnHour;
};
if (duration >= secondsInAMinute) {
let minutes = Math.floor(duration / secondsInAMinute);
friendly += `${minutes}m`;
duration -= minutes * secondsInAMinute;
};
if (duration > 0) {
friendly += `${duration}s`;
};
return friendly;
}

View file

@ -2,7 +2,6 @@ export class AspectItemData extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
name: new fields.HTMLField({ nullable: true, blank: false, trim: true }),
used: new fields.BooleanField(),
/** The number of seconds that the effect of the aspect stays */
deactivateAfter: new fields.NumberField({ nullable: true }),

View file

@ -12,10 +12,20 @@ export class AspectSheet extends ItemSheet {
return opts;
};
activateListeners(html) {
super.activateListeners(html);
if (this.document.isEmbedded) return;
if (!this.isEditable) return;
console.debug(`.dungeon | Adding event listeners for Item: ${this.id}`);
};
getData() {
const ctx = super.getData();
const ctx = {};
const item = this.item.toObject(false);
ctx.name = super.name;
ctx.item = item;
ctx.system = item.system;
ctx.flags = item.flags;

View file

@ -13,6 +13,7 @@ export class PlayerSheet extends ActorSheet {
activateListeners(html) {
super.activateListeners(html);
if (this.document.isEmbedded) return;
if (!this.isEditable) return;
console.debug(`.dungeon | Adding event listeners for Actor: ${this.id}`);
@ -33,4 +34,4 @@ export class PlayerSheet extends ActorSheet {
console.groupEnd();
return ctx;
};
}
};

View file

@ -0,0 +1,829 @@
{
"Actor": {
"types": [
"character",
"npc",
"vehicle",
"group"
],
"templates": {
"common": {
"abilities": {
"str": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
},
"dex": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
},
"con": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
},
"int": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
},
"wis": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
},
"cha": {
"value": 10,
"proficient": 0,
"max": null,
"bonuses": {
"check": "",
"save": ""
}
}
},
"attributes": {
"ac": {
"flat": null,
"calc": "default",
"formula": ""
},
"hp": {
"value": 10,
"max": null,
"temp": 0,
"tempmax": 0
},
"init": {
"ability": "",
"bonus": ""
},
"movement": {
"burrow": null,
"climb": null,
"fly": null,
"swim": null,
"walk": null,
"units": null,
"hover": false
}
},
"details": {
"biography": {
"value": "",
"public": ""
}
},
"traits": {
"size": "med",
"di": {
"value": [],
"bypasses": [],
"custom": ""
},
"dr": {
"value": [],
"bypasses": [],
"custom": ""
},
"dv": {
"value": [],
"bypasses": [],
"custom": ""
},
"ci": {
"value": [],
"custom": ""
}
},
"currency": {
"pp": 0,
"gp": 0,
"ep": 0,
"sp": 0,
"cp": 0
}
},
"creature": {
"attributes": {
"attunement": {
"max": 3
},
"senses": {
"darkvision": null,
"blindsight": null,
"tremorsense": null,
"truesight": null,
"units": null,
"special": ""
},
"spellcasting": "int"
},
"details": {
"alignment": "",
"race": ""
},
"skills": {
"acr": {
"value": 0,
"ability": "dex",
"bonuses": {
"check": "",
"passive": ""
}
},
"ani": {
"value": 0,
"ability": "wis",
"bonuses": {
"check": "",
"passive": ""
}
},
"arc": {
"value": 0,
"ability": "int",
"bonuses": {
"check": "",
"passive": ""
}
},
"ath": {
"value": 0,
"ability": "str",
"bonuses": {
"check": "",
"passive": ""
}
},
"dec": {
"value": 0,
"ability": "cha",
"bonuses": {
"check": "",
"passive": ""
}
},
"his": {
"value": 0,
"ability": "int",
"bonuses": {
"check": "",
"passive": ""
}
},
"ins": {
"value": 0,
"ability": "wis",
"bonuses": {
"check": "",
"passive": ""
}
},
"itm": {
"value": 0,
"ability": "cha",
"bonuses": {
"check": "",
"passive": ""
}
},
"inv": {
"value": 0,
"ability": "int",
"bonuses": {
"check": "",
"passive": ""
}
},
"med": {
"value": 0,
"ability": "wis",
"bonuses": {
"check": "",
"passive": ""
}
},
"nat": {
"value": 0,
"ability": "int",
"bonuses": {
"check": "",
"passive": ""
}
},
"prc": {
"value": 0,
"ability": "wis",
"bonuses": {
"check": "",
"passive": ""
}
},
"prf": {
"value": 0,
"ability": "cha",
"bonuses": {
"check": "",
"passive": ""
}
},
"per": {
"value": 0,
"ability": "cha",
"bonuses": {
"check": "",
"passive": ""
}
},
"rel": {
"value": 0,
"ability": "int",
"bonuses": {
"check": "",
"passive": ""
}
},
"slt": {
"value": 0,
"ability": "dex",
"bonuses": {
"check": "",
"passive": ""
}
},
"ste": {
"value": 0,
"ability": "dex",
"bonuses": {
"check": "",
"passive": ""
}
},
"sur": {
"value": 0,
"ability": "wis",
"bonuses": {
"check": "",
"passive": ""
}
}
},
"tools": {},
"traits": {
"languages": {
"value": [],
"custom": ""
}
},
"spells": {},
"bonuses": {
"mwak": {
"attack": "",
"damage": ""
},
"rwak": {
"attack": "",
"damage": ""
},
"msak": {
"attack": "",
"damage": ""
},
"rsak": {
"attack": "",
"damage": ""
},
"abilities": {
"check": "",
"save": "",
"skill": ""
},
"spell": {
"dc": ""
}
}
}
},
"htmlFields": [
"details.biography.value",
"details.biography.public",
"description.full",
"description.summary"
],
"character": {
"templates": [
"common",
"creature"
],
"attributes": {
"hp": {
"value": 0,
"bonuses": {
"level": "",
"overall": ""
}
},
"death": {
"success": 0,
"failure": 0
},
"exhaustion": 0,
"inspiration": false
},
"details": {
"background": "",
"originalClass": "",
"xp": {
"value": 0
},
"appearance": "",
"trait": "",
"ideal": "",
"bond": "",
"flaw": ""
},
"resources": {
"primary": {
"value": 0,
"max": 0,
"sr": false,
"lr": false,
"label": ""
},
"secondary": {
"value": 0,
"max": 0,
"sr": false,
"lr": false,
"label": ""
},
"tertiary": {
"value": 0,
"max": 0,
"sr": false,
"lr": false,
"label": ""
}
},
"traits": {
"weaponProf": {
"value": [],
"custom": ""
},
"armorProf": {
"value": [],
"custom": ""
},
"toolProf": {
"value": [],
"custom": ""
}
}
},
"npc": {
"templates": [
"common",
"creature"
],
"attributes": {
"hp": {
"max": 10,
"formula": ""
}
},
"details": {
"type": {
"value": "",
"subtype": "",
"swarm": "",
"custom": ""
},
"environment": "",
"cr": 1,
"spellLevel": 0,
"source": ""
},
"resources": {
"legact": {
"value": 0,
"max": 0
},
"legres": {
"value": 0,
"max": 0
},
"lair": {
"value": false,
"initiative": null
}
}
},
"vehicle": {
"templates": [
"common"
],
"vehicleType": "water",
"abilities": {
"int": {
"value": 0
},
"wis": {
"value": 0
},
"cha": {
"value": 0
}
},
"attributes": {
"ac": {
"calc": "flat",
"motionless": ""
},
"actions": {
"stations": false,
"value": 0,
"thresholds": {
"2": null,
"1": null,
"0": null
}
},
"hp": {
"value": null,
"dt": null,
"mt": null
},
"capacity": {
"creature": "",
"cargo": 0
}
},
"traits": {
"size": "lg",
"dimensions": "",
"di": {
"value": [
"poison",
"psychic"
]
},
"ci": {
"value": [
"blinded",
"charmed",
"deafened",
"frightened",
"paralyzed",
"petrified",
"poisoned",
"stunned",
"unconscious"
]
}
},
"cargo": {
"crew": [],
"passengers": []
}
},
"group": {
"description": {
"full": "",
"summary": ""
},
"members": [],
"attributes": {
"movement": {
"land": 0,
"water": 0,
"air": 0
}
},
"currency": {
"pp": 0,
"gp": 0,
"ep": 0,
"sp": 0,
"cp": 0
}
}
},
"Item": {
"types": [
"weapon",
"equipment",
"consumable",
"tool",
"loot",
"race",
"background",
"class",
"subclass",
"spell",
"feat",
"backpack"
],
"templates": {
"itemDescription": {
"description": {
"value": "",
"chat": "",
"unidentified": ""
},
"source": {}
},
"physicalItem": {
"quantity": 1,
"weight": 0,
"price": {
"value": 0,
"denomination": "gp"
},
"attunement": 0,
"equipped": false,
"rarity": "",
"identified": true
},
"activatedEffect": {
"activation": {
"type": "",
"cost": null,
"condition": ""
},
"duration": {
"value": "",
"units": ""
},
"cover": null,
"crewed": false,
"target": {
"value": null,
"width": null,
"units": "",
"type": ""
},
"range": {
"value": null,
"long": null,
"units": ""
},
"uses": {
"value": null,
"max": "",
"per": null,
"recovery": ""
},
"consume": {
"type": "",
"target": null,
"amount": null
}
},
"action": {
"ability": null,
"actionType": null,
"attackBonus": "",
"chatFlavor": "",
"critical": {
"threshold": null,
"damage": ""
},
"damage": {
"parts": [],
"versatile": ""
},
"formula": "",
"save": {
"ability": "",
"dc": null,
"scaling": "spell"
}
},
"mountable": {
"armor": {
"value": null
},
"hp": {
"value": null,
"max": null,
"dt": null,
"conditions": ""
}
}
},
"htmlFields": [
"description.value",
"description.chat",
"description.unidentified"
],
"background": {
"templates": [
"itemDescription"
],
"advancement": []
},
"backpack": {
"templates": [
"itemDescription",
"physicalItem"
],
"capacity": {
"type": "weight",
"value": null,
"weightless": false
},
"currency": {
"cp": 0,
"sp": 0,
"ep": 0,
"gp": 0,
"pp": 0
}
},
"class": {
"templates": [
"itemDescription"
],
"identifier": "",
"levels": 1,
"hitDice": "d6",
"hitDiceUsed": 0,
"advancement": [],
"spellcasting": {
"progression": "none",
"ability": ""
}
},
"consumable": {
"templates": [
"itemDescription",
"physicalItem",
"activatedEffect",
"action"
],
"consumableType": "potion",
"uses": {
"autoDestroy": false
}
},
"equipment": {
"templates": [
"itemDescription",
"physicalItem",
"activatedEffect",
"action",
"mountable"
],
"armor": {
"type": "light",
"value": null,
"dex": null
},
"baseItem": "",
"speed": {
"value": null,
"conditions": ""
},
"strength": null,
"stealth": false,
"proficient": null
},
"feat": {
"templates": [
"itemDescription",
"activatedEffect",
"action"
],
"type": {
"value": "",
"subtype": ""
},
"requirements": "",
"recharge": {
"value": null,
"charged": false
}
},
"loot": {
"templates": [
"itemDescription",
"physicalItem"
]
},
"tool": {
"templates": [
"itemDescription",
"physicalItem"
],
"toolType": "",
"baseItem": "",
"ability": "int",
"chatFlavor": "",
"proficient": null,
"bonus": ""
},
"race": {},
"spell": {
"templates": [
"itemDescription",
"activatedEffect",
"action"
],
"level": 1,
"school": "",
"components": {
"vocal": false,
"somatic": false,
"material": false,
"ritual": false,
"concentration": false
},
"materials": {
"value": "",
"consumed": false,
"cost": 0,
"supply": 0
},
"preparation": {
"mode": "prepared",
"prepared": false
},
"scaling": {
"mode": "none",
"formula": null
}
},
"subclass": {
"templates": [
"itemDescription"
],
"identifier": "",
"classIdentifier": "",
"advancement": [],
"spellcasting": {
"progression": "none",
"ability": ""
}
},
"weapon": {
"templates": [
"itemDescription",
"physicalItem",
"activatedEffect",
"action",
"mountable"
],
"weaponType": "simpleM",
"baseItem": "",
"properties": {},
"proficient": null
}
},
"JournalEntryPage": {
"types": [
"class"
],
"htmlFields": [
"description.value",
"description.additionalHitPoints",
"description.additionalTraits",
"description.additionalEquipment",
"description.subclass"
],
"class": {
"item": "",
"description": {
"value": "",
"additionalHitPoints": "",
"additionalTraits": "",
"additionalEquipment": "",
"subclass": ""
},
"subclassHeader": "",
"subclassItems": []
}
}
}

172
references/simple.js Normal file
View file

@ -0,0 +1,172 @@
/**
* A simple and flexible system for world-building using an arbitrary collection of character and item attributes
* Author: Atropos
*/
// Import Modules
import { SimpleActor } from "./actor.js";
import { SimpleItem } from "./item.js";
import { SimpleItemSheet } from "./item-sheet.js";
import { SimpleActorSheet } from "./actor-sheet.js";
import { preloadHandlebarsTemplates } from "./templates.js";
import { createWorldbuildingMacro } from "./macro.js";
import { SimpleToken, SimpleTokenDocument } from "./token.js";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
/**
* Init hook.
*/
Hooks.once("init", async function() {
console.log(`Initializing Simple Worldbuilding System`);
/**
* Set an initiative formula for the system. This will be updated later.
* @type {String}
*/
CONFIG.Combat.initiative = {
formula: "1d20",
decimals: 2
};
game.worldbuilding = {
SimpleActor,
createWorldbuildingMacro
};
// Define custom Document classes
CONFIG.Actor.documentClass = SimpleActor;
CONFIG.Item.documentClass = SimpleItem;
CONFIG.Token.documentClass = SimpleTokenDocument;
CONFIG.Token.objectClass = SimpleToken;
// Register sheet application classes
Actors.unregisterSheet("core", ActorSheet);
Actors.registerSheet("worldbuilding", SimpleActorSheet, { makeDefault: true });
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("worldbuilding", SimpleItemSheet, { makeDefault: true });
// Register system settings
game.settings.register("worldbuilding", "macroShorthand", {
name: "SETTINGS.SimpleMacroShorthandN",
hint: "SETTINGS.SimpleMacroShorthandL",
scope: "world",
type: Boolean,
default: true,
config: true
});
// Register initiative setting.
game.settings.register("worldbuilding", "initFormula", {
name: "SETTINGS.SimpleInitFormulaN",
hint: "SETTINGS.SimpleInitFormulaL",
scope: "world",
type: String,
default: "1d20",
config: true,
onChange: formula => _simpleUpdateInit(formula, true)
});
// Retrieve and assign the initiative formula setting.
const initFormula = game.settings.get("worldbuilding", "initFormula");
_simpleUpdateInit(initFormula);
/**
* Update the initiative formula.
* @param {string} formula - Dice formula to evaluate.
* @param {boolean} notify - Whether or not to post nofications.
*/
function _simpleUpdateInit(formula, notify = false) {
const isValid = Roll.validate(formula);
if ( !isValid ) {
if ( notify ) ui.notifications.error(`${game.i18n.localize("SIMPLE.NotifyInitFormulaInvalid")}: ${formula}`);
return;
}
CONFIG.Combat.initiative.formula = formula;
}
/**
* Slugify a string.
*/
Handlebars.registerHelper('slugify', function(value) {
return value.slugify({strict: true});
});
// Preload template partials
await preloadHandlebarsTemplates();
});
/**
* Macrobar hook.
*/
Hooks.on("hotbarDrop", (bar, data, slot) => createWorldbuildingMacro(data, slot));
/**
* Adds the actor template context menu.
*/
Hooks.on("getActorDirectoryEntryContext", (html, options) => {
// Define an actor as a template.
options.push({
name: game.i18n.localize("SIMPLE.DefineTemplate"),
icon: '<i class="fas fa-stamp"></i>',
condition: li => {
const actor = game.actors.get(li.data("documentId"));
return !actor.isTemplate;
},
callback: li => {
const actor = game.actors.get(li.data("documentId"));
actor.setFlag("worldbuilding", "isTemplate", true);
}
});
// Undefine an actor as a template.
options.push({
name: game.i18n.localize("SIMPLE.UnsetTemplate"),
icon: '<i class="fas fa-times"></i>',
condition: li => {
const actor = game.actors.get(li.data("documentId"));
return actor.isTemplate;
},
callback: li => {
const actor = game.actors.get(li.data("documentId"));
actor.setFlag("worldbuilding", "isTemplate", false);
}
});
});
/**
* Adds the item template context menu.
*/
Hooks.on("getItemDirectoryEntryContext", (html, options) => {
// Define an item as a template.
options.push({
name: game.i18n.localize("SIMPLE.DefineTemplate"),
icon: '<i class="fas fa-stamp"></i>',
condition: li => {
const item = game.items.get(li.data("documentId"));
return !item.isTemplate;
},
callback: li => {
const item = game.items.get(li.data("documentId"));
item.setFlag("worldbuilding", "isTemplate", true);
}
});
// Undefine an item as a template.
options.push({
name: game.i18n.localize("SIMPLE.UnsetTemplate"),
icon: '<i class="fas fa-times"></i>',
condition: li => {
const item = game.items.get(li.data("documentId"));
return item.isTemplate;
},
callback: li => {
const item = game.items.get(li.data("documentId"));
item.setFlag("worldbuilding", "isTemplate", false);
}
});
});

View file

@ -1,2 +1,3 @@
$title-font: 'Pixelify Sans', sans-serif;
$body-font: sans-serif;
$background: #f2f2f2;

View file

@ -1,16 +1,10 @@
@mixin bp-m {
@container (max-width: 700px) {
@container (max-width: 620px) {
@content
};
};
@mixin bp-s {
@container (max-width: 550px) {
@content
};
};
@mixin bp-xs {
@container (max-width: 400px) {
@content
};

View file

@ -1,3 +1,5 @@
@mixin fvtt_reset {
all: initial;
display: block;
box-sizing: border-box;
}

View file

@ -0,0 +1,12 @@
@mixin input-generic {
border-width: 2px;
border-radius: 4px;
border-style: solid;
border-color: rgba(0,0,0, 0.4);
background-color: rgba(0,0,0, 0.1);
&:focus,
&:active {
border-color: rgba(0,0,0, 1);
}
}

View file

@ -1,3 +1,4 @@
@use "./mixins/partials" as *;
@use "./mixins/foundry" as *;
@use "./vars.scss" as *;
@ -5,6 +6,14 @@
// Reset the parts of Foundry's styling which gets in the way of what I want
.dotdungeon > .window-content {
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 5px;
}
h2, h3, h4, h5, h6 {
@include fvtt_reset;
display: block;
@ -12,12 +21,24 @@
margin: 0;
}
label {
display: block;
}
button, button:hover {
@include fvtt_reset;
font-family: inherit;
cursor: pointer;
}
input[type="text"],
input[type="number"],
textarea {
@include fvtt_reset;
padding: 5px 7px;
@include input-generic;
}
select, select:hover {
cursor: pointer;
}
@ -36,4 +57,5 @@
@import "./sheets/partials/stat.scss";
@import "./sheets/partials/skill.scss";
@import "./sheets/actor/mvp.scss";
@import "./sheets/actor/mvp.scss";
@import "./sheets/items/aspect.scss";

View file

@ -105,7 +105,7 @@
}
@include bp-s {
@include bp-m {
.dotdungeon {
.actor--pc {
grid-template-columns: repeat(2, minmax(0, 1fr));
@ -140,16 +140,34 @@
}
}
@include bp-xs {
@include bp-s {
.dotdungeon {
.actor--pc {
grid-template-columns: 1fr;
grid-template-rows: repeat(12, min-content);
grid-template-areas:
"avatar"
"stats"
"skills";
"sync"
"skills"
"aspect"
"roles"
"backpack"
"weapons"
"spells"
"mounts"
"summons"
"storage";
}
.panel {
background: blueviolet;
&__header {
.icon {
display: none;
visibility: hidden;
}
}
}
}
}

View file

@ -0,0 +1,18 @@
@use "../../vars" as *;
.dotdungeon .item--aspect {
padding: 4px;
input[type=text] {
font-family: $body-font;
font-size: 1.5em;
height: 1.5em;
width: 100%;
}
textarea {
font-family: $body-font;
width: 100%;
resize: vertical;
}
}

View file

@ -1,23 +1,23 @@
<div class="skill-group">
<h3 class="skill-group__label">{{localize "dotdungeon.skills.build"}}</h3>
<h3 class="skill-group__label">{{localize "dotdungeon.actor.pc.skills.build"}}</h3>
{{#each (dotdungeon-array "defense" "magic" "melee" "platforming" "strength")}}
{{> dotdungeon.skill name=this}}
{{/each}}
</div>
<div class="skill-group">
<h3 class="skill-group__label">{{localize "dotdungeon.skills.meta"}}</h3>
<h3 class="skill-group__label">{{localize "dotdungeon.actor.pc.skills.meta"}}</h3>
{{#each (dotdungeon-array "alchemy" "arcanum" "dreams" "lore" "navigation")}}
{{> dotdungeon.skill name=this}}
{{/each}}
</div>
<div class="skill-group">
<h3 class="skill-group__label">{{localize "dotdungeon.skills.presence"}}</h3>
<h3 class="skill-group__label">{{localize "dotdungeon.actor.pc.skills.presence"}}</h3>
{{#each (dotdungeon-array "alchemy" "arcanum" "dreams" "lore" "navigation")}}
{{> dotdungeon.skill name=this}}
{{/each}}
</div>
<div class="skill-group">
<h3 class="skill-group__label">{{localize "dotdungeon.skills.hands"}}</h3>
<h3 class="skill-group__label">{{localize "dotdungeon.actor.pc.skills.hands"}}</h3>
{{#each (dotdungeon-array "animal_handling" "perception" "sneak" "speech" "vibes")}}
{{> dotdungeon.skill name=this}}
{{/each}}

View file

@ -1,6 +1,6 @@
<label class="stat stat--{{name}}">
<button class="roll-stat" data-stat="{{name}}">
{{localize (concat "dotdungeon.stat." name)}}
{{localize (concat "dotdungeon.actor.pc.stat." name)}}
</button>
{{> dotdungeon.dice_choice fieldToUpdate=(concat "system.stats." name) selected=value }}
</label>

View file

@ -1,41 +1,40 @@
<form autocomplete="off" class="actor--pc">
{{log system}}
{{#> dotdungeon.panel class="avatar" title="dotdungeon.panel.avatar"}}
{{#> dotdungeon.panel class="avatar" title="dotdungeon.actor.pc.panel.avatar"}}
Avatar Content
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="stats" title="dotdungeon.panel.statistics"}}
{{#> dotdungeon.panel class="stats" title="dotdungeon.actor.pc.panel.statistics"}}
{{#each system.stats }}
{{> dotdungeon.stat name=@key value=this}}
{{/each}}
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="skills" title="dotdungeon.panel.skills"}}
{{#> dotdungeon.panel class="skills" title="dotdungeon.actor.pc.panel.skills"}}
Skills
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="backpack" title="dotdungeon.panel.backpack"}}
{{#> dotdungeon.panel class="backpack" title="dotdungeon.actor.pc.panel.backpack"}}
Backpack
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="sync" title="dotdungeon.panel.sync"}}
{{#> dotdungeon.panel class="sync" title="dotdungeon.actor.pc.panel.sync"}}
Sync
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="aspect" title="dotdungeon.panel.aspect"}}
{{#> dotdungeon.panel class="aspect" title="dotdungeon.actor.pc.panel.aspect"}}
Aspect
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="weapons" title="dotdungeon.panel.weapons"}}
{{#> dotdungeon.panel class="weapons" title="dotdungeon.actor.pc.panel.weapons"}}
Weapons
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="spells" title="dotdungeon.panel.spells"}}
{{#> dotdungeon.panel class="spells" title="dotdungeon.actor.pc.panel.spells"}}
Spells
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="roles" title="dotdungeon.panel.roles"}}
{{#> dotdungeon.panel class="roles" title="dotdungeon.actor.pc.panel.roles"}}
Roles
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="mounts" title="dotdungeon.panel.mounts"}}
{{#> dotdungeon.panel class="mounts" title="dotdungeon.actor.pc.panel.mounts"}}
Mounts
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="summons" title="dotdungeon.panel.summons"}}
{{#> dotdungeon.panel class="summons" title="dotdungeon.actor.pc.panel.summons"}}
Summons
{{/ dotdungeon.panel}}
{{#> dotdungeon.panel class="storage" title="dotdungeon.panel.storage"}}
{{#> dotdungeon.panel class="storage" title="dotdungeon.actor.pc.panel.storage"}}
Storage
{{/ dotdungeon.panel}}
</form>

View file

@ -1,4 +1,27 @@
<form autocomplete="off" class="item--aspect">
{{log system}}
<h2>I'm an Item :')</h2>
<h2>
<input
type="text"
placeholder="{{localize "dotdungeon.item.aspect.name"}}"
name="name"
value="{{item.name}}"
>
</h2>
<label>
{{localize "dotdungeon.item.aspect.duration"}}
<input
type="number"
class="duration"
name="system.deactivateAfter"
value="{{system.deactivateAfter}}"
>
{{dotdungeon-toFriendlyDuration system.deactivateAfter}}
</label>
<label>
{{localize "dotdungeon.item.aspect.description"}}:
<textarea
name="system.info"
aria-description="{{localize "dotdungeon.aria.aspect-description"}}"
>{{system.info}}</textarea>
</label>
</form>