Files
DeltaGreen/module/deltagreen.js
T

548 lines
14 KiB
JavaScript

// 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";
import { sendPercentileTestToChat, sendLethalityTestToChat, sendDamageRollToChat } from "./roll/roll.js";
import { registerSystemSettings } from "./settings.js"
import { preloadHandlebarsTemplates } from "./templates.js";
import { ParseDeltaGreenStatBlock } from "./other/stat-parser-macro.js";
import { localizeWithFallback } from "./other/utility-functions.js";
Hooks.once('init', async function() {
game.deltagreen = {
DeltaGreenActor,
DeltaGreenItem,
rollItemMacro,
rollItemSkillCheckMacro,
rollSkillMacro,
ParseDeltaGreenStatBlock
};
/**
* Set an initiative formula for the system
* @type {String}
*/
CONFIG.Combat.initiative = {
formula: "@statistics.dex.value",
decimals: 0
};
// Register System Settings
registerSystemSettings();
// Define custom Entity classes
CONFIG.Actor.documentClass = DeltaGreenActor;
CONFIG.Item.documentClass = DeltaGreenItem;
// Register sheet application classes
Actors.unregisterSheet("core", ActorSheet);
Items.unregisterSheet("core", ItemSheet);
Actors.registerSheet("deltagreen", DeltaGreenActorSheet, { makeDefault: true });
Items.registerSheet("deltagreen", DeltaGreenItemSheet, { makeDefault: true });
// Preload Handlebars Templates
preloadHandlebarsTemplates();
// Add Handlebars helpers
Handlebars.registerHelper('localizeWithFallback', function(value, fallbackValue) {
return localizeWithFallback(value, fallbackValue);
});
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) {
try {
return str.toLowerCase();
} catch (error) {
return "";
}
});
Handlebars.registerHelper('toUpperCase', function(str) {
try {
return str.toUpperCase();
} catch (error) {
return "";
}
});
Handlebars.registerHelper('if_eq', function(a, b, opts) {
if (a == b) {
return opts.fn(this);
} else {
return opts.inverse(this);
}
});
Handlebars.registerHelper('if_not_eq', function(a, b, opts) {
if (a != b) { return opts.fn(this); }
return opts.inverse(this);
});
Handlebars.registerHelper('if_gt', function(a, b, trueVal, falseVal) {
if (a > b) {
return trueVal;
} else {
return falseVal;
}
});
Handlebars.registerHelper('cite_ahb', function(page) {
return "See page " + str(page) + " of the Agent's Handbook.";
});
Handlebars.registerHelper('formatLethality', function(lethality) {
if (lethality > 0) {
return lethality.toString() + "%";
}
else {
return "";
}
});
// Is this used anywhere?
Handlebars.registerHelper('getActorSkillProp', function(actorData, skillName, prop) {
try{
if(skillName != "" && prop != ""){
let skills = actorData.data.skills;
let skill = skills[skillName];
let propVal = skill[prop];
return propVal;
}
else{
return "";
}
}
catch(ex){
console.log(ex);
return "";
}
});
Handlebars.registerHelper('getAvailableRollModes', function() {
try {
return CONFIG.Dice.rollModes;
} catch (error) {
console.log(error);
}
});
Handlebars.registerHelper('getDefaultRollMode', function() {
try {
return game.settings.get("core", "rollMode");
} catch (error) {
console.log(error);
}
});
Handlebars.registerHelper('calculateHandToHandCombatDamageFormulaBonus', function(strength) {
try {
let bonus = "";
if(strength.value < 5){
bonus = " - 2";
}
else if(strength.value < 9){
bonus = " - 1";
}
else if(strength.value > 12 && strength < 17){
bonus = " + 1";
}
else if(strength.value > 16){
bonus = " + 2";
}
return bonus;
} catch (error) {
console.log(error);
}
});
Handlebars.registerHelper('localizeWeaponSkill', function(skill) {
let label = skill;
try {
if(skill === 'dex'){
label = game.i18n.localize("DG.Attributes.dex");
}
else{
label = game.i18n.localize("DG.Skills." + skill);
}
} catch (error) {
console.log(error);
}
return label;
});
Handlebars.registerHelper('hideSkillBasedOnProficiencyAndUserChoice', function(hideUntrainedSkills, proficiency) {
let showValue = true;
try {
if(hideUntrainedSkills === false){
showValue = true;
}
else{
if(proficiency > 0){
showValue = true;
}
else{
showValue = false;
}
}
} catch (error) {
console.log(error);
}
return showValue;
});
// looks at system setting for what font to use and returns the class that is then used in the handlebars template that
// generates the character sheet.
Handlebars.registerHelper('getFontFamilySystemSettingClass', function() {
let setting = game.settings.get("deltagreen", "characterSheetFont");
let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle");
/*
if(setting === "TypeWriterCondensed"){
return "typewriter-condensed-font";
}
else if(setting === "Martel"){
return "martel-font";
}
else if(setting === "Signika"){
return "signika-font";
}
else if(setting === "atwriter"){
return "atwriter-font";
}
else if(setting === "SpecialElite"){
return "special-elite-font";
}
else if(setting === "PublicSans"){
return "public-sans-font";
}
else{
return "martel-font";
}
*/
/*
if(characterSheetStyle === "cowboy"){
return "special-elite-font";
}
else{
return "public-sans-font";
}
*/
});
Handlebars.registerHelper('getCharacterSheetStyle', function() {
let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle");
if(characterSheetStyle === "cowboy"){
return "cowboy-style";
}
else if(characterSheetStyle === "outlaw"){
return "outlaw-style";
}
else{
return "program-style";
}
});
Handlebars.registerHelper('keepSanityPrivate', function() {
let setting = false;
try{
setting = game.settings.get("deltagreen", "keepSanityPrivate");
if(game.user.isGM){
setting = false;
}
}
catch(ex){
setting = false;
}
return setting;
});
});
Handlebars.registerHelper('playerHasGamemasterPrivileges', function(){
return game.user.isGM;
});
Handlebars.registerHelper('showImpossibleLandscapesContent', function() {
let result = false;
let setting = game.settings.get("deltagreen", "showImpossibleLandscapesContent");
if(game.user.isGM === true && setting === true){
result = true;
}
return result
});
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));
});
Hooks.on("ready", ()=> {
//let backgroundImageSetting = game.settings.get("deltagreen", "characterSheetBackgroundImageSetting");
//let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle");
//let customCss = "";
//let customStyle = document.createElement("style");
//customStyle.id = "dg-custom-css";
/*
if(backgroundImageSetting === "OldPaper1"){
customCss += `div.deltagreen.sheet.actor section.window-content{
background: url("systems/deltagreen/assets/img/old_paper.jpg") !important;
}`;
}
else if(backgroundImageSetting === "IvoryPaper"){
customCss += `div.deltagreen.sheet.actor section.window-content{
background-size: 100% !important;
}`;
}
*/
/*
if(characterSheetStyle === "cowboy"){
customCss += `div.deltagreen.sheet.actor section.window-content{
background: url("systems/deltagreen/assets/img/old_paper.jpg") !important;
}`;
}
else if(characterSheetStyle === "program"){
customCss += `div.deltagreen.sheet.actor section.window-content{
background: url("systems/deltagreen/assets/img/CrumpledPlainPaper10.webp") !important;
}`;
}
customStyle.innerHTML = customCss;
if(customCss != ""){
//document.querySelector("head").appendChild(customStyle);
}
*/
});
Hooks.on("preCreateItem", (item) => {
console.log("preCreateItem");
console.log(item.img);
console.log(item.type);
if(item.img === 'icons/svg/item-bag.svg'){
if(item.type === 'bond'){
item.updateSource({ img: 'systems/deltagreen/assets/icons/person-black-bg.svg'});
}
else{
item.updateSource({ img: 'systems/deltagreen/assets/icons/swap-bag-black-bg.svg'});
}
}
});
Hooks.on("renderSidebarTab", async (app, html) => {
if (app.options.id == "actors") {
let button = $("<button class='import-cd'><i class='fas fa-file-import'></i> Parse Stat Block</button>")
button.click(function () {
ParseDeltaGreenStatBlock()
});
html.find(".directory-footer").append(button);
}
})
// Note - this event is fired on ALL connected clients...
Hooks.on('createActor', async function(actor, options, userId){
try{
// use this to trap on if this hook is firing for the same user that triggered the create
// can put logic specific to a particular user session below
if (userId != game.user.id) { return; };
if(actor != null){
if(actor.type === 'agent'){
// update the default type skill of Art - Painting's labels to try to be localized
// since I really backed myself into a corner on this with my implementation of it...
console.log('createActor Hook');
let artLabel = game.i18n.translations.DG?.TypeSkills?.Art ?? "Art";
let paintingLabel = game.i18n.translations.DG?.TypeSkills?.Subskills?.Painting ?? "Painting";
let updatedData = duplicate(actor.system);
updatedData.typedSkills.tskill_01.group = artLabel;
updatedData.typedSkills.tskill_01.label = paintingLabel;
actor.update({"data": updatedData});
// throw on an unarmed strike item for convenience
actor.AddUnarmedAttackItemIfMissing();
}
else if(actor.type === 'unnatural'){
}
else if(actor.type === 'vehicle'){
actor.AddBaseVehicleItemsIfMissing();
}
}
}
catch(ex){
console.log(ex);
}
});
/* -------------------------------------------- */
/* 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" && data.itemData.type !== "weapon") return;
//if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items");
const item = data.itemData.system;
// Create the macro command
let command = '// Uncomment line below to also roll skill check if desired.'
command += '\n' + `//game.deltagreen.rollItemSkillCheckMacro("${data._id}");`;
command += '\n' + `game.deltagreen.rollItemMacro("${data._id}");`;
//let macro = game.macros.entities.find(m => (m.name === data.name) && (m.command === command));
//if (!macro) {
let macro = await Macro.create({
name: data.itemData.name,
type: "script",
img: data.itemData.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}
*/
async function rollItemMacro(itemId) {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
if (!actor) actor = game.actors.get(speaker.actor);
if(!actor) return ui.notifications.warn('Must have an Actor selected first.');
let item = actor ? actor.items.find(i => i._id === itemId) : null;
// for backwards compatibility with older macros, where I unwisely set it to use name instead of id
if(!item){
item = actor ? actor.items.find(i => i.name === itemId) : null;
}
if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemId}`);
// Trigger the item roll
let r = await item.roll();
return r;
}
function rollItemSkillCheckMacro(itemId) {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
if (!actor) actor = game.actors.get(speaker.actor);
if(!actor) return ui.notifications.warn('Must have an Actor selected first.');
let item = actor ? actor.items.find(i => i._id === itemId) : null;
// for backwards compatibility with older macros, where I unwisely set it to use name instead of id
if(!item){
item = actor ? actor.items.find(i => i.name === itemId) : null;
}
if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item '${itemName}'`);
let skillName = item.system.skill.toString();
let skill = actor.system.skills[skillName];
let translatedSkillLabel = "";
try{
translatedSkillLabel = game.i18n.localize("DG.Skills." + skillName)
}
catch{
translatedSkillLabel = skillName;
}
sendPercentileTestToChat(actor, translatedSkillLabel, skill.proficiency);
}
function rollSkillMacro(skillName) {
const speaker = ChatMessage.getSpeaker();
let actor;
if (speaker.token) actor = game.actors.tokens[speaker.token];
if (!actor) actor = game.actors.get(speaker.actor);
if(!actor) return ui.notifications.warn('Must have an Actor selected first.');
let skill = actor.system.skills[skillName];
if(!skill) return ui.notifications.warn('Bad skill name passed to macro.');
let translatedSkillLabel = "";
try{
translatedSkillLabel = game.i18n.localize("DG.Skills." + skillName)
}
catch{
translatedSkillLabel = skillName;
}
sendPercentileTestToChat(actor, translatedSkillLabel, skill.proficiency);
}