diff --git a/ProjectMoonTRPG/ProjectMoonTRPG.html b/ProjectMoonTRPG/ProjectMoonTRPG.html index 797a2b9781..c4d9dc4892 100644 --- a/ProjectMoonTRPG/ProjectMoonTRPG.html +++ b/ProjectMoonTRPG/ProjectMoonTRPG.html @@ -13074,7 +13074,6 @@ on('clicked:applyDamage', (info) => { if (ailmentArray["effect"] == "StagRes" || ailmentArray["effect"] == "HPStagRes") { stDamageBody += generateDamageHelperBodyEffect(ailmentArray["name"], ailmentArray["effectVal"], ailmentArray["type"], ailmentArray["customRes"], getIcon("ailments", ailmentArray["icon"]), ailmentArray["beforeRes"], stResistance, resSTIcon); } - console.log(ailmentArray["effect"]) if (ailmentArray["effect"] == "SP") { spDamageBody += generateDamageHelperBodyEffect(ailmentArray["name"], ailmentArray["effectVal"], ailmentArray["type"], ailmentArray["customRes"], getIcon("ailments", ailmentArray["icon"])); } @@ -14483,143 +14482,12 @@ getAttrs(["settingEditMode"], function(values) { /*--- AutoScript functions ---*/ - - -on("clicked:autoEffectTest", function() { - AutoScriptMain(`(Gain 5 Burn) /* Test comment */ (Gain 2 Fragile Next Turn, TestCondition2)`, "Combat start") - -}); - -/* Main function for using AutoScripts. Called by actions through on click events */ -/* inputAutoScript: AutoScript provided by the action. Can be an empty string */ -/* trigger: "Combat start", "Round start", "Round end", "Damaged", "Staggered", "Defeated", "Panic", - "Permanent", "Offensive", "Defensive", "Block", "Evade" or "None". - Selects which type of AutoEffects to collect and append to an AutoScript. - Block and Evade also include Defensive */ -function AutoScriptMain(inputAutoScript, triggerType="None") { - - /* Converts the input AutoScript to to an array if it isn't one already */ - let AutoScript = []; - if (inputAutoScript != "") { - try { AutoScript = JSON.parse(inputAutoScript); } - catch(e) { AutoScript = AutoScriptToArray(inputAutoScript); } - } - - /* Appends one or more AutoScripts based on the trigger type */ - AutoScript.push(collectAutoScripts(triggerType)); - - - /* Get relevant attributes */ - getAttrs(["settingMuteMessage", "settingWhisperRolls", "settingWhisperTarget", "settingLimbusStyle", "settingHideNextTurn", - "HP", "HP_max", "StagRes", "StagRes_max", "SP", "SP_max", - "StaggerState", "distortState", "egoActiveState", "egoType"], function(values) { - - let settingMuteMessage = values.settingMuteMessage; - let settingWhisperRolls = values.settingWhisperRolls; - let settingWhisperTarget = values.settingWhisperTarget; - let settingLimbusStyle = values.settingLimbusStyle; - let settingHideNextTurn = values.settingHideNextTurn; - - let HP = values.HP; - let HPdamage = values.HP_max - HP; - let ST = values.StagRes; - let STdamage = values.StagRes_max - ST; - let SP = values.SP; - let SPdamage = values.SP_max - SP; - - let StaggerState = values.StaggerState; - let distortState = values.distortState; - let egoActiveState = values.egoActiveState; - let egoType = values.egoType; - - let scaling = 2; - - let output = {}; - let tempOutput = {}; - let ailmentList = {}; - - - /* Get all ailments */ - getAttrs(["burnNextTurnSetting", "bleedNextTurnSetting", "smokeNextTurnSetting", "chargeNextTurnSetting", - "Burn", "Bleed", "Paralysis", "Protection", "StaggerProtection", "Fragile", "Strength", "Feeble", "Endurance", "Disarm", "Haste", "Bind", "Smoke", "Charge", "Fortune", - "BurnNextTurn", "BleedNextTurn", "ParalysisNextTurn", "ProtectionNextTurn", "StaggerProtectionNextTurn", "FragileNextTurn", "StrengthNextTurn", "FeebleNextTurn", "EnduranceNextTurn", "DisarmNextTurn", "HasteNextTurn", "BindNextTurn", "SmokeNextTurn", "ChargeNextTurn", "FortuneNextTurn"], function(values) { - - const HasNextTurn = settingHideNextTurn == true ? 'false' : 'true'; - - let ailmentNames = ["Burn", "Bleed", "Paralysis", "Protection", "StaggerProtection", "Fragile", "Strength", "Feeble", "Endurance", "Disarm", "Haste", "Bind", "Smoke", "Charge", "Fortune"] - ailmentNames.forEach(ailment => { - if (["Burn", "Bleed", "Smoke", "Charge"].includes(ailment)) { - ailmentList[ailment] = [values[ailment.toLowerCase()+"NextTurnSetting"], values[ailment], values[`${ailment}NextTurn`]]; - } else { - ailmentList[ailment] = [HasNextTurn, values[ailment], values[`${ailment}NextTurn`]]; - } - }); - - /* Get all custom ailments */ - getSectionIDs(`repeating_ailments`, idarray => { - const fieldnames = idarray.reduce((rows,id) => - [...rows, `repeating_ailments_${id}_ailName`, `repeating_ailments_${id}_ailNextTurn`, - `repeating_ailments_${id}_ailNum`, `repeating_ailments_${id}_ailNumNextTurn`, ], ''); - - let ailName = ""; - let ailHasNextTurn = ""; - let ailNum = 0; - let ailNumNextTurn = 0; - - getAttrs([...fieldnames], v => { - idarray.forEach(id => { - ailName = v[`repeating_ailments_${id}_ailName`]; - ailHasNextTurn = v[`repeating_ailments_${id}_ailNextTurn`]; - ailNum = v[`repeating_ailments_${id}_ailNum`]; - ailNumNextTurn = v[`repeating_ailments_${id}_ailNumNextTurn`] - - ailmentList[ailName] = [ailHasNextTurn, ailNum, ailNumNextTurn, id]; - }); - - - /* Execute each AutoEffect in the AutoScript */ - AutoScript.forEach(AutoEffect => { - switch (AutoEffect[0][0]) { - case "Gain": tempOutput = autoEffectGainAilment(AutoEffect, ailmentList, scaling); break; - default: autoEffectErrorMessage(`${AutoEffect[0]} is not a valid AutoEffect`, AutoEffect); - } - for (const property in tempOutput) { - if (output.hasOwnProperty(property)) { - output[property] += tempOutput[property]; - } else { - output[property] = tempOutput[property]; - } - } - }); - - // console.log(output) - setAttrs(output); - - - /* Message handling */ - - - - }); - }); - }); - }); -} - - - - -/* Checks all nested AutoScripts and generated one non-nested AutoScript from all scripts matching a type */ -function AutoScriptCombiner(AutoEffectType) { - return; -} - /* Gathers all AutoScripts that match a certain trigger type */ function collectAutoScripts(triggerType) { if (triggerType != "None") { switch (triggerType) { case "Permanent": break; /* Triggers with all other triggers. Useful for stuff like Status Quo */ - case "Combat start": return [["Gain","3","Rupture","This turn"]]; + case "Combat start": return [["Gain","3","Tremor","This turn"]]; case "Round start": break; case "Round end": break; case "Damaged": break; @@ -14687,29 +14555,182 @@ function AutoScriptToArray(inputAutoScript) { return AutoScriptArray; } -/* Checks that an AutoScript in array form is correctly formatted. Returns false upon detecting an error - let barValid = []; - let barValid = []; +on("clicked:autoEffectTest", function() { + AutoScriptMain(`(Require 1 Rupture Scaling) /* Test comment */ (Gain 2 Fragile Next Turn, TestCondition2)`, "Combat start") + +}); + +/* Main function for using AutoScripts. Called by actions through on click events */ +/* inputAutoScript: AutoScript provided by the action. Can be an empty string */ +/* trigger: "Combat start", "Round start", "Round end", "Damaged", "Staggered", "Defeated", "Panic", + "Permanent", "Offensive", "Defensive", "Block", "Evade" or "None". + Selects which type of AutoEffects to collect and append to an AutoScript. + Block and Evade also include Defensive */ +function AutoScriptMain(inputAutoScript, triggerType="None") { + + /* Converts the input AutoScript to to an array if it isn't one already */ + let AutoScript = []; + if (inputAutoScript != "") { + try { AutoScript = JSON.parse(inputAutoScript); } + catch(e) { AutoScript = AutoScriptToArray(inputAutoScript); } + } + + /* Appends one or more AutoScripts based on the trigger type */ + AutoScript.push(collectAutoScripts(triggerType)); + + + /* Get relevant attributes */ + getAttrs(["settingMuteMessage", "settingWhisperRolls", "settingWhisperTarget", "settingLimbusStyle", "settingHideNextTurn", + "HP", "HP_max", "StagRes", "StagRes_max", "SP", "SP_max", + "StaggerState", "distortState", "egoActiveState", "egoType"], function(values) { + + let settingMuteMessage = values.settingMuteMessage; + let settingWhisperRolls = values.settingWhisperRolls; + let settingWhisperTarget = values.settingWhisperTarget; + let settingLimbusStyle = values.settingLimbusStyle; + let settingHideNextTurn = values.settingHideNextTurn; + let HP = values.HP; + let ST = values.StagRes; + let SP = values.SP; + let barList = { HP: parseInt(HP), ST:parseInt(ST), SP:parseInt(SP) }; + + let HPdamage = values.HP_max - HP; + let STdamage = values.StagRes_max - ST; + let SPdamage = values.SP_max - SP; + let barDamageList = { "-HP": HPdamage, "-ST":STdamage, "-SP":SPdamage } + + let StaggerState = values.StaggerState; + let distortState = values.distortState; + let egoActiveState = values.egoActiveState; + let egoType = values.egoType; - inputAutoScript.forEach(AutoEffect => { - if (["Gain", "Require", "Consume", "Action", "Set", "Add", "ChallengeRoll"].includes(AutoEffect[0][0])) { - if (["Set", "Add"].includes(AutoEffect[0][0])) { - if (AutoEffect.length != 2) { - autoEffectErrorMessage(`Expected format: (${AutoEffect[0][0]} #Bar N)`, AutoEffect); return false; - } - } - if (AutoEffect[0][0] == "ChallengeRoll") { - if (AutoEffect.length != 2) { - autoEffectErrorMessage(`Expected format: (${AutoEffect[0][0]} #Stat N)`, AutoEffect); return false; - } + let scaling = 1; + let checkResult = "success"; + + let output = {}; + let tempOutput = {}; + let returnValues = { checkResult:"success", error:false, }; + let ailmentList = {}; + + + /* Get all ailments */ + getAttrs(["burnNextTurnSetting", "bleedNextTurnSetting", "smokeNextTurnSetting", "chargeNextTurnSetting", + "Burn", "Bleed", "Paralysis", "Protection", "StaggerProtection", "Fragile", "Strength", "Feeble", "Endurance", "Disarm", "Haste", "Bind", "Smoke", "Charge", "Fortune", + "BurnNextTurn", "BleedNextTurn", "ParalysisNextTurn", "ProtectionNextTurn", "StaggerProtectionNextTurn", "FragileNextTurn", "StrengthNextTurn", "FeebleNextTurn", "EnduranceNextTurn", "DisarmNextTurn", "HasteNextTurn", "BindNextTurn", "SmokeNextTurn", "ChargeNextTurn", "FortuneNextTurn"], function(values) { + + const HasNextTurn = settingHideNextTurn == true ? 'false' : 'true'; + + let ailmentNames = ["Burn", "Bleed", "Paralysis", "Protection", "StaggerProtection", "Fragile", "Strength", "Feeble", "Endurance", "Disarm", "Haste", "Bind", "Smoke", "Charge", "Fortune"] + ailmentNames.forEach(ailment => { + if (["Burn", "Bleed", "Smoke", "Charge"].includes(ailment)) { + ailmentList[ailment] = [values[ailment.toLowerCase()+"NextTurnSetting"], values[ailment], values[`${ailment}NextTurn`]]; + } else { + ailmentList[ailment] = [HasNextTurn, values[ailment], values[`${ailment}NextTurn`]]; + } + }); + + /* Get all custom ailments */ + getSectionIDs(`repeating_ailments`, idarray => { + const fieldnames = idarray.reduce((rows,id) => + [...rows, `repeating_ailments_${id}_ailName`, `repeating_ailments_${id}_ailNextTurn`, + `repeating_ailments_${id}_ailNum`, `repeating_ailments_${id}_ailNumNextTurn`, ], ''); + + let ailName = ""; + let ailHasNextTurn = ""; + let ailNum = 0; + let ailNumNextTurn = 0; + + getAttrs([...fieldnames], v => { + idarray.forEach(id => { + ailName = v[`repeating_ailments_${id}_ailName`]; + ailHasNextTurn = v[`repeating_ailments_${id}_ailNextTurn`]; + ailNum = v[`repeating_ailments_${id}_ailNum`]; + ailNumNextTurn = v[`repeating_ailments_${id}_ailNumNextTurn`] + + ailmentList[ailName] = [ailHasNextTurn, ailNum, ailNumNextTurn, id]; + }); + + + /* Execute each AutoEffect in the AutoScript */ + AutoScript.forEach(AutoEffect => { + /* Checks are always processed. Other AutoEffects are not processed if the last check failed */ + switch (AutoEffect[0][0]) { + case "Require": tempOutput = autoEffectRequire(AutoEffect, ailmentList, barList, barDamageList); break; + case "Consume": tempOutput = autoEffectConsume(AutoEffect, ailmentList, barList); break; + default: tempOutput = {}; break; + } + if (checkResult != "failure") { + switch (AutoEffect[0][0]) { + case "Require": break; /* Already executed above */ + case "Consume": break; + case "Gain": tempOutput = autoEffectGainAilment(AutoEffect, ailmentList, scaling); break; + default: tempOutput = {error:true}; autoEffectErrorMessage(`${AutoEffect[0]} is not a valid AutoEffect`, AutoEffect); break; } } - }); - else if (isNaN(parseInt(autoEffectArray[0][1]))) { autoEffectErrorMessage(`Value "${autoEffectArray[0][1]}" is not a number`, autoEffect); return null; } - else if (getAilmentAttribute(autoEffectArray[0][2]) == false) { autoEffectErrorMessage(`"Ailment "${autoEffectArray[0][2]}" does not exist`, autoEffect); return null; } - */ + console.log(tempOutput) + /* Handle errors. Continues executing AutoEffects for the sake of finding additional errors, */ + /* but does not apply any changes to attributes */ + if (tempOutput.hasOwnProperty("error") || returnValues.error == true) { + returnValues.error == true; + output = {}; + return; + } + + /* Handle changes to scaling */ + if (tempOutput.hasOwnProperty("scaling")) { + scaling = parseInt(tempOutput.scaling); + delete tempOutput.scaling; + } + + /* Handle check results from Require and Consume */ + /* For the returnValues, the worst result is returned */ + if (tempOutput.checkResult != undefined) { + checkResult = tempOutput.checkResult; + if (returnValues.checkResult == "success") { + returnValues.checkResult = tempOutput.checkResult; + } + else if (returnValues.checkResult == "last success" && tempOutput.checkResult == "failure") { + returnValues.checkResult = tempOutput.checkResult; + } + delete tempOutput.checkResult; + } + + /* Add attribute changes from AutoEffect to output */ + /* The first time a attribute is modified, add it's count */ + /* For example, if Gain 3 Burn is used and current Burn is 2, output Burn is set to 5 */ + /* If Consume 4 Burn is used later, this amount will be removed without adding count */ + for (const property in tempOutput) { + if (output.hasOwnProperty(property)) { + output[property] += tempOutput[property]; + } else { + output[property] = tempOutput[property] + tempOutput.count; + } + } + }); + + // console.log(output) + setAttrs(output); + + console.log(returnValues) + + + /* Message handling */ + + + /* Error handling */ + if (returnValues.error == true) { + /* Run function that clears all condition buttons */ + } + + + + }); + }); + }); + }); +} /*--- AutoScript functions end ---*/ @@ -14720,10 +14741,116 @@ function autoEffectErrorMessage(errorString, autoEffect) { console.log(errorString + autoEffect) } +/* Checks if an AutoEffect has conditionals */ +/* If true, creates a condition button for each conditional and returns true */ +/* If the condition button already exists, append the AutoEffect to the existing button */ +/* If false, returns false */ +function processConditionals(AutoEffect) { + if (AutoEffect.length > 1) { + AutoEffect.slice(1).forEach(conditional => { + /* Remember to apply AutoEffect.slice(0,2)) */ + console.log("Creating conditionButton " + conditional + " with effect " + JSON.stringify(AutoEffect.slice(0,2))); + }); + return true; + } + return false; +} -/* Sets up a condition button with an AutoEffect, or appends the AutoEffect to the button if it already exists*/ -function conditionButton(conditional, AutoEffect) { - console.log("Creating conditionButton " + conditional + " with effect " + JSON.stringify(AutoEffect)); + +function autoEffectRequire(AutoEffect, ailmentList, barList, barDamageList) { + /* Check format */ + if (AutoEffect[0].length < 3 || AutoEffect[0].length > 4) { autoEffectErrorMessage(`Expected format: (Require N #Ailment/#Bar/#BarDamage #Scaling(optional))`, AutoEffect); return {error: true}; } + + /* Handle conditionals */ + if (processConditionals(AutoEffect) == true) { return {}; } + + /* Get required value */ + let effectVal = parseInt(Math.abs(AutoEffect[0][1])); + if (isNaN(effectVal) == true) { autoEffectErrorMessage(`Value "${AutoEffect[0][1]}" is not a number`, AutoEffect); return {error: true}; } + + /* Get target count */ + let effectName = AutoEffect[0][2]; + + /* Handle ailment count */ + if (ailmentList.hasOwnProperty(effectName)) { count = ailmentList[effectName][1]; } + /* Handle bar count */ + else if (barList.hasOwnProperty(effectName)) { count = barList[effectName]; } + /* Handle bar damage count */ + else if (barDamageList.hasOwnProperty(effectName)) { count = barDamageList[effectName]; } + else { autoEffectErrorMessage(`Ailment, Bar or BarDamage "${effectName}" does not exist`, AutoEffect); return {error: true}; } + + /* Handle the optional scaling property */ + let scaling = 1; + let returnValues = {}; + if (AutoEffect[0][3] != undefined) { + if (AutoEffect[0][3].toLowerCase() == "scaling") { + scaling = Math.floor(count/effectVal); + returnValues.scaling = scaling; + } + } + + /* Execute AutoEffect check */ + if (count >= effectVal) { + returnValues.checkResult = "success"; + } else { + returnValues.checkResult = "failure"; + } + return returnValues; +} + +function autoEffectConsume(AutoEffect, ailmentList, barList) { + /* Check format */ + if (AutoEffect[0].length < 3 || AutoEffect[0].length > 4) { autoEffectErrorMessage(`Expected format: (Consume N #Ailment/#Bar #Scaling(optional))`, AutoEffect); return {error: true}; } + + /* Handle conditionals */ + if (processConditionals(AutoEffect) == true) { return {}; } + + /* Get consumed value */ + let effectVal = parseInt(Math.abs(AutoEffect[0][1])); + if (isNaN(effectVal) == true) { autoEffectErrorMessage(`Value "${AutoEffect[0][1]}" is not a number`, AutoEffect); return {error: true}; } + let count = 0; + + /* Get target */ + let effectName = AutoEffect[0][2]; + let effectTarget = ""; + let effectRepeatingId = ailmentList[effectName][3]; + + /* Handle ailment target */ + if (ailmentList.hasOwnProperty(effectName)) { + if (effectRepeatingId == undefined) { effectTarget = effectName; } /* If standard ailment */ + else { effectTarget = `repeating_ailments_${ailmentList[effectName][3]}_ailNum`; } /* If custom ailment */ + count = ailmentList[effectName][1]; + } + /* Handle bar target */ + else if (barList.hasOwnProperty(effectName)) { + effectTarget = effectName; + count = barList[effectName]; + } + else { autoEffectErrorMessage(`Ailment or Bar "${effectName}" does not exist`, AutoEffect); return {error: true}; } + + /* Handle the optional scaling property */ + let scaling = 1; + let returnValues = {}; + if (AutoEffect[0][3] != undefined) { + if (AutoEffect[0][3].toLowerCase() == "scaling") { + scaling = Math.floor(count/effectVal); + returnValues.scaling = scaling; + } + } + + /* Execute AutoEffect check */ + if (count >= effectVal) { + returnValues[effectTarget] = -effectVal*scaling; + returnValues.count = parseInt(count); + if (!(count >= 2*effectVal)) { + returnValues.checkResult = "last success"; + } else { + returnValues.checkResult = "success"; + } + } else { + returnValues.checkResult = "failure"; + } + return returnValues; } function autoEffectGainAilment(AutoEffect, ailmentList, scaling) { @@ -14732,17 +14859,10 @@ function autoEffectGainAilment(AutoEffect, ailmentList, scaling) { /* Handle scaling */ AutoEffect[0][1] *= scaling; - if (scaling == 0) { return null } + if (scaling == 0) { return {}; } /* Handle conditionals */ - if (AutoEffect.length > 1) { - let conditionalReturn = false; - AutoEffect.slice(1).forEach(conditional => { - conditionButton(conditional, AutoEffect.slice(0,2)); - conditionalReturn = true; - }); - if (conditionalReturn) { return null; } - } + if (processConditionals(AutoEffect) == true) { return {}; } /* Get ailment name */ let effectAilment = AutoEffect[0][2]; @@ -14775,7 +14895,7 @@ function autoEffectGainAilment(AutoEffect, ailmentList, scaling) { } /* Execute AutoEffect */ - return { [effectTarget]: parseInt(count) + parseInt(effectVal) } + return { [effectTarget]: parseInt(effectVal), count:parseInt(count) } }