i += base);
+}
+
+/**
+ * Return a sequence of names
+ * @param {number} count - Length of the sequence
+ * @param {string} name - Name template (with | placeholder to insert the sequence)
+ * @param {number} base - Base number for the sequence (default 1)
+ * @returns {string[]}
+ */
+ function nameSeq(count, name, base = 1) {
+ const [ prepend, append ] = name.split("|");
+ return seq(count, base).map(s => `${prepend || ""}${s}${append || ""}`)
+}
-function onChanged(list) {
- return list
- .split(",")
- .map(a => `changed:${ a.toLowerCase() }`)
- .join(" ");
+/**
+ * Return a list of event as array or as string
+ * @param {string} eventName - Name of the event
+ * @param {string[]} attributeList - List of attributes
+ * @param {string} joinChar - Character to use for joining the items
+ * @returns {string[]|string}
+ */
+function eventList(eventName, attributeList, joinChar = "") {
+ const result = attributeList.map(a => `${eventName}:${ a.toLowerCase() }`)
+ return joinChar !== "" ? result.join(joinChar) : result;
}
/**
* Remove all rows for a repeating section
* @param {string} sectionName Repeating section to clear
*/
-function removeRepeating(sectionName) {
+function removeRepeatingAll(sectionName) {
getSectionIDs(sectionName, function (rowIds) {
rowIds.forEach(rowId => {
removeRepeatingRow(`repeating_${sectionName}_${rowId}`);
@@ -9273,6 +10086,85 @@
});
}
+/** @typedef sendChatMsgOptions
+ * @property {string} title - Title of the message
+ * @property {string} template - Name of roll template
+ * @property {string} whisper - Target for whispered message
+ */
+
+/**
+ * Send a message to chat
+ * @param {string|string[]} msg - Message to send
+ * @param {sendChatMsgOptions} options - Options for the message
+ */
+ function sendChatMsg(msg, options = {}) {
+ let { title = "", template = "default", whisper = "" } = options;
+ if (whisper !== "") whisper = "/w " + whisper + " ";
+ let chatMsg;
+ if (Array.isArray(msg)) {
+ chatMsg = msg.map(t => `{{${t} }}`).join(" ");
+ } else {
+ chatMsg = "{{" + msg + "}}";
+ }
+ const chatCmd = `${whisper}&{template:${template}} ${title ? (template === "default" ? `{{name=${title} }}` : `{{${title} }}`) : "" } ${chatMsg}`;
+ startRoll(chatCmd, roll => {
+ finishRoll(roll.rollId);
+ });
+}
+
+/**
+ * Return co1 rolltemplate
+ * @param {object} props - List of {{ }} sections as object properties
+ * @returns {string[]}
+ */
+function coRollTemplate(props) {
+ return [
+ "perso=@{character_name}",
+ ...Object.entries(props).map(e => {
+ let [ prop, value ] = e;
+ prop = prop === "leftsub" ? "subtags" : prop;
+ prop = prop === "rightsub" ? "name" : prop;
+ return `${prop}=${value} `;
+ })
+ ];
+}
+
+/**
+ * Send a single value roll query to chat and process response
+ * @param {string} prompt - Input box label
+ * @param {object} callback - Callback function to process input
+ */
+function askValue(prompt, callback) {
+ const askValue = `!{{ask=[[?{${prompt}}]]}}`;
+ startRoll(askValue, question => {
+ const query = question.results.ask.result;
+ if(query && callback) {
+ callback(query);
+ }
+ });
+}
+
+/**
+ * Send a drop-down roll query to chat and process response
+ * @param {string|array} askParams - Parameters of the roll query
+ * @param {object} callback - Callback function to process input
+ */
+function ask(askParams, callback) {
+ if (!Array.isArray(askParams)) {
+ askParams = [ askParams, "Non", "Oui" ];
+ }
+ const [ prompt, ...choices ] = askParams;
+ const choice = choices.map((ch, ix) => `${ch},${ix}`).join("|");
+ const ask = `!{{ask=[[?{${prompt}|${choice}}]]}}`;
+ startRoll(ask, question => {
+ const query = question.results.ask.result;
+ if(query && callback) {
+ callback(query, choices);
+ }
+ //finishRoll(question.rollId);
+ });
+};
+
/**
* Check if sheet is a vehicle
* @param {string} sheetTypeValue sheet type
@@ -9335,10 +10227,10 @@
let abilities = false;
let ability = { name: "", desc: "" };
- clog("<<>>", "statblock import");
+ clog("<<>>", "NPC STATBLOCK IMPORT");
rows.forEach(function (row, rowNum) {
let dataRow = row.trim();
- clog(dataRow, "statblock import -> parse row");
+ clog(dataRow, "NPC statblock import -> parse row");
if (rowNum === 0) {
const values = dataRow.split(" ");
const ncix = values.findIndex((v) => v.startsWith("NC"));
@@ -9388,7 +10280,6 @@
dataRow = dataRow.replace(/ \(DM/g, " DM");
dataRow = dataRow.replace(/ DM \(/g, " DM ");
dataRow = dataRow.replace(/\)$/g, "");
- console.log(dataRow);
npc.attacks.push(dataRow);
return;
}
@@ -9415,7 +10306,7 @@
if (dataRow.toUpperCase().startsWith("PV"))
dataRow = dataRow.replace("(", "SBG ");
const items = dataRow.split(" ");
- clog(items, "statblock import -> attributes");
+ clog(items, "NPC statblock import -> attributes");
for (var item = 0; item < items.length; item++) {
if (item % 2 === 0) {
const k = items[item].toUpperCase().replace(/\./g, "");
@@ -9437,7 +10328,7 @@
});
if (ability.name !== "") addTrait(npc, ability);
- clog("<<>>", "statblock import");
+ clog("<<>>", "NPC STATBLOCK IMPORT");
return npc;
}
@@ -9480,10 +10371,10 @@
let crew = false;
let options = false;
- clog("<<>>", "statblock import");
+ clog("<<>>", "STARSHIP STATBLOCK IMPORT");
rows.forEach(function (row, rowNum) {
let dataRow = row.trim();
- clog(dataRow, "statblock import -> parse row");
+ clog(dataRow, "STARSHIP statblock import -> parse row");
if (rowNum == 0) {
ship.PROFIL = dataRow;
if (shipName !== "") ship.character_name = shipName;
@@ -9523,7 +10414,7 @@
if (dataRow.toUpperCase().indexOf("PV") >= 0)
dataRow = dataRow.replace("(", "SBG ");
const items = dataRow.split(" ");
- clog(items, "statblock import -> attributes");
+ clog(items, "STARSHIP statblock import -> attributes");
for (var item = 0; item < items.length; item++) {
if (item % 2 === 0) {
const k = items[item].toUpperCase().replace(/\./g, "");
@@ -9547,7 +10438,7 @@
if (crew) ship.crew.push(dataRow);
if (options) ship.options.push(dataRow);
});
- clog("<<>>", "statblock import");
+ clog("<<>>", "STARSHIP STATBLOCK IMPORT");
return ship;
}
@@ -9585,10 +10476,10 @@
let attribs = false;
let options = false;
- clog("<<>>", "statblock import");
+ clog("<<>>", "MECHA STATBLOCK IMPORT");
rows.forEach(function (row, rowNum) {
let dataRow = row.trim();
- clog(dataRow, "statblock import -> parse row");
+ clog(dataRow, "MECHA statblock import -> parse row");
if (rowNum === 0) {
if (mechName !== "") {
mecha.PROFIL = dataRow;
@@ -9626,10 +10517,9 @@
items[3].toUpperCase() == "NIVEAU"
) {
const type = items.splice(2, 1);
- console.log(type);
mecha.PROFIL = capitalize(type[0].replace("(", ""));
}
- clog(items, "statblock import -> attributes");
+ clog(items, "MECHA statblock import -> attributes");
for (var item = 0; item < items.length; item++) {
if (item % 2 === 0) {
const k = items[item].toUpperCase().replace(/\./g, "");
@@ -9652,7 +10542,7 @@
// read others
if (options) mecha.options.push(dataRow);
});
- clog("<<>>", "statblock import");
+ clog("<<>>", "MECHA STATBLOCK IMPORT");
return mecha;
}
@@ -9746,7 +10636,7 @@
delete pnjObj.SBG;
pnjAttrs.pnj_rd = int(pnjObj.RD);
delete pnjObj.RD;
- clog(pnjAttrs, "statblock parser -> setting attributes");
+ clog(pnjAttrs, "NPC statblock parser -> setting attributes");
pnjAttrs.statblock = "";
setAttrs(pnjAttrs);
@@ -9760,12 +10650,12 @@
* @returns {string} Result message
*/
function processAttacks(universe, pnjObj) {
- removeRepeating("pnjatk");
+ removeRepeatingAll("pnjatk");
let result = "";
for (const atk of pnjObj.attacks) {
const atkItems = atk.split(" ");
- clog(atkItems, "statblock parser -> attacks found");
+ clog(atkItems, "NPC statblock parser -> attacks found");
if (atkItems[atkItems.length - 1] === "DM") {
atkItems.push("-");
}
@@ -9794,7 +10684,7 @@
parsed = "";
continue;
}
- if (atkItem.charAt(0) === "(" && atkItem.endsWith("m)")) {
+ if (atkItem.startsWith("(") && atkItem.endsWith("m)")) {
atkPortee = atkItem.substring(1, atkItem.length - 1);
continue;
}
@@ -9803,7 +10693,7 @@
}
clog(
atkNom + " " + atkBonus + " " + atkDM + " " + atkSpec,
- "statblock parser -> attack"
+ "NPC statblock parser -> attack"
);
if (atkBonus === -1) {
atkAtt = "0"; // No attack bonus found, damage only
@@ -9846,7 +10736,7 @@
if (atkSpec !== "") {
atkRow[`${newRowID}_atkspec`] = atkSpec;
}
- clog(atkRow, "statblock parser -> adding attack");
+ clog(atkRow, "NPC statblock parser -> adding attack");
setAttrs(atkRow);
} else {
result +=
@@ -9867,7 +10757,7 @@
* @returns {string} Result message
*/
function processTraits(universe, pnjObj) {
- removeRepeating("pnjcapas");
+ removeRepeatingAll("pnjcapas");
let result = "";
for (const ability of pnjObj.abilities) {
@@ -9915,7 +10805,7 @@
desc = desc.replace(/\]\] \+ /g, " + ");
desc = desc.replace(/}\]/g, "} ]]");
abilityRow[`${newRowID}_capadesc`] = desc + reload;
- clog(abilityRow, "statblock parser -> adding trait");
+ clog(abilityRow, "NPC statblock parser -> adding trait");
setAttrs(abilityRow);
}
} else {
@@ -10002,7 +10892,7 @@
let options = shipObj.options.join(" ").split(",");
let optList = "";
- removeRepeating("armesv");
+ removeRepeatingAll("armesv");
options.forEach((optn) => {
optn = optn.trim();
if (
@@ -10014,9 +10904,7 @@
const armenom = atko[0].replace("’", "'");
const armedmnbde = int(atko[1].split("d")[0]);
const armedmde = int(atko[1].split("d")[1]);
- clog(armenom);
const weapon = shipWeapons.find((w) => w.name.toLowerCase() == armenom.substring(3).toLowerCase());
- clog(weapon);
if (!weapon) return;
let newRowID = "repeating_armesv_" + generateRowID();
shipAttrs[`${newRowID}_armenom`] = armenom;
@@ -10039,11 +10927,10 @@
shipAttrs.notes = shipObj.bio.join(" ");
- clog(shipAttrs, "statblock parser -> setting attributes");
+ clog(shipAttrs, "STARSHIP statblock parser -> setting attributes");
shipAttrs.statblock = "";
if (messages) success = "";
shipAttrs.sbresult = success + messages;
- clog(shipAttrs);
setAttrs(shipAttrs);
return shipAttrs.sbresult;
@@ -10249,8 +11136,8 @@
}
});
- removeRepeating("mecatk");
- removeRepeating("mecopt");
+ removeRepeatingAll("mecatk");
+ removeRepeatingAll("mecopt");
const funcs = [];
options.forEach((optn) => {
optn = optn.trim();
@@ -10265,7 +11152,6 @@
const armedmnbde = int(atko[1].split("d")[0]);
const armedmde = int(atko[1].split("d")[1].replaceAll("+", ""));
const weapon = mechWeapons.find((w) => w.name == armenom);
- //console.log(armenom,weapon);
const newRowID = "repeating_mecatk_" + generateRowID();
mechAttrs[`${newRowID}_atknom`] = capitalize(armenom);
mechAttrs[`${newRowID}_atkatt`] = "attaque=";
@@ -10306,11 +11192,10 @@
funcs.forEach((fn) => fn(mechAttrs));
- clog(mechAttrs, "statblock parser -> setting attributes");
+ clog(mechAttrs, "MECHA statblock parser -> setting attributes");
mechAttrs.statblock = "";
if (messages) success = "";
mechAttrs.sbresult = success + messages;
- clog(mechAttrs);
setAttrs(mechAttrs);
return mechAttrs.sbresult;
@@ -10324,24 +11209,8 @@
[
...ABILITIES,
"NIVEAU",
- "RANG_VOIE1",
- "RANG_VOIE2",
- "RANG_VOIE3",
- "RANG_VOIE4",
- "RANG_VOIE5",
- "RANG_VOIE6",
- "RANG_VOIE7",
- "RANG_VOIE8",
- "RANG_VOIE9",
- "voie1nom",
- "voie2nom",
- "voie3nom",
- "voie4nom",
- "voie5nom",
- "voie6nom",
- "voie7nom",
- "voie8nom",
- "voie9nom",
+ ...nameSeq(9, "RANG_VOIE"),
+ ...nameSeq(9, "voie|nom"),
],
function (values) {
let caracs = {};
@@ -10350,12 +11219,12 @@
if (value && !isNaN(value)) value = int(value);
if (attr.startsWith("RANG_")) {
if (!caracs.hasOwnProperty("rangs"))
- caracs.rangs = [0, 0, 0, 0, 0, 0, 0, 0, 0];
+ caracs.rangs = Array(9).fill(0);
let voie = int(attr.substring(attr.length - 1));
if (voie > 0) caracs.rangs[voie - 1] = value;
} else if (attr.startsWith("voie") && attr.endsWith("nom")) {
if (!caracs.hasOwnProperty("voies"))
- caracs.voies = ["", "", "", "", "", "", "", "", ""];
+ caracs.voies = Array(9).fill("");
let voie = int(attr.substring(4, 5));
if (voie > 0 && value) caracs.voies[voie - 1] = value.toUpperCase();
} else {
@@ -10365,6 +11234,7 @@
setAttrs({
CARACS: JSON.stringify(caracs),
});
+ clog(caracs, "BUILD CARACS");
}
);
}
@@ -10384,6 +11254,16 @@
} else {
attrs[`voie${ix + 1}-t${rank + 1}`] = ability.name;
attrs[`voie${ix + 1}-${rank + 1}`] = ability.description;
+ attrs[`v${ix + 1}r${rank + 1}_use`] = 0;
+ attrs[`v${ix + 1}r${rank + 1}_use_max`] = 0;
+ attrs[`v${ix + 1}r${rank + 1}_freq`] = "";
+ if (ability.uses) {
+ const { number = 0, per = "" } = ability.uses;
+ if (number > 0 && by !== "") {
+ attrs[`v${ix + 1}r${rank + 1}_use_max`] = number;
+ attrs[`v${ix + 1}r${rank + 1}_freq`] = per;
+ }
+ }
}
});
});
@@ -10399,8 +11279,8 @@
*/
function importGearJSON(attrs, data, reset = false) {
if (reset) {
- removeRepeating("equipement");
- removeRepeating("armes");
+ removeRepeatingAll("equipement");
+ removeRepeatingAll("armes");
}
data.forEach((gear, ix) => {
const nbr = int(gear.nombre);
@@ -10439,7 +11319,7 @@
* - parse and update profile's path & abilities
* - optionally parse profile's gear
*/
-on("clicked:importprofile", function () {
+on("clicked:importprofile-btn", function () {
getAttrs(["json_profile", "reset_gears", "NIVEAU", "CON", "CHA"], function (v) {
if (v.json_profile.trim() === "") return;
const reset_gears = int(v.reset_gears) === 1 ? true : false;
@@ -10479,7 +11359,6 @@
const combat = jsonData.character.combat || [];
if (combat.length > 0) {
combat.forEach(attr => {
- clog(attr)
const { name, value } = parseNameValue(attr);
let atk = "";
switch (name) {
@@ -10514,8 +11393,8 @@
attrs["FAMILLE"] = jsonData.family;
attrs = importProfileJSON(attrs, jsonData);
}
- clog(attrs, "JSON profile & gear parser");
setAttrs(attrs);
+ clog(attrs, "JSON profile & gear parser");
buildCaracs();
});
});
@@ -10694,7 +11573,9 @@
.join(":")
.trim();
setAttrs(traitRow);
- setAttrs({ VERSION: "3.4" });
+ setAttrs({
+ VERSION: "3.4"
+ });
}
});
}
@@ -10731,7 +11612,9 @@
setAttrs(buffAttr);
});
}
- setAttrs({ VERSION: "3.5" });
+ setAttrs({
+ VERSION: "3.5"
+ });
}
function migrateSheetV3_9() {
@@ -10897,7 +11780,9 @@
getAttrs(["UNIVERS", "type_personnage"], function (values) {
if (values.UNIVERS !== "CG" && values.UNIVERS !== "COG") return;
if (values.UNIVERS === "CG") {
- setAttrs({ UNIVERS: "COG" });
+ setAttrs({
+ UNIVERS: "COG"
+ });
}
if (values.type_personnage === SHEET_PC) {
getAttrs(
@@ -10955,7 +11840,9 @@
logv += " : Succès\n";
}
}
- setAttrs({ logvers: logv + logvers });
+ setAttrs({
+ logvers: logv + logvers
+ });
}
);
}
@@ -11006,63 +11893,63 @@
if (verfdp.major === 0) {
// Version 1.6 vers 1.7
migrateSheetV1_7();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major < 3) {
// version 2.0 > 3.0
migrateSheetV3();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 4) {
// version 3.3 > 3.4
migrateSheetV3_4();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 5) {
// version 3.4 > 3.5
migrateSheetV3_5();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 9) {
// version 3.50 > 3.90
migrateSheetV3_9();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 91) {
// version 3.90 > 3.91
migrateSheetV3_91();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 92) {
// version 3.91 > 3.92
migrateSheetV3_92();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 110) {
// version 3.92 > 3.110
migrateSheetV3_110();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 112) {
migrateSheetV3_112();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major == 3 && verfdp.minor < 114) {
migrateSheetV3_114();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
// update to COG v2
if (verfdp.major < 4) {
migrateSheetV4();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major === 4 && verfdp.minor <= 2) {
migrateSheetV420();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
if (verfdp.major === 4 && verfdp.minor <= 3) {
migrateSheetV430();
- clog(newver, "migrate sheet");
+ clog(newver, "MIGRATE SHEET");
}
}
@@ -11093,7 +11980,7 @@
const starship = int(values.vehicle_starship);
const mecha = int(values.vehicle_mecha);
let token_url = stringOrDefault(values.character_token);
- if (token_url !== "") token_url = token_url.split("?")[0];
+ if (token_url !== "") [ token_url ] = token_url.split("?");
if (token_url === "") {
if (starship && !mecha) token_url = "starship.png";
if (mecha && !starship) token_url = "mecha.png";
@@ -11132,7 +12019,9 @@
) {
migrateSheet(verfdp, newver);
}
- setAttrs({ VERSION: values.VERFDP });
+ setAttrs({
+ VERSION: values.VERFDP
+ });
});
// Activer Buffs PSY ou de vaisseau
getAttrs(
@@ -11172,14 +12061,18 @@
);
// MAJ LAST_PV
getAttrs(["PV"], function (v) {
- setAttrs({ LAST_PV: v.PV });
+ setAttrs({
+ LAST_PV: v.PV
+ });
});
// MAJ token
getAttrs(
["vehicle_starship", "vehicle_mecha", "character_token"],
function (values) {
const token_url = getTokenURL(values);
- setAttrs({ token_url });
+ setAttrs({
+ token_url
+ });
}
);
// ARMURE_MALUS
@@ -11226,10 +12119,12 @@
*/
on("change:character_name", function () {
getAttrs(["character_name"], function (values) {
- var charName = values.character_name;
+ let charName = values.character_name;
charName = charName.replace(/ "/g, " «");
charName = charName.replace(/" /g, "» ");
- setAttrs({ character_name: charName });
+ setAttrs({
+ character_name: charName
+ });
});
});
@@ -11286,7 +12181,9 @@
for (const value in values) {
pc_max += int(values[value]);
}
- setAttrs({ PC_max: pc_max });
+ setAttrs({
+ PC_max: pc_max
+ });
});
}
@@ -11318,7 +12215,10 @@
break;
}
const PR = PR_max - PR_used;
- setAttrs({ PR, PR_max });
+ setAttrs({
+ PR,
+ PR_max
+ });
})
});
});
@@ -11342,10 +12242,12 @@
case "foe": display = "Ennemi-e"; break;
case "other": display = "Divers"; break;
}
- setAttrs({ repeating_traits_traitdisptype: display });
+ setAttrs({
+ repeating_traits_traitdisptype: display
+ });
});
}
- if (["acq", "ally", "foe"].indexOf(eventInfo.newValue) !== -1) updatePR();
+ if (["acq", "ally", "foe"].includes(eventInfo.newValue)) updatePR();
});
/**
@@ -11358,7 +12260,9 @@
for (const value in values) {
seuilbg += int(values[value]);
}
- setAttrs({ SEUILBG: seuilbg });
+ setAttrs({
+ SEUILBG: seuilbg
+ });
});
}
@@ -11374,7 +12278,6 @@
*/
function buffValue(v, caracs) {
v = v.trim();
- clog(v);
let bm = 1;
if (v.startsWith("-")) bm = -1;
if (v.indexOf("2[") !== -1) {
@@ -11382,7 +12285,7 @@
bm *= 2;
}
v = v.replace(/[\+\-\[\]]/g, "");
- clog(v, "buff text parser");
+ clog(v, "BUFF text parser");
if (isNaN(v)) {
// c'est une référence d'attribut
if (v.toUpperCase().startsWith("VOIE")) {
@@ -11426,7 +12329,6 @@
for (let b = 0; b < buffs.length; b++) {
let buff = buffs[b] || "";
if (buff !== "") {
- console.log(buff);
let delim = buff.indexOf(":") !== -1 ? ":" : " ";
let buffv = buff.split(delim);
let buffName = "";
@@ -11439,7 +12341,7 @@
buffName = buffv[0].trim();
buffVal = buffValue(buffv[1], caracs);
}
- clog(buffName, "buff list parser");
+ clog(buffName, "BUFF list parser");
if (!buffName.startsWith("-")) buffSum += buffVal;
}
}
@@ -11466,18 +12368,13 @@
"INIT",
"DEF",
"DEP",
- ];
- for (let a = 0; a < attrs.length; a++) {
- attrs[a] = `${attrs[a]}_BUFF_LIST`;
- }
- attrs.unshift(changed);
+ ].map(attr => `${attr}_BUFF_LIST`);
getAttrs(attrs, function (values) {
- let props = Object.keys(values);
- for (let p = 1; p < props.length; p++) {
- if (props[p].startsWith(props[0])) continue;
- if (values[props[p]].indexOf(`[${props[0]}]`) !== -1)
- parseBuff(props[p].replace("_BUFF_LIST", ""));
- }
+ Object.keys(values).forEach(attr => {
+ if (attr.startsWith(changed)) return;
+ if (values[attr].indexOf(`[${changed}]`) !== -1)
+ parseBuff(attr.replace("_BUFF_LIST", ""));
+ });
});
}
@@ -11486,32 +12383,11 @@
*/
on(
[
- "change:for",
- "change:dex",
- "change:con",
- "change:int",
- "change:per",
- "change:cha",
"change:niveau",
"change:defarmureon",
- "change:voie1nom",
- "change:voie2nom",
- "change:voie3nom",
- "change:voie4nom",
- "change:voie5nom",
- "change:voie6nom",
- "change:voie7nom",
- "change:voie8nom",
- "change:voie9nom",
- "change:rang_voie1",
- "change:rang_voie2",
- "change:rang_voie3",
- "change:rang_voie4",
- "change:rang_voie5",
- "change:rang_voie6",
- "change:rang_voie7",
- "change:rang_voie8",
- "change:rang_voie9",
+ ...eventList("change", ABILITIES),
+ ...eventList("change", nameSeq(9, "voie|nom")),
+ ...eventList("change", nameSeq(9, "rang_voie"))
].join(" "),
function (eventInfo) {
// on reconstruit d'abord l'attribut caché CARACS...
@@ -11531,7 +12407,9 @@
initVal += int(values.PER);
initVal += int(values.INIT_BUFF);
initVal -= int(values.ARMURE_MALUS);
- setAttrs({ INIT: initVal });
+ setAttrs({
+ INIT: initVal
+ });
});
}
@@ -11572,7 +12450,9 @@
defVal += int(values.DEX);
defVal += int(values.DEF_BUFF);
defVal += int(values.DEFACT);
- setAttrs({ DEF: defVal });
+ setAttrs({
+ DEF: defVal
+ });
}
);
}
@@ -11604,7 +12484,9 @@
let depVal = 10;
depVal += int(values.CHA);
depVal += int(values.DEP_BUFF);
- setAttrs({ DEP: depVal });
+ setAttrs({
+ DEP: depVal
+ });
});
}
@@ -11747,6 +12629,7 @@
setBuffs[`${attr.toUpperCase()}_BUFF_LIST`] = buffs[attr];
}
setAttrs(setBuffs);
+ clog(setBuffs, "REBUILD BUFFS");
}
);
}
@@ -11816,142 +12699,67 @@
* Spaceships Buffs
*/
function attrBuff(attr) {
- let attrs = [];
- for (let b = 1; b < 6; b++) {
- attrs.push(`${attr}_BUFF${b}`);
- }
- return attrs;
+ return nameSeq(5, `${attr}_BUFF`);
}
function setBuff(v, buffAttr) {
let buffVal = 0;
- for (let attr = 1; attr < 6; attr++) {
- buffVal += int(v[`${buffAttr}_BUFF${attr}`]);
- }
- let buff = {};
+ attrBuff(buffAttr).forEach(attr => {
+ buffVal += int(v[attr]);
+ });
+ const buff = {};
buff[`${buffAttr}_BUFF`] = buffVal;
setAttrs(buff);
}
-on(
- [
- "change:for_buff1",
- "change:for_buff2",
- "change:for_buff3",
- "change:for_buff4",
- "change:for_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("FOR"), function (values) {
- setBuff(values, "FOR");
- });
- }
-);
+on(eventList("change", nameSeq(5, "for_buff"), " "), function () {
+ getAttrs(attrBuff("FOR"), function (values) {
+ setBuff(values, "FOR");
+ });
+});
-on(
- [
- "change:dex_buff1",
- "change:dex_buff2",
- "change:dex_buff3",
- "change:dex_buff4",
- "change:dex_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("DEX"), function (values) {
- setBuff(values, "DEX");
- });
- }
-);
+on(eventList("change", nameSeq(5, "dex_buff"), " "), function () {
+ getAttrs(attrBuff("DEX"), function (values) {
+ setBuff(values, "DEX");
+ });
+});
-on(
- [
- "change:con_buff1",
- "change:con_buff2",
- "change:con_buff3",
- "change:con_buff4",
- "change:con_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("CON"), function (values) {
- setBuff(values, "CON");
- });
- }
-);
-on(
- [
- "change:int_buff1",
- "change:int_buff2",
- "change:int_buff3",
- "change:int_buff4",
- "change:int_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("INT"), function (values) {
- setBuff(values, "INT");
- });
- }
-);
+on(eventList("change", nameSeq(5, "con_buff"), " "), function () {
+ getAttrs(attrBuff("CON"), function (values) {
+ setBuff(values, "CON");
+ });
+});
-on(
- [
- "change:per_buff1",
- "change:per_buff2",
- "change:per_buff3",
- "change:per_buff4",
- "change:per_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("PER"), function (values) {
- setBuff(values, "PER");
- });
- }
-);
+on(eventList("change", nameSeq(5, "int_buff"), " "), function () {
+ getAttrs(attrBuff("INT"), function (values) {
+ setBuff(values, "INT");
+ });
+});
-on(
- [
- "change:cha_buff1",
- "change:cha_buff2",
- "change:cha_buff3",
- "change:cha_buff4",
- "change:cha_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("CHA"), function (values) {
- setBuff(values, "CHA");
- });
- }
-);
+on(eventList("change", nameSeq(5, "per_buff"), " "), function () {
+ getAttrs(attrBuff("PER"), function (values) {
+ setBuff(values, "PER");
+ });
+});
-on(
- [
- "change:atktirv_buff1",
- "change:atktirv_buff2",
- "change:atktirv_buff3",
- "change:atktirv_buff4",
- "change:atktirv_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("ATKTIRV"), function (values) {
- setBuff(values, "ATKTIRV");
- });
- }
-);
+on(eventList("change", nameSeq(5, "cha_buff"), " "), function () {
+ getAttrs(attrBuff("CHA"), function (values) {
+ setBuff(values, "CHA");
+ });
+});
-on(
- [
- "change:pev_buff1",
- "change:pev_buff2",
- "change:pev_buff3",
- "change:pev_buff4",
- "change:pev_buff5",
- ].join(" "),
- function () {
- getAttrs(attrBuff("PEV"), function (values) {
- setBuff(values, "PEV");
- });
- }
-);
+on(eventList("change", nameSeq(5, "atktirv_buff"), " "), function () {
+ getAttrs(attrBuff("ATKTIRV"), function (values) {
+ setBuff(values, "ATKTIRV");
+ });
+});
+
+on(eventList("change", nameSeq(5, "pev_buff"), " "), function () {
+ getAttrs(attrBuff("PEV"), function (values) {
+ setBuff(values, "PEV");
+ });
+});
/**
* On changing the 'Blessure' checkbox
@@ -11960,8 +12768,8 @@
on("change:blessure", function () {
getAttrs(["BLESSURE"], function (values) {
var etatde = values.BLESSURE == "1" ? "12" : "20";
- setAttrs({
- ETATDE: etatde,
+ setAttrs({
+ ETATDE: etatde
});
});
});
@@ -12019,7 +12827,7 @@
* - Parse the statblock text
* - Create the NPC, starship or mecha character sheet
*/
-on("clicked:statblockimport", function () {
+on("clicked:sbimport-btn", function () {
getAttrs(
["UNIVERS", "type_fiche", "statblock", "character_name"],
function (values) {
@@ -12037,7 +12845,7 @@
sbObj = importMechaSB(values.statblock, values.character_name);
}
if (sbObj) {
- clog(sbObj, `statblock import -> ${values.type_fiche} object`);
+ clog(sbObj, `statblock import -> ${values.type_fiche.toUpperCase()} object`);
if (values.type_fiche === SHEET_STARSHIP) {
processShipAttributes(sbObj);
return;
@@ -12075,7 +12883,7 @@
// Other attributes go to DIVERS field
let divers = "";
let otherAttrs = Object.keys(sbObj);
- clog(otherAttrs, "statblock import -> additional data");
+ clog(otherAttrs, `${values.type_fiche.toUpperCase()} statblock import -> additional data`);
for (const other in otherAttrs) {
if (sbObj[other] !== undefined)
divers += other + " " + sbObj[other] + "\n";
@@ -12284,9 +13092,9 @@
/**
* Build hidden macro formulas for spaceship stations
-* @param {array} v Attributes list
+* @param {string[]} v Attributes list
* @param {string} attr Spaceship station shortname
-* @param {array} fill Fillers for attribute formulas
+* @param {string[]} fill Fillers for attribute formulas
*/
function setStation(v, attr, fill) {
let station = {};
@@ -12433,7 +13241,9 @@
if (poste_pil_oqp !== 0) {
initv = 10 + dex + poste_pil_dex + per + poste_sen_oqp * poste_sen_int;
}
- setAttrs({ INITV: initv });
+ setAttrs({
+ INITV: initv
+ });
}
);
}
@@ -12487,7 +13297,10 @@
poste_sen_oqp * poste_sen_int;
}
defsol = 10 + con + per_test + poste_sen_oqp * poste_sen_int;
- setAttrs({ DEFRAP: defrap, DEFSOL: defsol });
+ setAttrs({
+ DEFRAP: defrap,
+ DEFSOL: defsol
+ });
}
);
}
@@ -12519,24 +13332,30 @@
pev_max += int(values.PEV_BUFF);
pev_max += int(values.FOR);
pev_max -= int(values.PEV_DMG);
- let chatmsg = "";
if (pev > pev_max) {
- chatmsg = JSON.stringify({
- template: {
- id: "co1",
- props: [{ name: "text", value: "Trop de PE répartis" }],
- },
+ const chatMsg = coRollTemplate({
+ leftsub: "Energie",
+ rightsub: "Répartition",
+ desc: `${pev} PE répartis`,
+ alert: `PE Maximum : ${pev_max}`,
+
});
+ sendChatMsg(chatMsg, { template: "co1" });
}
- setAttrs({ PEV_max: pev_max, chatmsg: chatmsg });
+ setAttrs({
+ PEV_max: pev_max
+ });
}
);
}
on(
- ["change:niveau", "change:pev_buff", "change:for", "change:pev_dmg"].join(
- " "
- ),
+ [
+ "change:niveau",
+ "change:pev_buff",
+ "change:for",
+ "change:pev_dmg"
+ ].join(" "),
function () {
updateShipEP();
}
@@ -12584,7 +13403,8 @@
for (const attr in values) {
const ep = int(values[attr]);
ep_total += ep;
- epts[attr.split("_")[0].toUpperCase()] += ep;
+ const [ baseAttr ] = attr.split("_");
+ epts[baseAttr.toUpperCase()] += ep;
}
let attrs = {};
if (ep_total <= pev_max) {
@@ -12592,7 +13412,14 @@
} else {
const attr = eventInfo.sourceAttribute;
attrs[attr] = "0";
- epts[attr.split("_")[0].toUpperCase()]--;
+ const [ baseAttr ] = attr.split("_");
+ epts[baseAttr.toUpperCase()]--;
+ const chatMsg = coRollTemplate({
+ leftsub: "Energie",
+ rightsub: "Répartition",
+ alert: `PE Maximum : ${pev_max}`
+ })
+ sendChatMsg(chatMsg, { template: "co1" });
}
for (const attr in epts) {
attrs[`${attr}_BUFF1`] = epts[attr];
@@ -12608,16 +13435,15 @@
/**
* Initialize an array of abilities
* @param {string} voie path #
-* @returns Array of attribute names
+* @returns {string[]} Array of attribute names
*/
function attrRanks(voie) {
- let attrs = [];
- for (let r = 1; r < 6; r++) {
- attrs.push(`v${voie}r${r}`);
- attrs.push(`voie${voie}-t${r}`);
- attrs.push(`voie${voie}-${r}`);
- }
- return attrs;
+ return seq(5).reduce((attrRanks, rank) => {
+ attrRanks.push(`v${voie}r${rank}`);
+ attrRanks.push(`voie${voie}-t${rank}`);
+ attrRanks.push(`voie${voie}-${rank}`);
+ return attrRanks;
+ }, []);
}
/**
@@ -12626,18 +13452,16 @@
*/
function setRank(voie) {
getAttrs(attrRanks(voie), function (v) {
- let vr = 0;
- for (let r = 1; r < 6; r++) {
- const flag = int(v[`v${voie}r${r}`]);
- const title = stringOrDefault(v[`voie${voie}-t${r}`]);
- const text = stringOrDefault(v[`voie${voie}-${r}`]);
- if (flag === 1 && (title !== "" || text !== "")) {
- vr = r;
- }
- }
- let rank = {};
- rank[`RANG_VOIE${voie}`] = vr;
- setAttrs(rank);
+ let rank = 0;
+ seq(5).forEach(rn => {
+ const flag = int(v[`v${voie}r${rn}`]);
+ const title = stringOrDefault(v[`voie${voie}-t${rn}`]);
+ const text = stringOrDefault(v[`voie${voie}-${rn}`]);
+ if (flag === 1 && (title !== "" || text !== "")) rank = rn;
+ });
+ const ranks = {};
+ ranks[`RANG_VOIE${voie}`] = rank;
+ setAttrs(ranks);
buildCaracs();
});
}
@@ -12650,21 +13474,9 @@
on(
[
"change:voie1nom",
- "change:voie1-t1",
- "change:voie1-t2",
- "change:voie1-t3",
- "change:voie1-t4",
- "change:voie1-t5",
- "change:voie1-1",
- "change:voie1-2",
- "change:voie1-3",
- "change:voie1-4",
- "change:voie1-5",
- "change:v1r1",
- "change:v1r2",
- "change:v1r3",
- "change:v1r4",
- "change:v1r5",
+ ...eventList("change", nameSeq(5, "voie1-t")),
+ ...eventList("change", nameSeq(5, "voie1-")),
+ ...eventList("change", nameSeq(5, "v1r")),
].join(" "),
function () {
setRank("1");
@@ -12674,21 +13486,9 @@
on(
[
"change:voie2nom",
- "change:voie2-t1",
- "change:voie2-t2",
- "change:voie2-t3",
- "change:voie2-t4",
- "change:voie2-t5",
- "change:voie2-1",
- "change:voie2-2",
- "change:voie2-3",
- "change:voie2-4",
- "change:voie2-5",
- "change:v2r1",
- "change:v2r2",
- "change:v2r3",
- "change:v2r4",
- "change:v2r5",
+ ...eventList("change", nameSeq(5, "voie2-t")),
+ ...eventList("change", nameSeq(5, "voie2-")),
+ ...eventList("change", nameSeq(5, "v2r")),
].join(" "),
function () {
setRank("2");
@@ -12698,21 +13498,9 @@
on(
[
"change:voie3nom",
- "change:voie3-t1",
- "change:voie3-t2",
- "change:voie3-t3",
- "change:voie3-t4",
- "change:voie3-t5",
- "change:voie3-1",
- "change:voie3-2",
- "change:voie3-3",
- "change:voie3-4",
- "change:voie3-5",
- "change:v3r1",
- "change:v3r2",
- "change:v3r3",
- "change:v3r4",
- "change:v3r5",
+ ...eventList("change", nameSeq(5, "voie3-t")),
+ ...eventList("change", nameSeq(5, "voie3-")),
+ ...eventList("change", nameSeq(5, "v3r")),
].join(" "),
function () {
setRank("3");
@@ -12722,21 +13510,9 @@
on(
[
"change:voie4nom",
- "change:voie4-t1",
- "change:voie4-t2",
- "change:voie4-t3",
- "change:voie4-t4",
- "change:voie4-t5",
- "change:voie4-1",
- "change:voie4-2",
- "change:voie4-3",
- "change:voie4-4",
- "change:voie4-5",
- "change:v4r1",
- "change:v4r2",
- "change:v4r3",
- "change:v4r4",
- "change:v4r5",
+ ...eventList("change", nameSeq(5, "voie4-t")),
+ ...eventList("change", nameSeq(5, "voie4-")),
+ ...eventList("change", nameSeq(5, "v4r")),
].join(" "),
function () {
setRank("4");
@@ -12746,21 +13522,9 @@
on(
[
"change:voie5nom",
- "change:voie5-t1",
- "change:voie5-t2",
- "change:voie5-t3",
- "change:voie5-t4",
- "change:voie5-t5",
- "change:voie5-1",
- "change:voie5-2",
- "change:voie5-3",
- "change:voie5-4",
- "change:voie5-5",
- "change:v5r1",
- "change:v5r2",
- "change:v5r3",
- "change:v5r4",
- "change:v5r5",
+ ...eventList("change", nameSeq(5, "voie5-t")),
+ ...eventList("change", nameSeq(5, "voie5-")),
+ ...eventList("change", nameSeq(5, "v5r")),
].join(" "),
function () {
setRank("5");
@@ -12770,21 +13534,9 @@
on(
[
"change:voie6nom",
- "change:voie6-t1",
- "change:voie6-t2",
- "change:voie6-t3",
- "change:voie6-t4",
- "change:voie6-t5",
- "change:voie6-1",
- "change:voie6-2",
- "change:voie6-3",
- "change:voie6-4",
- "change:voie6-5",
- "change:v6r1",
- "change:v6r2",
- "change:v6r3",
- "change:v6r4",
- "change:v6r5",
+ ...eventList("change", nameSeq(5, "voie6-t")),
+ ...eventList("change", nameSeq(5, "voie6-")),
+ ...eventList("change", nameSeq(5, "v6r")),
].join(" "),
function () {
setRank("6");
@@ -12794,21 +13546,9 @@
on(
[
"change:voie7nom",
- "change:voie7-t1",
- "change:voie7-t2",
- "change:voie7-t3",
- "change:voie7-t4",
- "change:voie7-t5",
- "change:voie7-1",
- "change:voie7-2",
- "change:voie7-3",
- "change:voie7-4",
- "change:voie7-5",
- "change:v7r1",
- "change:v7r2",
- "change:v7r3",
- "change:v7r4",
- "change:v7r5",
+ ...eventList("change", nameSeq(5, "voie7-t")),
+ ...eventList("change", nameSeq(5, "voie7-")),
+ ...eventList("change", nameSeq(5, "v7r")),
].join(" "),
function () {
setRank("7");
@@ -12818,21 +13558,9 @@
on(
[
"change:voie8nom",
- "change:voie8-t1",
- "change:voie8-t2",
- "change:voie8-t3",
- "change:voie8-t4",
- "change:voie8-t5",
- "change:voie8-1",
- "change:voie8-2",
- "change:voie8-3",
- "change:voie8-4",
- "change:voie8-5",
- "change:v8r1",
- "change:v8r2",
- "change:v8r3",
- "change:v8r4",
- "change:v8r5",
+ ...eventList("change", nameSeq(5, "voie8-t")),
+ ...eventList("change", nameSeq(5, "voie8-")),
+ ...eventList("change", nameSeq(5, "v8r")),
].join(" "),
function () {
setRank("8");
@@ -12842,21 +13570,9 @@
on(
[
"change:voie9nom",
- "change:voie9-t1",
- "change:voie9-t2",
- "change:voie9-t3",
- "change:voie9-t4",
- "change:voie9-t5",
- "change:voie9-1",
- "change:voie9-2",
- "change:voie9-3",
- "change:voie9-4",
- "change:voie9-5",
- "change:v9r1",
- "change:v9r2",
- "change:v9r3",
- "change:v9r4",
- "change:v9r5",
+ ...eventList("change", nameSeq(5, "voie9-t")),
+ ...eventList("change", nameSeq(5, "voie9-")),
+ ...eventList("change", nameSeq(5, "v9r")),
].join(" "),
function () {
setRank("9");
@@ -12870,8 +13586,8 @@
getAttrs(["DEFARMUREON", "DEFARMUREMALUS"], function (values) {
let armure_on = int(values.DEFARMUREON);
let armure_malus = int(values.DEFARMUREMALUS);
- setAttrs({
- ARMURE_MALUS: armure_on * armure_malus,
+ setAttrs({
+ ARMURE_MALUS: armure_on * armure_malus
});
});
}
@@ -12930,9 +13646,7 @@
let portees = int(portee);
if (portees !== 0) {
setAttrs({
- repeating_armes_armeportees: `${portees}m | ${portees * 2}m (DM/2) | ${
- portees * 3
- }m (DM/3)`,
+ repeating_armes_armeportees: `${portees}m | ${portees * 2}m (DM/2) | ${ portees * 3 }m (DM/3)`
});
}
});
@@ -12976,7 +13690,6 @@
"target_def",
"target_dep"
], function (v) {
- console.log(v);
let targetdefp = "";
const armeatt = ( stringOrDefault(v["repeating_armes_armeatt"]) === "0" ) ? 0 : 1;
const armeatk = stringOrDefault(v["repeating_armes_armeatk"]);
@@ -12996,7 +13709,6 @@
break;
}
}
- console.log(targetdefp);
setAttrs({
repeating_armes_targetdefp: targetdefp,
});
@@ -13106,7 +13818,9 @@
*/
function encumbrance() {
getSectionIDs("repeating_equipement", function (ids) {
- setAttrs({ total_enc: 0 });
+ setAttrs({
+ total_enc: 0
+ });
const encombrement = {
total: 0,
zeros: 0,
@@ -13133,7 +13847,9 @@
} else {
encombrement.total += qte * enc;
}
- setAttrs({ total_enc: encombrement.total });
+ setAttrs({
+ total_enc: encombrement.total
+ });
}
}
);
@@ -13148,7 +13864,9 @@
getSectionIDs("repeating_equipement", function (ids) {
let matmod = "";
let matmod_desc = "-";
- setAttrs({ matmod, matmod_desc });
+ setAttrs({
+ matmod, matmod_desc
+ });
for (const id of ids) {
getAttrs(
[
@@ -13159,17 +13877,16 @@
],
function (values) {
const [ useK, descK, propsK ] = Object.keys(values);
+ const caracs = JSON.parse(values.CARACS);
const use = int(values[useK]);
if (use !== 1) return;
- const desc = stringOrDefault(values[desK]);
+ const desc = stringOrDefault(values[descK]);
const props = stringOrDefault(values[propsK]);
for (const prop of props.split(",")) {
const parsed = parseNameValue(prop);
const propName = parsed.name ? parsed.name.toUpperCase() : "";
if (propName === "MOD") {
- const propVal = int(
- buffValue(parsed.value, JSON.parse(values.CARACS))
- );
+ const propVal = int(buffValue(parsed.value, caracs));
if (propVal > matmod) {
matmod = propVal;
matmod_desc = desc;
@@ -13177,7 +13894,7 @@
}
}
const attrs = { matmod, matmod_desc };
- clog(attrs, "best gear bonus");
+ clog(attrs, "Best gear bonus");
setAttrs(attrs);
}
);
@@ -13402,18 +14119,18 @@
* - Attack and DM mods
*/
function rebuildAllPC() {
- for (const v of [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
+ for (const v of seq(9)) {
setRank(v.toString());
}
encumbrance();
buildCaracs();
- //rebuildCustom();
updateINIT();
updateDEF();
updateDEP();
rebuildBuffs();
rebuildModAtkDM("repeating_modatk", "armebuff");
rebuildModAtkDM("repeating_moddm", "armebuffdm");
+ //rebuildCustom();
}
/**
@@ -13428,7 +14145,11 @@
updateShipInit();
updateShipDEF();
starshipDMThreshold();
- setAttrs({ vehicle_starship: 1, vehicle_mecha: 0, sbresult: "" });
+ setAttrs({
+ vehicle_starship: 1,
+ vehicle_mecha: 0,
+ sbresult: ""
+ });
}
/**
@@ -13444,16 +14165,65 @@
const useCOGCrew = int(v.cogcrew) === 1 ? true : false;
const physical = vehicle ? "0" : "1";
const update = vehicle && useCOGCrew ? `update:${v.type_personnage}` : "";
- setAttrs({ physical, sbresult: "", cogcrew: v.cogcrew, POSTES_EQ: update });
+ setAttrs({
+ physical, sbresult: "",
+ cogcrew: v.cogcrew,
+ POSTES_EQ: update
+ });
+ });
+}
+
+
+/**
+ * Scan abilities for usage mention in description
+ */
+ function abilityUsage() {
+
+ const attrs = [];
+ seq(9).forEach(v => {
+ seq(5).forEach(r => {
+ attrs.push(`voie${v}-${r}`);
+ attrs.push(`v${v}r${r}_freq`);
+ });
});
+ getAttrs(attrs, function (values) {
+ const updatedAbilities = {};
+ const rx = new RegExp("([U|u]ne|[D|d]eux|[T|t]rois) fois par ([A-Za-z]+)","gm");
+ Object.keys(values).filter(v => v.endsWith("_freq")).forEach(value => {
+ if (stringOrDefault(values[value]) !== "") return; // already has a usage freq
+
+ const [ ability ] = value.split("_");
+ const abilityDesc = `voie${ ability.charAt(1) }-${ ability.charAt(3) }`;
+ const description = stringOrDefault(values[abilityDesc]);
+ if (description === "") return; // no description found
+
+ const matches = [ ...description.matchAll(rx) ];
+ if (matches.length === 0) return; // no regex match
+
+ const [ , use, freq ] = matches[0];
+ if ([ "round", "tour" ].includes(freq.toLowerCase())) return; // no per round usage
+
+ const use_max = [ "une", "deux", "trois" ].indexOf(use.toLowerCase()) + 1;
+ if (use_max > 0) {
+ updatedAbilities[`${ability}_use_max`] = use_max;
+ updatedAbilities[`${ability}_freq`] = freq;
+ }
+ });
+ if (Object.keys(updatedAbilities).length > 0) {
+ setAttrs(updatedAbilities);
+ }
+ clog(updatedAbilities, "ABILITY USAGE");
+ });
+
}
/**
* On clicking the Reset button
* - Rebuild derived attributes
*/
-on("clicked:resetattrib", function () {
+on("clicked:resetattrib-btn", function () {
rebuildAll();
+ abilityUsage();
});
/**
@@ -13484,7 +14254,7 @@
*/
function rebuildModAtkDM(section, buffAttr) {
getSectionIDs(section, function (ids) {
- const sectId = section.split("_")[1];
+ const [ , sectId ] = section.split("_");
let armebuff = "";
for (const id of ids) {
getAttrs(
@@ -13550,7 +14320,7 @@
/**
* Condition codes
*/
-const conditions = {
+const CONDITIONS = {
aveugle: "A",
blesse: "B",
confus: "C",
@@ -13566,7 +14336,7 @@
/**
* Condition modifiers
*/
-const conditions_data = {
+const CONDITIONS_INFO = {
"": {
atc: 0,
atd: 0,
@@ -13647,10 +14417,10 @@
function applyConditions(buffs, conditionAttr, s) {
if (conditionAttr === "") return;
for (let cond of conditionAttr) {
- buffs.atc += s * int(conditions_data[cond].atc);
- buffs.atd += s * int(conditions_data[cond].atd);
- buffs.def += s * int(conditions_data[cond].def);
- buffs.init += s * int(conditions_data[cond].init);
+ buffs.atc += s * int(CONDITIONS_INFO[cond].atc);
+ buffs.atd += s * int(CONDITIONS_INFO[cond].atd);
+ buffs.def += s * int(CONDITIONS_INFO[cond].def);
+ buffs.init += s * int(CONDITIONS_INFO[cond].init);
}
}
@@ -13670,21 +14440,10 @@
* On changing the enabled condition(s)
* - Set/Unset combat stats buffs
*/
-on(
- [
- "clicked:aveugle",
- "clicked:blesse",
- "clicked:confus",
- "clicked:effraye",
- "clicked:etourdi",
- "clicked:immobilise",
- "clicked:panique",
- "clicked:ralenti",
- "clicked:renverse",
- "clicked:surpris",
- ].join(" "),
+on(eventList("clicked", Object.keys(CONDITIONS), " "),
function (eventInfo) {
- var clickedCondition = conditions[eventInfo.triggerName.split(":")[1]];
+ const [ , clicked ] = eventInfo.triggerName.split(":");
+ const conditionCode = CONDITIONS[clicked];
getAttrs(
[
"PCONDITION",
@@ -13709,10 +14468,10 @@
applyConditions(buffs, pcondition, +1);
// change condition
let condition = stringOrDefault(values.CONDITION);
- if (condition.includes(clickedCondition)) {
- condition = condition.replace(clickedCondition, "");
+ if (condition.includes(conditionCode)) {
+ condition = condition.replace(conditionCode, "");
} else {
- condition += clickedCondition;
+ condition += conditionCode;
}
// buff new condition
applyConditions(buffs, condition, -1);
@@ -13722,45 +14481,45 @@
let mentde = values.MENTDE || "20";
if (
pcondition !== "" &&
- (pcondition.includes(conditions.immobilise) ||
- pcondition.includes(conditions.panique))
+ (pcondition.includes(CONDITIONS.immobilise) ||
+ pcondition.includes(CONDITIONS.panique))
) {
etatde = "20";
physde = "20";
mentde = "20";
}
- if (pcondition !== "" && pcondition.includes(conditions.blesse)) {
+ if (pcondition !== "" && pcondition.includes(CONDITIONS.blesse)) {
physde = "20";
}
- if (pcondition !== "" && pcondition.includes(conditions.confus)) {
+ if (pcondition !== "" && pcondition.includes(CONDITIONS.confus)) {
mentde = "20";
}
if (physde === "20" && mentde === "20") etatde = "20";
// check condition for die roll
if (
condition !== "" &&
- (condition.includes(conditions.immobilise) ||
- condition.includes(conditions.panique))
+ (condition.includes(CONDITIONS.immobilise) ||
+ condition.includes(CONDITIONS.panique))
) {
etatde = "12";
physde = "12";
mentde = "12";
}
- if (condition !== "" && condition.includes(conditions.blesse)) {
+ if (condition !== "" && condition.includes(CONDITIONS.blesse)) {
physde = "12";
}
- if (condition !== "" && condition.includes(conditions.confus)) {
+ if (condition !== "" && condition.includes(CONDITIONS.confus)) {
mentde = "12";
}
if (physde === "12" && mentde === "12") etatde = "12";
// build displayed conditions
let displayConditions = "";
if (condition !== "") {
- for (const cond of Object.keys(conditions)) {
- if (condition.includes(conditions[cond])) {
+ for (const cond of Object.keys(CONDITIONS)) {
+ if (condition.includes(CONDITIONS[cond])) {
displayConditions +=
(displayConditions === "" ? "" : ", ") +
- conditions_data[conditions[cond]].title;
+ CONDITIONS_INFO[CONDITIONS[cond]].title;
}
}
}
@@ -13791,7 +14550,9 @@
});
}
- setAttrs({ skills });
+ setAttrs({
+ skills
+ });
}
/**
@@ -13811,7 +14572,9 @@
const pv_buff = int(values.PV_BUFF);
pv_max += pv_buff;
- setAttrs({ PV_max: pv_max });
+ setAttrs({
+ PV_max: pv_max
+ });
});
}
@@ -13831,7 +14594,9 @@
const oldVal = int(eventInfo.previousValue);
const newVal = int(eventInfo.newValue);
getAttrs(["PV_max"], function (v) {
- setAttrs({ PV_max: int(v.PV_max) - oldVal + newVal });
+ setAttrs({
+ PV_max: int(v.PV_max) - oldVal + newVal
+ });
});
});
@@ -13843,14 +14608,13 @@
["type_personnage", "NIVEAU", "DV", "CON", "PV_BUFF"],
function (values) {
if (values.type_personnage !== SHEET_STARSHIP) return;
- clog(values, "starship DM threshold");
const niveau = int(values.NIVEAU, 1);
const dv = int(values.DV, 4);
const con = int(values.CON);
const buff = int(values.PV_BUFF);
const seuil_avarie = con + niveau + dv + buff;
const attr = { seuil_avarie };
- clog(attr, "starship DM threshold");
+ clog(attr, "STARSHIP DM threshold");
setAttrs(attr);
}
);
@@ -13969,7 +14733,9 @@
mec_froid_max += int(values.NIVEAU);
mec_froid_max += int(values.mec_cha);
mec_froid_max += int(values.mec_crew_cha);
- setAttrs({ mec_froid_max: mec_froid_max });
+ setAttrs({
+ mec_froid_max: mec_froid_max
+ });
});
}
@@ -14025,7 +14791,9 @@
getAttrs(["mec_dex", "mec_crew_dex", "mec_vitesse_base"], function (values) {
const dex = 1 + int(values.mec_dex) + int(values.mec_crew_dex);
const base = int(values.mec_vitesse_base);
- setAttrs({ mec_vitesse: dex * base });
+ setAttrs({
+ mec_vitesse: dex * base
+ });
});
}
@@ -14044,7 +14812,10 @@
const mec_pv_max = (dv + con) * niveau;
let mec_pv = int(values.mec_pv);
if (values.mec_pv === "") mec_pv = mec_pv_max;
- setAttrs({ mec_pv: mec_pv, mec_pv_max: mec_pv_max });
+ setAttrs({
+ mec_pv: mec_pv,
+ mec_pv_max: mec_pv_max
+ });
});
}
@@ -14094,7 +14865,11 @@
updateMechInitDef();
updateMechSpeed();
updateMechHP();
- setAttrs({ vehicle_starship: 0, vehicle_mecha: 1, sbresult: "" });
+ setAttrs({
+ vehicle_starship: 0,
+ vehicle_mecha: 1,
+ sbresult: ""
+ });
}
/**
@@ -14103,57 +14878,35 @@
function updateRuleOf4() {
getAttrs(
[
- "cp1mod",
- "cp2mod",
- "cp3mod",
- "cp4mod",
- "cp5mod",
- "cp6mod",
- "cp7mod",
- "cp8mod",
- "cp9mod",
- "RANG_VOIE1",
- "RANG_VOIE2",
- "RANG_VOIE3",
- "RANG_VOIE4",
- "RANG_VOIE5",
- "RANG_VOIE6",
- "RANG_VOIE7",
- "RANG_VOIE8",
- "RANG_VOIE9",
- "voie1nom",
- "voie2nom",
- "voie3nom",
- "voie4nom",
- "voie5nom",
- "voie6nom",
- "voie7nom",
- "voie8nom",
- "voie9nom",
"sitmod",
"matmod",
"matmod_desc",
+ ...nameSeq(9, "cp|mod"),
+ ...nameSeq(9, "RANG_VOIE"),
+ ...nameSeq(9, "voie|nom"),
],
function (values) {
let cmpmod = 0;
let cmpmod_desc = "";
- for (let v = 1; v <= 9; v++) {
+ seq(9).forEach(v => {
const use_rank = int(values[`cp${v}mod`]);
- if (use_rank !== 1) continue;
+ if (use_rank !== 1) return;
const rank = int(values[`RANG_VOIE${v}`]);
if (rank > cmpmod) {
cmpmod = rank;
cmpmod_desc = values[`voie${v}nom`] || "Compétence";
}
- }
- const sitmod = int(values.sitmod);
+ });
+ //const sitmod = int(values.sitmod);
const matmod = int(values.matmod);
const matmod_desc = values.matmod_desc || "Matériel";
let rof4 = "";
if (cmpmod > 0) rof4 += `+ ([[${cmpmod}]])[${cmpmod_desc}]`;
if (matmod > 0) rof4 += `+ ([[${matmod}]])[${matmod_desc}]`;
if (rof4 === "") rof4 = "+[[0]]";
- setAttrs({ rof4 });
+ setAttrs({
+ rof4
+ });
}
);
}
@@ -14163,15 +14916,7 @@
"change:sitmod",
"change:matmod",
"change:matmod_desc",
- "change:cp1mod",
- "change:cp2mod",
- "change:cp3mod",
- "change:cp4mod",
- "change:cp5mod",
- "change:cp6mod",
- "change:cp7mod",
- "change:cp8mod",
- "change:cp9mod",
+ ...eventList("change", nameSeq(9, "cp|mod")),
].join(" "),
function () {
updateRuleOf4();
@@ -14195,22 +14940,9 @@
});
setAttrs(skillRows);
});
- /*
- const abilities = Object.keys(SKILLS);
- const skillRows = {};
- abilities.forEach((ability) => {
- SKILLS[ability].forEach((skill) => {
- const skillRowID = "repeating_jetcapas_" + generateRowID();
- skillRows[`${skillRowID}_jetcapanom`] = "Compétence";
- skillRows[`${skillRowID}_jetcapacarac`] = `@{${ability}_TEST}`;
- skillRows[`${skillRowID}_jetcapatitre`] = `${skill.name} (${ability})`;
- skillRows[`${skillRowID}_jetcapadesc`] = skill.focus || "";
- });
- });
- setAttrs(skillRows); */
}
-on("clicked:addskills", function () {
+on("clicked:addskills-btn", function () {
createSkillList();
});
@@ -14239,5 +14971,211 @@
});
*/
+/**
+ * Display buff help
+ */
+ on("clicked:helpbuff-btn", function() {
+ sendChatMsg([
+ "Format=attribut : valeur (séparés par des ;)",
+ "Attributs=Noms & alias",
+ "Caracs:=FOR,DEX,CON,INT,PER,CHA",
+ "ATC:=Attaque au contact (alias: atkcac, cac, contact)",
+ "ATD:=Attaque à distance (alias : atktir, cad, distance, tir)",
+ "MAG:=Attaque Magique (alias : atkmag, magie)",
+ "PSYINF:=Attaque Psy Influence (alias : psyinflu)",
+ "PSYINT:=Attaque Psy Intuition (alias : psyintui)",
+ "INIT:=Initiative (alias : initiative)",
+ "DEF:=Défense",
+ "DEP:=Défense Psy",
+ "PV:=Points de Vie",
+ "SIT:XXX=MOD de situation carac XXX",
+ "Valeurs=---",
+ "Nombre=Buff/debuff fixe",
+ "[attribut]=Valeur de 'attribut'",
+ "[VOIE#]=Rang dans la voie no #",
+ "[rang {voie}]=Rang dans la voie nommée {voie} ",
+ ], {
+ title: "Aide BUFFS attributs",
+ whisper: "@{character_name}"
+ });
+});
+
+/**
+ * Display gear help
+ */
+on("clicked:helpgear-btn", function() {
+ sendChatMsg([
+ "Format=propriété:valeur (séparées par des ,)",
+ "DEF:=Bonus de DEF armure",
+ "DEF-:=Malus d'armure",
+ "RD:=Réduction DM",
+ "ATD:=Portée arme à distance",
+ "DM:=Dommages arme",
+ "MOD:=Bonus de matériel",
+ "Porté=Cocher pour inclure l'équipement dans l'encombrement",
+ "Utilisé=Cocher plusieurs équipements pour calcul du meilleur bonus de matériel",
+ "A une attaque=Cocher pour créer un ligne d'attaque",
+ ], {
+ title: "Aide propriétés d'équipement",
+ whisper: "@{character_name}"
+ });
+});
+
+/**
+ * Reset abilities usage
+ */
+on("clicked:resetuses-btn", function() {
+ const attrs = [];
+ seq(9).forEach(v => {
+ seq(5).forEach(r => {
+ attrs.push(`v${v}r${r}`);
+ attrs.push(`v${v}r${r}_use`);
+ attrs.push(`v${v}r${r}_freq`);
+ });
+ })
+ getAttrs(attrs, function(values) {
+ const freqs = [ "Aucune" ];
+ const owned = {};
+ const abilities = [];
+ for (const v in values) {
+ if (values[v] !== "") {
+ const [ ability, attr ] = v.split("_");
+ if (!attr) {
+ if (int(values[v]) === 1)
+ owned[ability] = 0;
+ continue;
+ } else if (attr === "use") {
+ if (owned.hasOwnProperty(ability))
+ owned[ability] = int(values[v]);
+ continue;
+ }
+ if (!owned.hasOwnProperty(ability)) continue;
+ if (owned[ability] === 0) continue;
+ const freq = capitalize(values[v]);
+ if (!freqs.includes(freq)) {
+ freqs.push(freq);
+ abilities[freq] = [];
+ }
+ abilities[freq].push(ability);
+ }
+ }
+ if (freqs.length === 1) {
+ const chatMsg = coRollTemplate({
+ leftsub: "Capacités",
+ rightsub: "Utilisations",
+ desc: "Aucune capacité avec nombre d'utilisations à recharger"
+ });
+ sendChatMsg(chatMsg, { template: "co1" });
+ return;
+ }
+ ask([ "Capacités ?", ...freqs], function(selected, choices) {
+ const freq = choices[selected];
+ const attrs = abilities[freq].map(attr => `voie${ attr.charAt(1) }-t${ attr.charAt(3) }`);
+ getAttrs(attrs, function(values) {
+ const chatMsg = coRollTemplate({
+ leftsub: "Capacités",
+ rightsub: `Par ${freq}`,
+ desc: Object.values(values).map(v => `${v}\n`).join("")
+ });
+ sendChatMsg(chatMsg, { template: "co1" });
+ const reset = {};
+ abilities[freq].forEach(attr => {
+ reset[attr + "_use"] = 0;
+ });
+ setAttrs(reset);
+ });
+ });
+ });
+});
+
+/**
+ * Display ability text with alert on usage
+ * @param {number} path - Path #
+ * @param {number} rank - Rank #
+ */
+function actionAbility(path, rank) {
+ getAttrs([ `v${path}r${rank}_use`, `v${path}r${rank}_use_max`, `v${path}r${rank}_freq` ], function(values) {
+ const [ kused, kuses, kfreq ] = Object.keys(values);
+ const used = int(values[kused]) + 1;
+ const uses = int(values[kuses]);
+ const freq = stringOrDefault(values[kfreq]);
+ let alert = "";
+ if (uses !== 0) {
+ if (used > uses) {
+ alert = `Déjà utilisée ${uses} fois / ${freq.toLowerCase()}`;
+ } else {
+ alert = `Utilisée ${used} fois`;
+ }
+ }
+ const chatMsg = [
+ "@{token_dsp}",
+ ...coRollTemplate({
+ leftsub: "Capacité ",
+ rightsub: `@{voie${path}-t${rank}} `,
+ desc: `**@{voie${path}nom}, rang ${rank}** `,
+ text: `@{voie${path}-${rank}} }}`
+ })
+ ];
+ if (alert !== "") chatMsg.push("alert=" + alert);
+ sendChatMsg(chatMsg, { template: "co1" });
+ if (used <= uses) {
+ const attr = {};
+ attr[kused] = used;
+ setAttrs(attr);
+ }
+ });
+}
+
+/**
+ * Handle ability buttons roll
+ */
+seq(9).forEach(path => {
+ seq(5).forEach(rank => {
+ on(`clicked:v${path}r${rank}-btn`, function() {
+ actionAbility(path, rank);
+ });
+ })
+});
+
+function changeHP(button) {
+ let prompt = (button === "hploss-btn") ? "PV perdus ?" : "PV soignés ?";
+ let plusminus = (button === "hploss-btn") ? -1 : +1;
+ //const ask = `!{{ask=[[?{${prompt}}]]}}`;
+ askValue(prompt, function(hp) {
+ if (hp <= 0) return;
+ getAttrs([ "type_personnage", "PV", "PV_max", "SEUILBG", "pnj_pv", "pnj_pv_max", "pnj_sbg" ], function (values) {
+ const type = stringOrDefault(values.type_personnage);
+ let pv = (type === SHEET_NPC) ? int(values.pnj_pv) : int(values.PV);
+ const pvMax = (type === SHEET_NPC) ? int(values.pnj_pv_max) : int(values.PV_max);
+ const bg = (type === SHEET_NPC) ? int(values.pnj_sbg) : int(values.SEUILBG);
+ let hasBG = (plusminus === -1 && hp >= bg) ? true : false;
+ pv += hp * plusminus;
+ if (pv < 0) {
+ pv = 0;
+ hasBG = true;
+ }
+ if (pv > pvMax) {
+ pv = pvMax;
+ }
+ const chatMsg = [
+ "@{token_dsp}",
+ ...coRollTemplate({
+ leftsub: "Vitalité ",
+ rightsub: `${ plusminus === -1 ? "Blessure" : "Soins" } `,
+ text : `@{character_name} ${ plusminus === -1 ? "perd" : "gagne" } ${hp} PV${hasBG ? " et subit une blessure grave" : "" } `
+ }),
+ ];
+ sendChatMsg(chatMsg, { template: "co1" });
+ const changedHP = (type === SHEET_NPC) ? { pnj_pv: pv } : { PV: pv };
+ setAttrs(changedHP);
+ });
+ });
+}
+
+on("clicked:hploss-btn clicked:hpheal-btn", function (eventInfo) {
+ const [ , button ] = eventInfo.triggerName.split(":");
+ changeHP(button);
+});
+
diff --git a/ChroniquesGalactiques/sheet.json b/ChroniquesGalactiques/sheet.json
index d01aca115128..4215ce280d28 100644
--- a/ChroniquesGalactiques/sheet.json
+++ b/ChroniquesGalactiques/sheet.json
@@ -4,7 +4,7 @@
"authors": "StéphaneD",
"roll20userid": "84776",
"preview": "cog_v4.png",
- "instructions": "Feuilles de personnage, pnj, vaisseau et mécha (avec jets de dés intégrés) pour Chroniques Oubliées Galactiques (http://www.black-book-editions.fr/catalogue.php?id=207). Version 4.6.0 (24/06/2024). [Lisez-moi](https://github.com/Roll20/roll20-character-sheets/blob/master/ChroniquesGalactiques/ReadMe.md).",
+ "instructions": "Feuilles de personnage, pnj, vaisseau et mécha (avec jets de dés intégrés) pour Chroniques Oubliées Galactiques (http://www.black-book-editions.fr/catalogue.php?id=207). Version 4.7.0 (24/08/2024). [Lisez-moi](https://github.com/Roll20/roll20-character-sheets/blob/master/ChroniquesGalactiques/ReadMe.md).",
"useroptions": [
{
"attribute": "cogcrew",
|