initial commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# IDE
|
||||
.idea/
|
||||
.vs/
|
||||
|
||||
# Node Modules
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
@@ -0,0 +1,7 @@
|
||||
# IDE
|
||||
.idea/
|
||||
.vs/
|
||||
|
||||
# Node Modules
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
@@ -0,0 +1,35 @@
|
||||
# DeltaGreen System
|
||||
|
||||
This system is a Delta Green (standalone) system based on the Agent's Handbook from Arc Dream Publishing.
|
||||
|
||||
# Delta Green Community License
|
||||
Published by arrangement with the Delta Green Partnership. The intellectual property known as Delta Green is a trademark and copyright owned by the Delta Green Partnership, who has licensed its use here. The contents of this system are free for public use, excepting those elements that are components of the Delta Green intellectual property.
|
||||
|
||||
# Foundry VTT License
|
||||
This code uses the Foundry VTT and its API under the terms of the Limited License Agreement for Module Development.
|
||||
Foundry VTT is a Copyright of Foundry Gaming, LLC.
|
||||
|
||||
# Delta Green Foundry System License
|
||||
The code (HTML, CSS, Javascript, etc.) in this system and any related information are provided under the MIT license, excepting that which comes via Foundry VTT
|
||||
excepting that which is otherwise covered by the Delta Green Partnership and/or Arc Dream Publishing.
|
||||
|
||||
Copyright 2020 N. Eimers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# Licenses, Citations and Shoutouts
|
||||
System Base Code
|
||||
This system is built upon on Matt Smith's (AKA Asacolips) excellent Boilerplate System and corresponding tutorial.
|
||||
https://gitlab.com/asacolips-projects/foundry-mods/foundryvtt-system-tutorial
|
||||
|
||||
DIDACT GOTHIC
|
||||
|
||||
The font used in many places is Didact Gothic, by Daniel Johnson and Cyreal.
|
||||
https://fonts.google.com/specimen/Didact+Gothic?query=did#about
|
||||
|
||||
It is licensed and used under the Open Font License.
|
||||
https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
|
||||
@@ -0,0 +1,281 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Didact+Gothic");
|
||||
/* Global styles */
|
||||
.window-app {
|
||||
font-family: "Didact Gothic", "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.rollable:hover, .rollable:focus {
|
||||
color: #000;
|
||||
text-shadow: 0 0 10px red;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.grid,
|
||||
.grid-2col {
|
||||
display: grid;
|
||||
grid-column: span 2 / span 2;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid-3col {
|
||||
grid-column: span 3 / span 3;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-4col {
|
||||
grid-column: span 4 / span 4;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-5col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-6col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-7col {
|
||||
grid-column: span 7 / span 7;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-8col {
|
||||
grid-column: span 8 / span 8;
|
||||
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-9col {
|
||||
grid-column: span 9 / span 9;
|
||||
grid-template-columns: repeat(9, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-10col {
|
||||
grid-column: span 10 / span 10;
|
||||
grid-template-columns: repeat(10, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-11col {
|
||||
grid-column: span 11 / span 11;
|
||||
grid-template-columns: repeat(11, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-12col {
|
||||
grid-column: span 12 / span 12;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-group-center,
|
||||
.flex-group-left,
|
||||
.flex-group-right {
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.flex-group-left {
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.flex-group-right {
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* Styles limited to delta green sheets */
|
||||
.deltagreen {
|
||||
font-family: "Didact Gothic", "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.deltagreen .item-form {
|
||||
font-family: "Didact Gothic", "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-header {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 300px;
|
||||
flex: 0 0 300px;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-header .profile-img {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 100px;
|
||||
flex: 0 0 100px;
|
||||
height: 100px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-header .header-fields {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-header h1.charname {
|
||||
height: 50px;
|
||||
padding: 0px;
|
||||
margin: 5px 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-header h1.charname input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-tabs {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0;
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.deltagreen .sheet-body,
|
||||
.deltagreen .sheet-body .tab,
|
||||
.deltagreen .sheet-body .tab .editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.deltagreen .tox .tox-editor-container {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.deltagreen .tox .tox-edit-area {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.deltagreen .resource-label {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.deltagreen .tabs {
|
||||
height: 40px;
|
||||
border-top: 1px solid #AAA;
|
||||
border-bottom: 1px solid #AAA;
|
||||
}
|
||||
|
||||
.deltagreen .tabs .item {
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.deltagreen .tabs .item.active {
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.deltagreen .items-list {
|
||||
list-style: none;
|
||||
margin: 7px 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item {
|
||||
height: 30px;
|
||||
line-height: 24px;
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid #BBB;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item .item-image {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 24px;
|
||||
flex: 0 0 24px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item-name {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.deltagreen .items-list .item-controls {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 86px;
|
||||
flex: 0 0 86px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.deltagreen button.btn-tiny{
|
||||
height: 26px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
span.breaking-point-label{
|
||||
justify-content: right;
|
||||
margin-right: 10px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
span.left-aligned-label{
|
||||
justify-content: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
span.max-attribute-value-label{
|
||||
border: 1px solid rgb(122, 121, 113);
|
||||
border-radius: 3px;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
const gulp = require('gulp');
|
||||
const prefix = require('gulp-autoprefixer');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const sass = require('gulp-sass');
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Compile Sass
|
||||
/* ----------------------------------------- */
|
||||
|
||||
// Small error handler helper function.
|
||||
function handleError(err) {
|
||||
console.log(err.toString());
|
||||
this.emit('end');
|
||||
}
|
||||
|
||||
const SYSTEM_SCSS = ["scss/**/*.scss"];
|
||||
function compileScss() {
|
||||
// Configure options for sass output. For example, 'expanded' or 'nested'
|
||||
let options = {
|
||||
outputStyle: 'expanded'
|
||||
};
|
||||
return gulp.src(SYSTEM_SCSS)
|
||||
.pipe(
|
||||
sass(options)
|
||||
.on('error', handleError)
|
||||
)
|
||||
.pipe(prefix({
|
||||
cascade: false
|
||||
}))
|
||||
.pipe(gulp.dest("./css"))
|
||||
}
|
||||
const css = gulp.series(compileScss);
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Watch Updates
|
||||
/* ----------------------------------------- */
|
||||
|
||||
function watchUpdates() {
|
||||
gulp.watch(SYSTEM_SCSS, css);
|
||||
}
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Export Tasks
|
||||
/* ----------------------------------------- */
|
||||
|
||||
exports.default = gulp.series(
|
||||
compileScss,
|
||||
watchUpdates
|
||||
);
|
||||
exports.css = css;
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
Vendored
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class DeltaGreenActorSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["deltagreen", "sheet", "actor"],
|
||||
template: "systems/deltagreen/templates/actor/actor-sheet.html",
|
||||
width: 600,
|
||||
height: 600,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
getData() {
|
||||
const data = super.getData();
|
||||
|
||||
//data.dtypes = ["String", "Number", "Boolean"];
|
||||
//for (let attr of Object.values(data.data.attributes)) {
|
||||
// attr.isCheckbox = attr.dtype === "Boolean";
|
||||
//}
|
||||
|
||||
// Prepare items.
|
||||
if (this.actor.data.type == 'character') {
|
||||
this._prepareCharacterItems(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Organize and classify Items for Character sheets.
|
||||
*
|
||||
* @param {Object} actorData The actor to prepare.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
_prepareCharacterItems(sheetData) {
|
||||
const actorData = sheetData.actor;
|
||||
|
||||
// Initialize containers.
|
||||
const gear = [];
|
||||
const features = [];
|
||||
const spells = {
|
||||
0: [],
|
||||
1: [],
|
||||
2: [],
|
||||
3: [],
|
||||
4: [],
|
||||
5: [],
|
||||
6: [],
|
||||
7: [],
|
||||
8: [],
|
||||
9: []
|
||||
};
|
||||
|
||||
// Iterate through items, allocating to containers
|
||||
// let totalWeight = 0;
|
||||
for (let i of sheetData.items) {
|
||||
let item = i.data;
|
||||
i.img = i.img || DEFAULT_TOKEN;
|
||||
// Append to gear.
|
||||
if (i.type === 'item') {
|
||||
gear.push(i);
|
||||
}
|
||||
// Append to features.
|
||||
else if (i.type === 'feature') {
|
||||
features.push(i);
|
||||
}
|
||||
// Append to spells.
|
||||
else if (i.type === 'spell') {
|
||||
if (i.data.spellLevel != undefined) {
|
||||
spells[i.data.spellLevel].push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign and return
|
||||
actorData.gear = gear;
|
||||
actorData.features = features;
|
||||
actorData.spells = spells;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Add Inventory Item
|
||||
html.find('.item-create').click(this._onItemCreate.bind(this));
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const item = this.actor.getOwnedItem(li.data("itemId"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
|
||||
// Delete Inventory Item
|
||||
html.find('.item-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.deleteOwnedItem(li.data("itemId"));
|
||||
li.slideUp(200, () => this.render(false));
|
||||
});
|
||||
|
||||
// Rollable abilities.
|
||||
html.find('.rollable').click(this._onRoll.bind(this));
|
||||
|
||||
html.find('#btnResetBreakingPoint').click(this._resetBreakingPoint.bind(this));
|
||||
|
||||
// Drag events for macros.
|
||||
if (this.actor.owner) {
|
||||
let handler = ev => this._onDragItemStart(ev);
|
||||
html.find('li.item').each((i, li) => {
|
||||
if (li.classList.contains("inventory-header")) return;
|
||||
li.setAttribute("draggable", true);
|
||||
li.addEventListener("dragstart", handler, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset
|
||||
* @param {Event} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
_onItemCreate(event) {
|
||||
event.preventDefault();
|
||||
const header = event.currentTarget;
|
||||
// Get the type of item to create.
|
||||
const type = header.dataset.type;
|
||||
// Grab any data associated with this control.
|
||||
const data = duplicate(header.dataset);
|
||||
// Initialize a default name.
|
||||
const name = `New ${type.capitalize()}`;
|
||||
// Prepare the item object.
|
||||
const itemData = {
|
||||
name: name,
|
||||
type: type,
|
||||
data: data
|
||||
};
|
||||
// Remove the type from the dataset since it's in the itemData.type prop.
|
||||
delete itemData.data["type"];
|
||||
|
||||
// Finally, create the item!
|
||||
return this.actor.createOwnedItem(itemData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clickable rolls.
|
||||
* @param {Event} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
_onRoll(event) {
|
||||
event.preventDefault();
|
||||
const element = event.currentTarget;
|
||||
const dataset = element.dataset;
|
||||
|
||||
if (dataset.roll) {
|
||||
let roll = new Roll(dataset.roll, this.actor.data.data);
|
||||
let key = dataset.label ? dataset.label : '';
|
||||
let label = dataset.label ? `Rolling ${dataset.label.toUpperCase()}` : '';
|
||||
let targetVal = "";
|
||||
|
||||
// check the 'data-target="something" property to determine how to grab the target for the roll
|
||||
if(dataset.target === "statistic.x5"){
|
||||
let stat = this.actor.data.data.statistics[key];
|
||||
targetVal = stat.x5;
|
||||
label += `, Target: ${targetVal}`;
|
||||
}
|
||||
else if(dataset.target === "sanity"){
|
||||
targetVal = this.actor.data.data.sanity.value;
|
||||
label += `, Target: ${targetVal}`;
|
||||
}
|
||||
|
||||
roll.roll().toMessage({
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
flavor: label
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_resetBreakingPoint(event){
|
||||
//let actorData = this.actor.data;
|
||||
|
||||
console.log('Resetting breaking point...');
|
||||
//console.log(actorData);
|
||||
this.actor.data.data.sanity.currentBreakingPoint = this.actor.data.data.sanity.value - this.actor.data.data.statistics.pow.value;
|
||||
|
||||
this._render();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
|
||||
* @extends {Actor}
|
||||
*/
|
||||
export class DeltaGreenActor extends Actor {
|
||||
|
||||
/**
|
||||
* Augment the basic actor data with additional dynamic data.
|
||||
*/
|
||||
prepareData() {
|
||||
super.prepareData();
|
||||
|
||||
const actorData = this.data;
|
||||
const data = actorData.data;
|
||||
const flags = actorData.flags;
|
||||
|
||||
// Make separate methods for each Actor type (character, npc, etc.) to keep
|
||||
// things organized.
|
||||
if (actorData.type === 'agent') this._prepareAgentData(actorData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Agent type specific data
|
||||
*/
|
||||
_prepareAgentData(actorData) {
|
||||
const data = actorData.data;
|
||||
|
||||
// Make modifications to data here. For example:
|
||||
|
||||
// Loop through ability scores, and add their modifiers to our sheet output.
|
||||
for (let [key, statistic] of Object.entries(data.statistics)) {
|
||||
|
||||
// the x5 is just whatever the raw statistic is x 5 to turn it into a d100 percentile
|
||||
statistic.x5 = statistic.value * 5;
|
||||
}
|
||||
//console.log(data.statistics);
|
||||
console.log(actorData);
|
||||
actorData.data.wp.max = actorData.data.statistics.pow.value;
|
||||
|
||||
actorData.data.health.max = Math.ceil((actorData.data.statistics.con.value + actorData.data.statistics.str.value) / 2);
|
||||
|
||||
// initialize sanity, don't set these afterwards, as they need to be manually edited
|
||||
if(actorData.data.sanity.value >= 100){
|
||||
actorData.data.sanity.value = actorData.data.statistics.pow.x5
|
||||
actorData.data.sanity.currentBreakingPoint = actorData.data.sanity.value - actorData.data.statistics.pow.value;
|
||||
};
|
||||
|
||||
actorData.data.sanity.max = 99 - actorData.data.skills.unnatural.proficiency;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Import Modules
|
||||
import { DeltaGreenActor } from "./actor/actor.js";
|
||||
import { DeltaGreenActorSheet } from "./actor/actor-sheet.js";
|
||||
import { DeltaGreenItem } from "./item/item.js";
|
||||
import { DeltaGreenItemSheet } from "./item/item-sheet.js";
|
||||
|
||||
Hooks.once('init', async function() {
|
||||
|
||||
game.deltagreen = {
|
||||
DeltaGreenActor,
|
||||
DeltaGreenItem,
|
||||
rollItemMacro
|
||||
};
|
||||
|
||||
/**
|
||||
* Set an initiative formula for the system
|
||||
* @type {String}
|
||||
*/
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "@statistics.dex",
|
||||
decimals: 0
|
||||
};
|
||||
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.entityClass = DeltaGreenActor;
|
||||
CONFIG.Item.entityClass = DeltaGreenItem;
|
||||
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("deltagreen", DeltaGreenActorSheet, { makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("deltagreen", DeltaGreenItemSheet, { makeDefault: true });
|
||||
|
||||
// If you need to add Handlebars helpers, here are a few useful examples:
|
||||
Handlebars.registerHelper('concat', function() {
|
||||
var outStr = '';
|
||||
for (var arg in arguments) {
|
||||
if (typeof arguments[arg] != 'object') {
|
||||
outStr += arguments[arg];
|
||||
}
|
||||
}
|
||||
return outStr;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('toLowerCase', function(str) {
|
||||
return str.toLowerCase();
|
||||
});
|
||||
});
|
||||
|
||||
Hooks.once("ready", async function() {
|
||||
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
|
||||
Hooks.on("hotbarDrop", (bar, data, slot) => createDeltaGreenMacro(data, slot));
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Hotbar Macros */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a Macro from an Item drop.
|
||||
* Get an existing item macro if one exists, otherwise create a new one.
|
||||
* @param {Object} data The dropped data
|
||||
* @param {number} slot The hotbar slot to use
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function createDeltaGreenMacro(data, slot) {
|
||||
if (data.type !== "Item") return;
|
||||
if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items");
|
||||
const item = data.data;
|
||||
|
||||
// Create the macro command
|
||||
const command = `game.deltagreen.rollItemMacro("${item.name}");`;
|
||||
let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command));
|
||||
if (!macro) {
|
||||
macro = await Macro.create({
|
||||
name: item.name,
|
||||
type: "script",
|
||||
img: item.img,
|
||||
command: command,
|
||||
flags: { "deltagreen.itemMacro": true }
|
||||
});
|
||||
}
|
||||
game.user.assignHotbarMacro(macro, slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Macro from an Item drop.
|
||||
* Get an existing item macro if one exists, otherwise create a new one.
|
||||
* @param {string} itemName
|
||||
* @return {Promise}
|
||||
*/
|
||||
function rollItemMacro(itemName) {
|
||||
const speaker = ChatMessage.getSpeaker();
|
||||
let actor;
|
||||
if (speaker.token) actor = game.actors.tokens[speaker.token];
|
||||
if (!actor) actor = game.actors.get(speaker.actor);
|
||||
const item = actor ? actor.items.find(i => i.name === itemName) : null;
|
||||
if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`);
|
||||
|
||||
// Trigger the item roll
|
||||
return item.roll();
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class DeltaGreenItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["deltagreen", "sheet", "item"],
|
||||
width: 520,
|
||||
height: 480,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
get template() {
|
||||
const path = "systems/deltagreen/templates/item";
|
||||
// Return a single sheet for all item types.
|
||||
// return `${path}/item-sheet.html`;
|
||||
|
||||
// Alternatively, you could use the following return statement to do a
|
||||
// unique item sheet by type, like `weapon-sheet.html`.
|
||||
return `${path}/item-${this.item.data.type}-sheet.html`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
getData() {
|
||||
const data = super.getData();
|
||||
return data;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - 192;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Roll handlers, click handlers, etc. would go here.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Extend the basic Item with some very simple modifications.
|
||||
* @extends {Item}
|
||||
*/
|
||||
export class DeltaGreenItem extends Item {
|
||||
/**
|
||||
* Augment the basic Item data model with additional dynamic data.
|
||||
*/
|
||||
prepareData() {
|
||||
super.prepareData();
|
||||
|
||||
// Get the Item's data
|
||||
const itemData = this.data;
|
||||
const actorData = this.actor ? this.actor.data : {};
|
||||
const data = itemData.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clickable rolls.
|
||||
* @param {Event} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
async roll() {
|
||||
// Basic template rendering data
|
||||
const token = this.actor.token;
|
||||
const item = this.data;
|
||||
const actorData = this.actor ? this.actor.data.data : {};
|
||||
const itemData = item.data;
|
||||
|
||||
let roll = new Roll('d20+@abilities.str.mod', actorData);
|
||||
let label = `Rolling ${item.name}`;
|
||||
roll.roll().toMessage({
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
flavor: label
|
||||
});
|
||||
}
|
||||
}
|
||||
Generated
+4277
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "deltagreen",
|
||||
"version": "1.0.0",
|
||||
"description": "CSS compiler for the DeltaGreen system",
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"compile": "gulp css",
|
||||
"watch": "gulp",
|
||||
"gulp": "gulp"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 3 versions"
|
||||
],
|
||||
"author": "John Doe",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-autoprefixer": "^7.0.1",
|
||||
"gulp-sass": "^4.1.0",
|
||||
"gulp-sourcemaps": "^2.6.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
.item-form {
|
||||
font-family: $font-primary;
|
||||
}
|
||||
|
||||
.sheet-header {
|
||||
flex: 0 0 210px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.profile-img {
|
||||
flex: 0 0 100px;
|
||||
height: 100px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
h1.charname {
|
||||
height: 50px;
|
||||
padding: 0px;
|
||||
margin: 5px 0;
|
||||
border-bottom: 0;
|
||||
input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sheet-tabs {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.sheet-body,
|
||||
.sheet-body .tab,
|
||||
.sheet-body .tab .editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tox {
|
||||
.tox-editor-container {
|
||||
background: $c-white;
|
||||
}
|
||||
|
||||
.tox-edit-area {
|
||||
padding: 0 8px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
.items-list {
|
||||
list-style: none;
|
||||
margin: 7px 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
|
||||
.item-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item {
|
||||
height: 30px;
|
||||
line-height: 24px;
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid #BBB;
|
||||
|
||||
.item-image {
|
||||
flex: 0 0 24px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.item-controls {
|
||||
flex: 0 0 86px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
.resource-label {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// .tabs {
|
||||
// .item {
|
||||
// background: rgba(0, 0, 0, 0.125);
|
||||
// border: 1px solid;
|
||||
// border-radius: 4px;
|
||||
// margin: 0 10px 0;
|
||||
// padding: 8px 4px;
|
||||
|
||||
// &:hover,
|
||||
// &:focus {
|
||||
// background: rgba(0, 0, 0, 0.125);
|
||||
// }
|
||||
|
||||
// &.active {
|
||||
// background: transparent;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
.tabs {
|
||||
height: 40px;
|
||||
border-top: 1px solid #AAA;
|
||||
border-bottom: 1px solid #AAA;
|
||||
|
||||
.item {
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item.active {
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Import utilities.
|
||||
@import 'utils/typography';
|
||||
@import 'utils/colors';
|
||||
@import 'utils/mixins';
|
||||
@import 'utils/variables';
|
||||
|
||||
/* Global styles */
|
||||
@import 'global/window';
|
||||
@import 'global/grid';
|
||||
@import 'global/flex';
|
||||
|
||||
/* Styles limited to deltagreen sheets */
|
||||
.deltagreen {
|
||||
@import 'components/forms';
|
||||
@import 'components/resource';
|
||||
@import 'components/tabs';
|
||||
@import 'components/items';
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.flex-center {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
.grid,
|
||||
.grid-2col {
|
||||
display: grid;
|
||||
grid-column: span 2 / span 2;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid-3col {
|
||||
grid-column: span 3 / span 3;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-4col {
|
||||
grid-column: span 4 / span 4;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-5col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-6col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-7col {
|
||||
grid-column: span 7 / span 7;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-8col {
|
||||
grid-column: span 8 / span 8;
|
||||
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-9col {
|
||||
grid-column: span 9 / span 9;
|
||||
grid-template-columns: repeat(9, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-10col {
|
||||
grid-column: span 10 / span 10;
|
||||
grid-template-columns: repeat(10, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-11col {
|
||||
grid-column: span 11 / span 11;
|
||||
grid-template-columns: repeat(11, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-12col {
|
||||
grid-column: span 12 / span 12;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-group-center,
|
||||
.flex-group-left,
|
||||
.flex-group-right {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
.flex-group-left {
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.flex-group-right {
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
.window-app {
|
||||
font-family: $font-primary;
|
||||
}
|
||||
|
||||
.rollable {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #000;
|
||||
text-shadow: 0 0 10px red;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
$c-white: #fff;
|
||||
$c-black: #000;
|
||||
@@ -0,0 +1,16 @@
|
||||
@mixin element-invisible {
|
||||
position: absolute;
|
||||
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
clip: rect(0 0 0 0);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@mixin hide {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap');
|
||||
|
||||
$font-primary: 'Roboto', sans-serif;
|
||||
$font-secondary: 'Roboto', sans-serif;
|
||||
@@ -0,0 +1,3 @@
|
||||
$padding-sm: 5px;
|
||||
$padding-md: 10px;
|
||||
$padding-lg: 20px;
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "deltagreen",
|
||||
"title": "Delta Green",
|
||||
"description": "Delta Green RPG system for FoundryVTT!",
|
||||
"version": "1.0.3",
|
||||
"minimumCoreVersion": "0.6.2",
|
||||
"compatibleCoreVersion": "0.6.2",
|
||||
"templateVersion": 2,
|
||||
"author": "Nick Eimers",
|
||||
"esmodules": ["module/deltagreen.js"],
|
||||
"styles": ["css/deltagreen.css"],
|
||||
"scripts": [],
|
||||
"packs": [],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en.json"
|
||||
}
|
||||
],
|
||||
"gridDistance": 5,
|
||||
"gridUnits": "ft",
|
||||
"primaryTokenAttribute": "health",
|
||||
"secondaryTokenAttribute": "wp",
|
||||
"url": "",
|
||||
"manifest": "",
|
||||
"download": "",
|
||||
"license": "LICENSE.txt"
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
{
|
||||
"Actor": {
|
||||
"types": [
|
||||
"agent",
|
||||
"npc"
|
||||
],
|
||||
"templates": {
|
||||
"base": {
|
||||
"health": {
|
||||
"value": 10,
|
||||
"min": 0,
|
||||
"max": 10
|
||||
},
|
||||
"wp": {
|
||||
"value": 10
|
||||
},
|
||||
"statistics": {
|
||||
"str": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
},
|
||||
"con": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
},
|
||||
"dex": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
},
|
||||
"int": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
},
|
||||
"pow": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
},
|
||||
"cha": {
|
||||
"value": 10,
|
||||
"distinguishing_feature": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"human_skills": {
|
||||
"skills": {
|
||||
"accounting": {
|
||||
"label": "Accounting",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"alertness": {
|
||||
"label": "Alertness",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"anthropology": {
|
||||
"label": "Anthropology",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"archeology": {
|
||||
"label": "Archeology",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"art": [
|
||||
{
|
||||
"specialization": "Painting/Dance/Sculpture/etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
],
|
||||
"artillery": {
|
||||
"label": "Artillery",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"athletics": {
|
||||
"label": "Artillery",
|
||||
"proficiency": 30,
|
||||
"failure": false
|
||||
},
|
||||
"bureaucracy": {
|
||||
"label": "Bureaucracy",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"computer_science": {
|
||||
"label": "Computer Science",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"craft": [
|
||||
{
|
||||
"specialization": "Carpentry/Electrical/Etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
],
|
||||
"criminology": {
|
||||
"label": "Criminology",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"demolitions": {
|
||||
"label": "Demolitions",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"disguise": {
|
||||
"label": "Disguise",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"dodge": {
|
||||
"label": "Dodge",
|
||||
"proficiency": 30,
|
||||
"failure": false
|
||||
},
|
||||
"drive": {
|
||||
"label": "Drive",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"firearms": {
|
||||
"label": "Firearms",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"first_aid": {
|
||||
"label": "First Aid",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"forensics": {
|
||||
"label": "Forensics",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"heavy_machiner": {
|
||||
"label": "Heavy Machinery",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"heavy_weapons": {
|
||||
"label": "Heavy Weapons",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"history": {
|
||||
"label": "History",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"humint": {
|
||||
"label": "HUMINT",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"law": {
|
||||
"label": "Law",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"medicine": {
|
||||
"label": "Medicine",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"melee_weapons": {
|
||||
"label": "Melee Weapons",
|
||||
"proficiency": 30,
|
||||
"failure": false
|
||||
},
|
||||
"military_science": {
|
||||
"label": "Military Science",
|
||||
"specializations": [
|
||||
{
|
||||
"label": "Land/Air/Sea/Etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"navigate": {
|
||||
"label": "Navigate",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"occult": {
|
||||
"label": "Occult",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"persuade": {
|
||||
"label": "Persuade",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"pilot": {
|
||||
"label": "Pilot",
|
||||
"specializations": [
|
||||
{
|
||||
"label": "Airplane/Small Boat/Helicopter/Etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"psychotherapy": {
|
||||
"label": "Psychotherapy",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"ride": {
|
||||
"label": "Ride",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"science": {
|
||||
"label": "Science",
|
||||
"specializations": [
|
||||
{
|
||||
"label": "Biology/Chemistry/Physics/Etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"search": {
|
||||
"label": "Search",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"sigint": {
|
||||
"label": "SIGINT",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
},
|
||||
"stealth": {
|
||||
"label": "Stealth",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"survival": {
|
||||
"label": "Survival",
|
||||
"proficiency": 10,
|
||||
"failure": false
|
||||
},
|
||||
"swim": {
|
||||
"label": "Swim",
|
||||
"proficiency": 20,
|
||||
"failure": false
|
||||
},
|
||||
"unarmed_combat": {
|
||||
"label": "Unarmed Combat",
|
||||
"proficiency": 40,
|
||||
"failure": false
|
||||
},
|
||||
"unnatural": {
|
||||
"label": "Unnatural",
|
||||
"proficiency": 0
|
||||
},
|
||||
"foreign_languages": {
|
||||
"label": "Foreign Languages",
|
||||
"specializations": [
|
||||
{
|
||||
"label": "Spanish/Yiddish/Etc.",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"other_skills": {
|
||||
"label": "Other Skills and Training",
|
||||
"specializations": [
|
||||
{
|
||||
"label": "",
|
||||
"proficiency": 0,
|
||||
"failure": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"agent": {
|
||||
"templates": [
|
||||
"base",
|
||||
"human_skills"
|
||||
],
|
||||
"sanity": {
|
||||
"value": 100,
|
||||
"currentBreakingPoint": 101,
|
||||
"adaptations": {
|
||||
"violence": 0,
|
||||
"helplessness": 0
|
||||
}
|
||||
},
|
||||
"physicalDescription": "",
|
||||
"biography": {
|
||||
"profession": "",
|
||||
"employer": "",
|
||||
"nationality": "",
|
||||
"sex": "",
|
||||
"age": "",
|
||||
"education": ""
|
||||
},
|
||||
"motivations":[
|
||||
{
|
||||
"description":"",
|
||||
"disorder":""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Item": {
|
||||
"types": [
|
||||
"weapon",
|
||||
"equipment",
|
||||
"ability",
|
||||
"ritual"
|
||||
],
|
||||
"templates": {
|
||||
"base": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"weapon": {
|
||||
"templates": [
|
||||
"base"
|
||||
]
|
||||
},
|
||||
"equipment": {
|
||||
"templates": [
|
||||
"base"
|
||||
]
|
||||
},
|
||||
"ability": {
|
||||
"templates": [
|
||||
"base"
|
||||
]
|
||||
},
|
||||
"ritual": {
|
||||
"templates": [
|
||||
"base"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<form class="{{cssClass}} flexcol" autocomplete="off">
|
||||
|
||||
{{!-- Sheet Header --}}
|
||||
<header class="sheet-header">
|
||||
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="150" width="100"/>
|
||||
<div class="header-fields">
|
||||
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name"/></h1>
|
||||
{{!-- The grid classes are defined in scss/global/_grid.scss. To use,
|
||||
use both the "grid" and "grid-Ncol" class where "N" can be any number
|
||||
from 1 to 12 and will create that number of columns. --}}
|
||||
<div class="resources grid grid-2col">
|
||||
{{!-- "flex-group-center" is also defined in the _grid.scss file
|
||||
and it will add a small amount of padding, a border, and will
|
||||
center all of its child elements content and text. --}}
|
||||
<div class="resource flex-group-center">
|
||||
<label for="data.health.value" class="resource-label">Health</label>
|
||||
<div class="resource-content flexrow flex-center flex-between">
|
||||
<input type="text" name="data.health.value" value="{{data.health.value}}" data-dtype="Number"/>
|
||||
<span> / </span>
|
||||
<span title="Maximum health is the average of STR + CON, rounded UP." class="max-attribute-value-label">{{numberFormat data.health.max decimals=0 sign=false}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource flex-group-center">
|
||||
<label for="data.wp.value" class="resource-label">WP</label>
|
||||
<div class="resource-content flexrow flex-center flex-between">
|
||||
<input type="text" name="data.wp.value" value="{{data.wp.value}}" data-dtype="Number"/>
|
||||
<span> / </span>
|
||||
<span class="max-attribute-value-label">{{numberFormat data.wp.max decimals=0 sign=false}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resources">
|
||||
{{!-- "flex-group-center" is also defined in the _grid.scss file
|
||||
and it will add a small amount of padding, a border, and will
|
||||
center all of its child elements content and text. --}}
|
||||
<div class="resource flex-group-center">
|
||||
<label for="data.sanity.value" class="resource-label">SANITY</label>
|
||||
<div class="resource-content flexrow flex-center flex-between">
|
||||
<input title="Starting sanity is equal to POW x 5." type="text" name="data.sanity.value" value="{{data.sanity.value}}" data-dtype="Number"/>
|
||||
<span> / </span>
|
||||
<span title="Maximum sanity is equal to 99 - the Unnatural skill." class="max-attribute-value-label">{{numberFormat data.sanity.max decimals=0 sign=false}}</span>
|
||||
<!-- <span class="statistic-mod rollable left-aligned-label" data-roll="d100" data-target="sanity" data-label="SAN">(SAN Test)</span> -->
|
||||
<button class="btn-tiny rollable" data-roll="d100" data-target="sanity" data-label="SAN">TEST</button>
|
||||
<span> </span>
|
||||
<span class="breaking-point-label"> Breaking Point: </span>
|
||||
<!-- <span title="The current breaking point, resent when current sanity falls to or below this value." class="max-attribute-value-label">{{numberFormat data.sanity.currentBreakingPoint decimals=0 sign=false}}</span> -->
|
||||
<input title="The current breaking point, resent when current sanity falls to or below this value." type="text" name="data.sanity.currentBreakingPoint" value="{{data.sanity.currentBreakingPoint}}" data-dtype="Number"/>
|
||||
<button id="btnResetBreakingPoint" class="btn-tiny" title="Reset breaking point to be SAN - WP.">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{!-- The grid classes are defined in scss/global/_grid.scss. To use,
|
||||
use both the "grid" and "grid-Ncol" class where "N" can be any number
|
||||
from 1 to 12 and will create that number of columns. --}}
|
||||
<div class="statistics grid grid-3col">
|
||||
{{#each data.statistics as |statistic key|}}
|
||||
<div class="statistic flexrow flex-group-center">
|
||||
<label for="data.statistics.{{key}}.value" class="resource-label">{{key}}</label>
|
||||
<input type="text" name="data.statistics.{{key}}.value" value="{{statistic.value}}" data-dtype="Number"/>
|
||||
<span class="statistic-mod rollable" data-roll="d100" data-target="statistic.x5" data-label="{{key}}">{{numberFormat statistic.x5 decimals=0 sign=false}}</span>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="skills">Skills</a>
|
||||
<a class="item" data-tab="gear">gear</a>
|
||||
<a class="item" data-tab="physical-description">Description</a>
|
||||
<a class="item" data-tab="bonds">Bonds</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Biography Tab --}}
|
||||
<div class="tab biography" data-group="primary" data-tab="physical-description">
|
||||
{{editor content=data.physicalDescription target="data.physicalDescription" button=true owner=owner editable=editable}}
|
||||
</div>
|
||||
|
||||
{{!-- Owned Items Tab --}}
|
||||
<div class="tab items" data-group="primary" data-tab="items">
|
||||
<ol class="items-list">
|
||||
<li class="item flexrow item-header">
|
||||
<div class="item-image"></div>
|
||||
<div class="item-name">Name</div>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-create" title="Create item" data-type="item"><i class="fas fa-plus"></i> Add item</a>
|
||||
</div>
|
||||
</li>
|
||||
{{#each actor.gear as |item id|}}
|
||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||
<div class="item-image"><img src="{{item.img}}" title="{{item.name}}" width="24" height="24"/></div>
|
||||
<h4 class="item-name">{{item.name}}</h4>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{{!-- Owned Features Tab --}}
|
||||
<div class="tab features" data-group="primary" data-tab="features">
|
||||
<ol class="items-list">
|
||||
<li class="item flexrow item-header">
|
||||
<div class="item-image"></div>
|
||||
<div class="item-name">Name</div>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-create" title="Create item" data-type="feature"><i class="fas fa-plus"></i> Add item</a>
|
||||
</div>
|
||||
</li>
|
||||
{{#each actor.features as |item id|}}
|
||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||
<div class="item-image"><img src="{{item.img}}" title="{{item.name}}" width="24" height="24"/></div>
|
||||
<h4 class="item-name">{{item.name}}</h4>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{{!-- Owned Spells Tab --}}
|
||||
<div class="tab spells" data-group="primary" data-tab="spells">
|
||||
<ol class="items-list">
|
||||
<li class="item flexrow item-header">
|
||||
<div class="item-image"></div>
|
||||
<div class="item-name">Name</div>
|
||||
<div class="item-controls"></div>
|
||||
</li>
|
||||
{{#each actor.spells as |spells spellLevel|}}
|
||||
<li class="item flexrow item-header">
|
||||
<div class="item-name">Level {{spellLevel}} Spells</div>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-create" title="Create item" data-type="spell" data-spell-level="{{spellLevel}}"><i class="fas fa-plus"></i> Add LVL {{spellLevel}}</a>
|
||||
</div>
|
||||
</li>
|
||||
{{#each spells as |item id|}}
|
||||
<li class="item flexrow" data-item-id="{{item._id}}">
|
||||
<div class="item-image"><img src="{{item.img}}" title="{{item.name}}" width="24" height="24"/></div>
|
||||
<h4 class="item-name">{{item.name}}</h4>
|
||||
<div class="item-controls">
|
||||
<a class="item-control item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<form class="{{cssClass}}" autocomplete="off">
|
||||
<header class="sheet-header">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}"/>
|
||||
<div class="header-fields">
|
||||
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name"/></h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="description">Description</a>
|
||||
<a class="item" data-tab="attributes">Attributes</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Description Tab --}}
|
||||
<div class="tab" data-group="primary" data-tab="description">
|
||||
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
||||
</div>
|
||||
|
||||
{{!-- Attributes Tab --}}
|
||||
<div class="tab attributes" data-group="primary" data-tab="attributes">
|
||||
{{!-- As you add new fields, add them in here! --}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
@@ -0,0 +1,38 @@
|
||||
<form class="{{cssClass}}" autocomplete="off">
|
||||
<header class="sheet-header">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}"/>
|
||||
<div class="header-fields">
|
||||
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name"/></h1>
|
||||
<div class="grid grid-2col">
|
||||
<div class="resource">
|
||||
<label class="resource-label">Quantity</label>
|
||||
<input type="text" name="data.quantity" value="{{data.quantity}}" data-dtype="Number"/>
|
||||
</div>
|
||||
<div class="resource">
|
||||
<label class="resource-label">Weight</label>
|
||||
<input type="text" name="data.weight" value="{{data.weight}}" data-dtype="Number"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="description">Description</a>
|
||||
<a class="item" data-tab="attributes">Attributes</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Description Tab --}}
|
||||
<div class="tab" data-group="primary" data-tab="description">
|
||||
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
||||
</div>
|
||||
|
||||
{{!-- Attributes Tab --}}
|
||||
<div class="tab attributes" data-group="primary" data-tab="attributes">
|
||||
{{!-- As you add new fields, add them in here! --}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
@@ -0,0 +1,28 @@
|
||||
<form class="{{cssClass}}" autocomplete="off">
|
||||
<header class="sheet-header">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}"/>
|
||||
<div class="header-fields">
|
||||
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name"/></h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="description">Description</a>
|
||||
<a class="item" data-tab="attributes">Attributes</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Description Tab --}}
|
||||
<div class="tab" data-group="primary" data-tab="description">
|
||||
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
||||
</div>
|
||||
|
||||
{{!-- Attributes Tab --}}
|
||||
<div class="tab attributes" data-group="primary" data-tab="attributes">
|
||||
{{!-- As you add new fields, add them in here! --}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
@@ -0,0 +1,32 @@
|
||||
<form class="{{cssClass}}" autocomplete="off">
|
||||
<header class="sheet-header">
|
||||
<img class="profile-img" src="{{item.img}}" data-edit="img" title="{{item.name}}"/>
|
||||
<div class="header-fields">
|
||||
<h1 class="charname"><input name="name" type="text" value="{{item.name}}" placeholder="Name"/></h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="description">Description</a>
|
||||
<a class="item" data-tab="attributes">Attributes</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
|
||||
{{!-- Description Tab --}}
|
||||
<div class="tab" data-group="primary" data-tab="description">
|
||||
{{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
|
||||
</div>
|
||||
|
||||
{{!-- Attributes Tab --}}
|
||||
<div class="tab attributes" data-group="primary" data-tab="attributes">
|
||||
{{!-- As you add new fields, add them in here! --}}
|
||||
<div class="resource">
|
||||
<label class="resource-label">Spell Level</label>
|
||||
<input type="text" name="data.spellLevel" value="{{data.spellLevel}}" data-dtype="Number"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
Reference in New Issue
Block a user