switch to using TypeScript
This commit is contained in:
parent
1d120b273a
commit
d163fd27fe
53 changed files with 2875 additions and 1614 deletions
110
src/module/actor/actor-sheet.ts
Normal file
110
src/module/actor/actor-sheet.ts
Normal file
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class DS4ActorSheet extends ActorSheet<{
|
||||
/* TODO: add actual type for data */
|
||||
}> {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor"],
|
||||
template: "systems/ds4/templates/actor/actor-sheet.html",
|
||||
width: 600,
|
||||
height: 600,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
getData() {
|
||||
// TODO: replace ["..."] access with .
|
||||
const data = super.getData();
|
||||
data["dtypes"] = ["String", "Number", "Boolean"];
|
||||
const innerData = data.data;
|
||||
for (let attr of Object.values(data.data["attributes"])) {
|
||||
attr["isCheckbox"] = attr["dtype"] === "Boolean";
|
||||
}
|
||||
console.log(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/** @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));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* 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 label = dataset.label ? `Rolling ${dataset.label}` : "";
|
||||
roll.roll().toMessage({
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
flavor: label,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
38
src/module/actor/actor.ts
Normal file
38
src/module/actor/actor.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
|
||||
* @extends {Actor}
|
||||
*/
|
||||
export class DS4Actor extends Actor {
|
||||
/** @override */
|
||||
prepareDerivedData() {
|
||||
const data = this.data;
|
||||
this._prepareCombatValues(data);
|
||||
}
|
||||
|
||||
_prepareCombatValues(data) {
|
||||
const hitPointsModifier = getProperty(data, "data.combatValues.hitPoints.modifier") || 0;
|
||||
setProperty(
|
||||
data,
|
||||
"data.combatValues.hitPoints.max",
|
||||
data.data.attributes.body.initial + data.data.traits.constitution.initial + 10 + hitPointsModifier
|
||||
);
|
||||
|
||||
const defenseModifier = getProperty(data, "data.combatValues.defense.modifier") || 0;
|
||||
setProperty(
|
||||
data,
|
||||
"data.combatValues.defense.value",
|
||||
data.data.attributes.body.initial +
|
||||
data.data.traits.constitution.initial +
|
||||
this._getArmorValue() +
|
||||
defenseModifier
|
||||
);
|
||||
}
|
||||
|
||||
_getArmorValue() {
|
||||
return this.data["items"]
|
||||
.filter((item) => ["armor", "shield"].includes(item.type))
|
||||
.filter((item) => item.data.equipped)
|
||||
.map((item) => item.data.armorValue)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
}
|
68
src/module/config.ts
Normal file
68
src/module/config.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
export const DS4 = {
|
||||
// ASCII Artwork
|
||||
ASCII: `_____________________________________________________________________________________________
|
||||
____ _ _ _ _ ____ _____ ___ _ _ ____ _ _ __ _______ ____ ____ _ _
|
||||
| _ \\| | | | \\ | |/ ___| ____/ _ \\| \\ | / ___|| | / \\\\ \\ / / ____| _ \\/ ___| | || |
|
||||
| | | | | | | \\| | | _| _|| | | | \\| \\___ \\| | / _ \\\\ V /| _| | |_) \\___ \\ | || |_
|
||||
| |_| | |_| | |\\ | |_| | |__| |_| | |\\ |___) | |___ / ___ \\| | | |___| _ < ___) | |__ _|
|
||||
|____/ \\___/|_| \\_|\\____|_____\\___/|_| \\_|____/|_____/_/ \\_\\_| |_____|_| \\_\\____/ |_|
|
||||
=============================================================================================`,
|
||||
|
||||
/**
|
||||
* Define the set of acttack types that can be performed with weapon items
|
||||
* @type {Object}
|
||||
*/
|
||||
attackTypes: {
|
||||
melee: "DS4.AttackTypeMelee",
|
||||
ranged: "DS4.AttackTypeRanged",
|
||||
meleeRanged: "DS4.AttackTypeMeleeRanged",
|
||||
},
|
||||
|
||||
/**
|
||||
* Define the set of item availabilties
|
||||
* @type {Object}
|
||||
*/
|
||||
itemAvailabilities: {
|
||||
hamlet: "DS4.ItemAvailabilityHamlet",
|
||||
village: "DS4.ItemAvailabilityVilage",
|
||||
city: "DS4.ItemAvailabilityCity",
|
||||
elves: "DS4.ItemAvailabilityElves",
|
||||
dwarves: "DS4.ItemAvailabilityDwarves",
|
||||
none: "DS4.ItemAvailabilityNone",
|
||||
},
|
||||
|
||||
/**
|
||||
* * Define the set of item types
|
||||
* @type {Object}
|
||||
*/
|
||||
itemTypes: {
|
||||
weapon: "DS4.ItemTypeWeapon",
|
||||
armor: "DS4.ItemTypeArmor",
|
||||
shield: "DS4.ItemTypeShield",
|
||||
trinket: "DS4.ItemTypeTrinket",
|
||||
equipment: "DS4.ItemTypeEquipment",
|
||||
},
|
||||
|
||||
/**
|
||||
* * Define the set of armor types, a character may only wear one item of each at any given time
|
||||
* @type {Object}
|
||||
*/
|
||||
armorTypes: {
|
||||
body: "DS4.ArmorTypeBody",
|
||||
helment: "DS4.ArmorTypeHelmet",
|
||||
vambrace: "DS4.ArmorTypeVambrace",
|
||||
greaves: "DS4.ArmorTypeGreaves",
|
||||
vambraceGreaves: "DS4.ArmorTypeVambraceGreaves",
|
||||
},
|
||||
|
||||
/**
|
||||
* * Define the set of armor materials, used to determine if a characer may wear the armor without additional penalties
|
||||
* @type {Object}
|
||||
*/
|
||||
armorMaterialTypes: {
|
||||
cloth: "DS4.ArmorMaterialTypeCloth",
|
||||
leather: "DS4.ArmorMaterialTypeLeather",
|
||||
chain: "DS4.ArmorMaterialTypeChain",
|
||||
plate: "DS4.ArmorMaterialTypePlate",
|
||||
},
|
||||
};
|
63
src/module/ds4.ts
Normal file
63
src/module/ds4.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Import Modules
|
||||
import { DS4Actor } from "./actor/actor.js";
|
||||
import { DS4ActorSheet } from "./actor/actor-sheet.js";
|
||||
import { DS4Item } from "./item/item.js";
|
||||
import { DS4ItemSheet } from "./item/item-sheet.js";
|
||||
import { DS4 } from "./config.js";
|
||||
|
||||
Hooks.once("init", async function () {
|
||||
console.log(`DS4 | Initializing the DS4 Game System\n${DS4.ASCII}`);
|
||||
|
||||
game.ds4 = {
|
||||
DS4Actor,
|
||||
DS4Item,
|
||||
DS4,
|
||||
};
|
||||
|
||||
// Record configuration
|
||||
CONFIG.DS4 = DS4;
|
||||
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.entityClass = DS4Actor;
|
||||
CONFIG.Item.entityClass = DS4Item;
|
||||
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("ds4", DS4ActorSheet, { makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("ds4", DS4ItemSheet, { makeDefault: true });
|
||||
|
||||
registerHandlebarsPartials();
|
||||
});
|
||||
|
||||
async function registerHandlebarsPartials() {
|
||||
const templatePaths = ["systems/ds4/templates/item/partials/description.hbs"];
|
||||
return loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Setup */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This function runs after game data has been requested and loaded from the servers, so entities exist
|
||||
*/
|
||||
Hooks.once("setup", function () {
|
||||
// Localize CONFIG objects once up-front
|
||||
const toLocalize = ["attackTypes", "itemAvailabilities", "itemTypes", "armorTypes", "armorMaterialTypes"];
|
||||
|
||||
// Exclude some from sorting where the default order matters
|
||||
const noSort = [];
|
||||
|
||||
// Localize and sort CONFIG objects
|
||||
for (let o of toLocalize) {
|
||||
const localized = Object.entries(CONFIG.DS4[o]).map((e) => {
|
||||
return [e[0], game.i18n.localize(e[1] as string)];
|
||||
});
|
||||
if (!noSort.includes(o)) localized.sort((a, b) => a[1].localeCompare(b[1]));
|
||||
CONFIG.DS4[o] = localized.reduce((obj, e) => {
|
||||
obj[e[0]] = e[1];
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
});
|
85
src/module/item/item-sheet.ts
Normal file
85
src/module/item/item-sheet.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class DS4ItemSheet extends ItemSheet {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
width: 530,
|
||||
height: 400,
|
||||
classes: ["ds4", "sheet", "item"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
get template() {
|
||||
const path = "systems/ds4/templates/item";
|
||||
return `${path}/${this.item.data.type}-sheet.hbs`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
getData() {
|
||||
const data = { ...super.getData(), config: CONFIG.DS4 };
|
||||
console.log(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = (this.element as JQuery).find(".sheet-body"); // TODO: Why is the cast necessary?
|
||||
const bodyHeight = position.height - 192;
|
||||
//sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
if (!this.options.editable) return;
|
||||
|
||||
html.find(".effect-create").click(this._onEffectCreate.bind(this));
|
||||
|
||||
html.find(".effect-edit").click((ev) => {
|
||||
const li = $(ev.currentTarget).parents(".effect");
|
||||
console.log(li.data("effectId"));
|
||||
const effect = this.item.effects.get(li.data("effectId"));
|
||||
effect.sheet.render(true);
|
||||
});
|
||||
|
||||
html.find(".effect-delete").click(async (ev) => {
|
||||
const li = $(ev.currentTarget).parents(".effect");
|
||||
await this.item.deleteEmbeddedEntity("ActiveEffect", li.data("effectId"));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creating a new ActiveEffect for the item using initial data defined in the HTML dataset
|
||||
* @param {Event} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
async _onEffectCreate(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const label = `New Effect`;
|
||||
|
||||
const createData = {
|
||||
label: label,
|
||||
changes: [],
|
||||
duration: {},
|
||||
transfer: true,
|
||||
};
|
||||
|
||||
const effect = await ActiveEffect.create(createData, this.item);
|
||||
return effect.create({});
|
||||
}
|
||||
}
|
17
src/module/item/item.ts
Normal file
17
src/module/item/item.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Extend the basic Item with some very simple modifications.
|
||||
* @extends {Item}
|
||||
*/
|
||||
export class DS4Item 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue