Calm fixes & netHP

This commit is contained in:
Chris Schmalz
2025-08-29 17:46:05 -07:00
parent 0c85d926cf
commit f3dac766ab
4 changed files with 211 additions and 190 deletions
+151 -70
View File
@@ -6,51 +6,79 @@ import { fromIdUuid } from "../mosh.js";
*/
export class MothershipActor extends Actor {
//Augment the basic actor data with additional dynamic data.
prepareData() {
//console.log(game.release.generation);
super.prepareData();
// augment the basic actor data with additional dynamic data
prepareDerivedData() {
const actorData = this;
const data = actorData.system;
const flags = actorData.flags;
// Make separate methods for each Actor type (character, npc, etc.) to keep
// things organized.
if (actorData.type === 'character') this._prepareCharacterData(actorData);
else if (actorData.type === 'creature') this._prepareCreatureData(actorData);
else if (actorData.type === 'ship') this._prepareShipData(actorData);
super.prepareDerivedData();
const system = this.system;
// ----- per-type derived -----
if (this.type === "character") this._deriveCharacter();
else if (this.type === "creature") this._deriveCreature();
else if (this.type === "ship") this._deriveShip();
}
//Prepare Character type specific data
_prepareCharacterData(actorData) {
const data = actorData.system;
let armorPoints = 0;
let damageReduction = 0;
const armors = this.getEmbeddedCollection("Item").filter(e => "armor" === e.type);
for (let armor of armors) {
if (armor.system.equipped) {
armorPoints += armor.system.armorPoints;
damageReduction += armor.system.damageReduction;
// Prepare Character type specific data
_deriveCharacter() {
const system = this.system;
//armor points + damage reduction
//init vars
let armorPoints = 0;
let damageReduction = 0;
//count values
for (const armor of this.items.filter(i => i.type === "armor")) {
if (armor.system?.equipped) {
armorPoints += Number(armor.system.armorPoints ?? 0);
damageReduction += Number(armor.system.damageReduction ?? 0);
}
}
}
data.stats.armor.mod = armorPoints;
data.stats.armor.total = armorPoints + data.stats.armor.value;
data.stats.armor.damageReduction = damageReduction;
//set values
system.stats.armor.mod = armorPoints;
system.stats.armor.total = armorPoints + Number(system.stats.armor.value ?? 0);
system.stats.armor.damageReduction = damageReduction;
//net hp
//init vars
let netHPvalue = 0;
let netHPmax = 0;
//check if actor has netHP
system.netHP ??= { value: 0, min: 0, max: 0, label: "Net HP"};
//set values
system.netHP.value = ((Number(system.hits.max ?? 0)-Number(system.hits.value ?? 0)-1) * Number(system.health.max ?? 0)) + Number(system.health.value ?? 0);
system.netHP.max = Number(system.health.max ?? 0) * Number(system.hits.max ?? 0);
}
//Prepare Creature type specific data
_prepareCreatureData(actorData) {
const data = actorData;
// Prepare Creature type specific data
_deriveCreature() {
const system = this.system;
//armor points + damage reduction
//init vars
let armorPoints = 0;
let damageReduction = 0;
//count values
for (const armor of this.items.filter(i => i.type === "armor")) {
if (armor.system?.equipped) {
armorPoints += Number(armor.system.armorPoints ?? 0);
damageReduction += Number(armor.system.damageReduction ?? 0);
}
}
//set values
system.stats.armor.mod = armorPoints;
system.stats.armor.total = armorPoints + Number(system.stats.armor.value ?? 0);
system.stats.armor.damageReduction = damageReduction;
//net hp
//init vars
let netHPvalue = 0;
let netHPmax = 0;
//check if actor has netHP
system.netHP ??= { value: 0, min: 0, max: 0, label: "Net HP"};
//set values
system.netHP.value = ((Number(system.hits.max ?? 0)-Number(system.hits.value ?? 0)-1) * Number(system.health.max ?? 0)) + Number(system.health.value ?? 0);
system.netHP.max = Number(system.health.max ?? 0) * Number(system.hits.max ?? 0);
}
//Prepare Ship type specific data
_prepareShipData(actorData) {
const data = actorData;
// Prepare Ship type specific data
_deriveShip() {
//nothing needed yet
}
//central flavor text library for all chat messages
@@ -1494,18 +1522,27 @@ export class MothershipActor extends Actor {
if (firstEdition) {
//if calm not enabled
if (!useCalm) {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
} else {
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
//if 0e
} else {
@@ -1513,20 +1550,31 @@ export class MothershipActor extends Actor {
if (!useCalm) {
//on Save failure
if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//gain 1 stress
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
} else {
//output standard failure
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
//on Save failure
if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//gain 1 stress
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
}
}
}
@@ -1572,8 +1620,16 @@ export class MothershipActor extends Actor {
if (useCalm) {
//prep text based on success or failure
if (parsedRollResult.success === false && this.type === 'character') {
//set fail text
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
} else if (parsedRollResult.success === true && this.type === 'character') {
//calculate stress reduction
let onesValue = Number(String(parsedRollResult.total).charAt(String(parsedRollResult.total).length - 1));
@@ -1585,13 +1641,13 @@ export class MothershipActor extends Actor {
} else {
//prep text based on success or failure
if (parsedRollResult.success === false && this.type === 'character') {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
@@ -1609,8 +1665,16 @@ export class MothershipActor extends Actor {
if (useCalm) {
//prep text based on success or failure
if (parsedRollResult.success === false && this.type === 'character') {
//set fail text
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
} else if (parsedRollResult.success === true && this.type === 'character') {
//calculate stress reduction
let succeedBy = Math.floor((rollTarget - parsedRollResult.total) / 10);
@@ -1626,13 +1690,13 @@ export class MothershipActor extends Actor {
} else {
//prep text based on success or failure
if (parsedRollResult.success === false && this.type === 'character') {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
@@ -1711,18 +1775,27 @@ export class MothershipActor extends Actor {
if (firstEdition) {
//if calm not enabled
if (!useCalm) {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
} else {
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//increase stress by 1 and retrieve the flavor text from the result
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
//if 0e
} else {
@@ -1730,20 +1803,28 @@ export class MothershipActor extends Actor {
if (!useCalm) {
//on Save failure
if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') {
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//gain 1 stress
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
let addStress = await this.modifyActor('system.other.stress.value', 1, null, false);
flavorText = addStress[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
} else {
//output standard failure
flavorText = game.i18n.localize("Mosh.YouSenseTheWeightOfYourSetbacks");
if (game.settings.get('mosh', 'autoStress')) { //If the automatic stress option is enabled
//gain 1 stress
let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false);
flavorText = removeCalm[1];
}
//if critical failure, make sure to ask for panic check
if (parsedRollResult.critical === true) {
//set crit fail
critFail = true;
}
}
}
} else if (parsedRollResult.success === true && this.type === 'character') {
+33 -110
View File
@@ -121,87 +121,6 @@ Hooks.once("ready", async function () {
}
});
//Calm & 1e/0e character updates
// if the user has calm enabled at the start,
if (game.settings.get('mosh','useCalm')) {
//get list of actors
let actorList = game.actors;
let actorName = '';
let minStart = null;
let valueStart = null;
let maxStart = null;
let labelStart = '';
let minEnd = null;
let valueEnd = null;
let maxEnd = null;
let labelEnd = '';
//loop through all actors and update their stress values
actorList.forEach(function(actor){
//loop through each result
if (actor.type === 'character') {
//set character name
actorName = actor.name;
//set current values
minStart = actor.system.other.stress.min;
valueStart = actor.system.other.stress.value;
maxStart = actor.system.other.stress.max;
labelStart = actor.system.other.stress.label;
//if the label does not say Calm
if (actor.system.other.stress.label != 'Calm') {
//change it to calm
actor.update({'system.other.stress.label': 'Calm'});
//log
labelEnd = 'Calm';
}
//if the MIN value is not 0, this is an old character
if (actor.system.other.stress.min != 0) {
//put this value as the maximum
//change it to calm
actor.update({'system.other.stress.max': actor.system.other.stress.min});
//log
maxEnd = actor.system.other.stress.min;
//set the minimum to zero
//change it to calm
actor.update({'system.other.stress.min': 0});
//log
minEnd = 0;
}
//log change
console.log(actorName + " stress.min changed from " + minStart + " to " + minEnd);
console.log(actorName + " stress.max changed from " + maxStart + " to " + maxEnd);
console.log(actorName + " stress.label changed from " + labelStart + " to " + labelEnd);
//rerender this sheet
actor.render();
}
});
//user does not have calm enabled
} else {
//if the user has Zero edition enabled
if (!game.settings.get('mosh','firstEdition')) {
//loop through all actors and update their stress values
actorList.forEach(function(actor){
//loop through each result
if (actor.type === 'character') {
//set character name
actorName = actor.name;
//set current values
maxStart = actor.system.other.stress.max;
//if the max value, this is an old character
if (actor.system.other.stress.max != 999) {
//put this value as the maximum
//change it to calm
actor.update({'system.other.stress.max': 999});
//log
maxEnd = 999;
}
//log change
console.log(actorName + " stress.max changed from " + maxStart + " to " + maxEnd);
//rerender this sheet
actor.render();
}
});
}
}
});
//add custom damage dice for MOSH
@@ -255,38 +174,42 @@ Hooks.once('diceSoNiceReady', (dice3d) => {
)
})
//Hooks.on("preCreateActor", (createData) => {
/**
* Set default values for new actors' tokens
*/
//set initial things when creating an actor
Hooks.on("preCreateActor", (document, createData, options, userId) => {
let disposition = CONST.TOKEN_DISPOSITIONS.NEUTRAL;
console.log("preCreateActor fired for:", createData?.name, createData?.type);
if (createData.type == "creature") {
disposition = CONST.TOKEN_DISPOSITIONS.HOSTILE
const disposition =
createData.type === "creature"
? CONST.TOKEN_DISPOSITIONS.HOSTILE
: CONST.TOKEN_DISPOSITIONS.NEUTRAL;
// Apply prototype token defaults (v12+)
document.updateSource({
"prototypeToken.bar1.attribute": "system.health", // <-- use full system path
"prototypeToken.bar2.attribute": "system.hits", // adjust to your schema
"prototypeToken.displayName": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER,
"prototypeToken.displayBars": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER,
"prototypeToken.disposition": disposition,
"prototypeToken.name": createData.name
});
if (createData.type === "character") {
document.updateSource({
"prototypeToken.disposition": CONST.TOKEN_DISPOSITIONS.FRIENDLY,
"prototypeToken.actorLink": true,
"prototypeToken.vision": true
});
if (game.settings.get("mosh", "useCalm")) {
document.updateSource({
"system.other.stress.min": 0,
"system.other.stress.value": 85,
"system.other.stress.max": 85,
"system.other.stress.label": "Calm"
});
}
}
// Set wounds, advantage, and display name visibility
foundry.utils.mergeObject(createData,
{
"token.bar1": { "attribute": "health" }, // Default Bar 1 to Health
"token.bar2": { "attribute": "hits" }, // Default Bar 2 to Insanity
"token.displayName": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER, // Default display name to be on owner hover
"token.displayBars": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER, // Default display bars to be on owner hover
"token.disposition": disposition, // Default disposition to neutral
"token.name": createData.name // Set token name to actor name
})
console.log(createData);
console.log("Created!");
if (createData.type == "character") {
console.log("Got here");
const prototypeToken = { disposition: 1, actorLink: true, vision: true}; // Set disposition to "Friendly"
document.updateSource({ prototypeToken });
}
})
});
/* -------------------------------------------- */
+21 -7
View File
@@ -196,15 +196,29 @@ export const registerSettings = function () {
valueStart = actor.system.other.stress.value;
maxStart = actor.system.other.stress.max;
labelStart = actor.system.other.stress.label;
//convert min stress to max calm
actor.update({'system.other.stress.max': Math.round(85-(actor.system.other.stress.min*3))});
maxEnd = Math.round(85-(actor.system.other.stress.min*3));
//update max calm
//set max calm to 85 if min stress is 2
if (minStart === 2) {
actor.update({'system.other.stress.max': 85});
maxEnd = 85;
//otherwise convert the min stress to max calm
} else {
actor.update({'system.other.stress.max': Math.round(85-(actor.system.other.stress.value*3))});
maxEnd = Math.round(85-(actor.system.other.stress.value*3));
}
//set min stress to 0
actor.update({'system.other.stress.min': 0});
minEnd = 0;
//convert stress to calm
actor.update({'system.other.stress.value': Math.round(85-(actor.system.other.stress.value*3))});
valueEnd = Math.round(85-(actor.system.other.stress.value*3));
//update calm
//set calm to 85 if stress is 2
if (valueStart === 2) {
actor.update({'system.other.stress.value': 85});
valueEnd = 85;
//otherwise convert stress to calm
} else {
actor.update({'system.other.stress.value': Math.round(85-(actor.system.other.stress.value*3))});
valueEnd = Math.round(85-(actor.system.other.stress.value*3));
}
//set stress label to Calm
actor.update({'system.other.stress.label': 'Calm'});
labelEnd = 'Calm';
@@ -234,7 +248,7 @@ export const registerSettings = function () {
//set min stress to 20 if > 20
if (Math.round((85-actor.system.other.stress.max)/3) > 20) {
actor.update({'system.other.stress.min': 20});
minEnd = 2;
minEnd = 20;
//set min stress to 2 if < 2
} else if (Math.round((85-actor.system.other.stress.max)/3) < 2) {
actor.update({'system.other.stress.min': 2});
+6 -3
View File
@@ -19,6 +19,12 @@
"max" : 2,
"label" : "Wounds"
},
"netHP": {
"value": 20,
"min": 0,
"max" : 20,
"label" : "Net HP"
},
"bleeding": {
"value": 0,
"min": 0,
@@ -36,9 +42,6 @@
"current" : 0,
"capacity" : 0
},
"settings" : {
"useCalm" : false
},
"class": {
"value": ""
},