From 21753ee142b8aa45831e9203073dedab84b035ea Mon Sep 17 00:00:00 2001 From: TheLastScrub <67403321+TheLastScrub@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:11:13 -0700 Subject: [PATCH] added getting armor and attacks to stat parser --- lang/ca.json | 1 + lang/de.json | 1 + lang/en.json | 1 + lang/es.json | 1 + lang/fr.json | 1 + lang/ja.json | 1 + lang/pt-BR.json | 2 + module/actor/actor.js | 60 ++++++++ module/other/stat-parser-macro.js | 223 ++++++++++++++++++++++++++++++ 9 files changed, 291 insertions(+) diff --git a/lang/ca.json b/lang/ca.json index 6552316..f4893ae 100644 --- a/lang/ca.json +++ b/lang/ca.json @@ -43,6 +43,7 @@ "DG.Skills.swim": "Nedar", "DG.Skills.unarmed_combat": "Combat sense armes", "DG.Skills.unnatural": "Sobrenatural", + "DG.Skills.flight": "Flight", "DG.Skills.AddTypedOrCustomSkill": "Afegir tipus o habilitat personalitzada", "DG.Skills.AddSkill": "Afegir habilitat", diff --git a/lang/de.json b/lang/de.json index ca8c35e..ceb61fe 100644 --- a/lang/de.json +++ b/lang/de.json @@ -43,6 +43,7 @@ "DG.Skills.swim": "Schwimmen", "DG.Skills.unarmed_combat": "Waffenloser Kampf", "DG.Skills.unnatural": "Mythos", + "DG.Skills.flight": "Flight", "DG.Skills.AddTypedOrCustomSkill": "Eigene Fertigkeit hinzufügen", "DG.Skills.AddSkill": "Fertigkeit hinzufügen", diff --git a/lang/en.json b/lang/en.json index 20544c6..f5084da 100644 --- a/lang/en.json +++ b/lang/en.json @@ -44,6 +44,7 @@ "DG.Skills.swim": "Swim", "DG.Skills.unarmed_combat": "Unarmed Combat", "DG.Skills.unnatural": "Unnatural", + "DG.Skills.flight": "Flight", "DG.Skills.AddTypedOrCustomSkill": "Add Typed/Custom Skill", "DG.Skills.AddSkill": "Add Skill", diff --git a/lang/es.json b/lang/es.json index e0c4994..6da90c4 100644 --- a/lang/es.json +++ b/lang/es.json @@ -43,6 +43,7 @@ "DG.Skills.swim": "Nadar", "DG.Skills.unarmed_combat": "Combate sin Armas", "DG.Skills.unnatural": "Antinatural", + "DG.Skills.flight": "Flight", "DG.Skills.AddTypedOrCustomSkill": "Añadir Tipo o Habilidad Personalizada", "DG.Skills.AddSkill": "Añadir Habilidad", diff --git a/lang/fr.json b/lang/fr.json index 9f8cb62..9bc20d6 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -43,6 +43,7 @@ "DG.Skills.swim": "Natation", "DG.Skills.unarmed_combat": "Corps à corps", "DG.Skills.unnatural": "Paranaturel", + "DG.Skills.flight": "Flight", "DG.Skills.AddTypedOrCustomSkill": "Ajouter une compétence personnalisée", "DG.Skills.AddSkill": "Ajout Compétence", diff --git a/lang/ja.json b/lang/ja.json index b70d154..549fc97 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -43,6 +43,7 @@ "DG.Skills.swim": "泳ぎ", "DG.Skills.unarmed_combat": "非武装戦闘", "DG.Skills.unnatural": "不自然", + "DG.Skills.flight": "飛び", "DG.Skills.AddTypedOrCustomSkill": "スキルを加える", "DG.Skills.AddSkill": "スキルを加える", diff --git a/lang/pt-BR.json b/lang/pt-BR.json index 1d99f49..b9db68e 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -41,6 +41,8 @@ "DG.Skills.swim": "Nadar", "DG.Skills.unarmed_combat": "Combate Desarmado", "DG.Skills.unnatural": "Antinatural", + "DG.Skills.flight": "Flight", + "DG.Skills.AddTypedOrCustomSkill": "Adicionar Habilidade Personalizada", "DG.Skills.AddSkill": "Adicionar Habilidade", "DG.Skills.EditTypedOrCustomSkill": "Edit Typed or Custom Skill", diff --git a/module/actor/actor.js b/module/actor/actor.js index bf96c97..2fbee2f 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -363,4 +363,64 @@ export default class DeltaGreenActor extends Actor { console.log(ex); } } + + async AddArmorItemToSheet( + name, + description, + protection, + isEquipped, + expense = "NA", + ) { + const armorData = { + type: "armor", + name: name, + system: { + description: description, + protection: protection, + equipped: isEquipped, + expense: expense, + }, + }; + + await this.createEmbeddedDocuments("Item", [armorData]); + } + + async AddWeaponItemToSheet( + name, + description, + damage, + skill = "custom", + skillModifier = 0, + customSkillTarget = 50, + armorPiercing = 0, + lethality = 0, + isLethal = false, + range = "10M", + killRadius = "N/A", + ammo = "", + expense = "NA", + equipped = true, + ) { + const weaponData = { + type: "weapon", + name: name, + system: { + description: description, + skill: skill, //custom + skillModifier: skillModifier, + customSkillTarget: customSkillTarget, + range: range, + damage: damage, + armorPiercing: armorPiercing, + lethality: lethality, + isLethal: isLethal, + killRadius: killRadius, + ammo: ammo, + expense: expense, + equipped: equipped, + }, + }; + + await this.createEmbeddedDocuments("Item", [weaponData]); + } } diff --git a/module/other/stat-parser-macro.js b/module/other/stat-parser-macro.js index f6a4667..1be9956 100644 --- a/module/other/stat-parser-macro.js +++ b/module/other/stat-parser-macro.js @@ -1,3 +1,135 @@ +function GetAttacksFromInput(inputText) { + const attacks = []; + try { + // some attacks split onto multiple lines, usually separated by semicolons, + // try to get these back on the same line before splitting... + const lines = inputText + .replace("; \r\n", ";") + .replace(";\r\n", ";") + .replace(";\n", ";") + .replace("; \n", ";") + .split(/\r?\n/); + + let isInAttackSection = false; + + if (lines !== null && lines.length > 0) { + for (var i = 0; i < lines.length; i++) { + if (lines[i].toString().toUpperCase().indexOf("ATTACKS:") >= 0) { + isInAttackSection = true; + } else if ( + isInAttackSection && + lines[i].toString().toUpperCase().indexOf(":") > 0 + ) { + isInAttackSection = false; + } + + if (isInAttackSection) { + const attackLine = lines[i] + .toString() + .toUpperCase() + .replace("ATTACKS:", ""); + + console.log(attackLine); + + const weaponData = { + type: "weapon", + name: "New Attack", + description: attackLine, + system: { + skill: "custom", + skillModifier: 0, + customSkillTarget: 0, + range: "0M", + damage: "1D10", + armorPiercing: 0, + lethality: 0, + isLethal: false, + killRadius: "N/A", + ammo: "N/A", + expense: "NA", + equipped: true, + }, + }; + + // try to determine if it's a lethality attack, as those will have two % values in them + if (attackLine.indexOf("LETHALITY") >= 0) { + weaponData.isLethal = true; + + const lethalityMatchStr = "(\\w.*?)(\\d\\d?%)"; // test with 'Black box 50%, Lethality 40% (see BLACK BOX).' + const re = new RegExp(lethalityMatchStr, "i"); + const lethalityResults = attackLine.match(re); + + if ( + lethalityResults !== null && + lethalityResults.length > 0 && + lethalityResults[1] !== null && + lethalityResults[1] !== undefined + ) { + weaponData.name = lethalityResults[1].toString().trim(); + + weaponData.lethality = parseInt( + lethalityResults[2] + .toString() + .replace("%", "") + .replace(";", ""), + ); + } + } else { + // assume only percent value will be the skill test associated with it + const skillMatchStr = `(\\w.*?)(\\d?\\d%)([\\S\\s]*?damage\\s.*?)?(\\d?d\\d?\\d?\\d([\\+\\-]\\d+)?)?`; // test with 'SIG Sauer P228 pistol 94%, damage 1D10.' + const re1 = new RegExp(skillMatchStr, "i"); + const skillResults = attackLine.match(re1); + + if ( + skillResults !== null && + skillResults.length > 0 && + skillResults[1] !== null && + skillResults[1] !== undefined + ) { + weaponData.name = skillResults[1].toString().trim(); + + if ( + skillResults.length > 2 && + skillResults[2] !== null && + skillResults[2] !== undefined + ) { + weaponData.customSkillTarget = parseInt( + skillResults[2].toString().replace("%", "").replace(";", ""), + ); + } + + // have to be careful, some unnatural attacks don't actually deal damage, they just grab or something. + // don't have a great way to indicate that in the system, so just set it to zero if we can't find it. + if ( + skillResults.length > 4 && + skillResults[4] !== null && + skillResults[4] !== undefined + ) { + weaponData.damage = skillResults[4].toString().replace(";", ""); + } else { + weaponData.damage = 0; + } + } + + // look for armor piercing + if (attackLine.indexOf("ARMOR PIERCING") >= 0) { + } + } + + if (weaponData.customSkillTarget > 0 || weaponData.isLethal) { + attacks.push(weaponData); + } + } + } + } + } catch (ex) { + console.log("GetAttacksFromInput Error"); + console.log(ex); + } + + return attacks; +} + function GetNotesFromInput(inputText) { const matchStr = "(?:ATTACKS:[\\S\\s]*?\\.\\n)([\\S\\s]*)"; const re = new RegExp(matchStr, "gi"); @@ -17,6 +149,55 @@ function GetNotesFromInput(inputText) { return notes; } +function GetArmorFromInput(inputText) { + try { + let armor = { name: "Armor", description: "", armor: 0 }; + + const lines = inputText.split(/\r?\n/); + + if (lines !== null && lines.length > 0) { + for (var i = 0; i < lines.length; i++) { + if (lines[i].toString().toUpperCase().indexOf("ARMOR:") >= 0) { + armor.description = lines[i] + .replace("Armor:", "") + .replace("ARMOR:", "") + .trim(); + + const matchStr = `(\\d\\d?)`; + const re = new RegExp(matchStr, "i"); + const results = lines[i].match(re); + + try { + if (results != null && results.length > 0) { + armor.armor = parseInt(results[0]); + + armor.name = armor.description + .replace(`(Armor ${armor.armor})`, "") + .trim(); + + armor.name = armor.name + .replace(`${armor.armor} points of`, "") + .replace(`${armor.armor} point of`, "") + .replace(".", "") + .trim(); + } + } catch (ex) { + console.log("GetArmorFromInput Error"); + console.log(ex); + } + + return armor; + } + } + } + } catch (ex) { + console.log("GetArmorFromInput Error"); + console.log(ex); + } + return null; +} + +// this is the main stat call, it's exposed as part of the system itself for users to access // call this within a world as: game.deltagreen.ParseDeltaGreenStatBlock() function GetTypeSkillRatingsFromInput(inputText) { const matchStr = @@ -128,6 +309,14 @@ async function RegexParseNpcStatBlock(inputStr, actorType) { actorData.name = "Unknown"; } + let armor = GetArmorFromInput(inputStr); + + let attacks = GetAttacksFromInput(inputStr); + + if (armor !== null) { + console.log(armor); + } + if (actorType === "agent") { actorData.system.physical = { description: shortDescription, @@ -402,6 +591,40 @@ async function RegexParseNpcStatBlock(inputStr, actorType) { const newActors = await Actor.createDocuments([actorData]); + if (armor !== null) { + if (armor.description === null || armor.description.trim() === "") { + armor.description = "Armor"; + } + + await newActors[0].AddArmorItemToSheet( + armor.name, + armor.description, + armor.armor, + true, + ); + } + + if (attacks !== null && attacks.length > 0) { + for (const a of attacks) { + await newActors[0].AddWeaponItemToSheet( + a.name, + a.description, + a.damage, + a.skill, + a.skillModifier, + a.customSkillTarget, + a.armorPiercing, + a.lethality, + a.isLethal, + a.range, + a.killRadius, + a.ammo, + a.expense, + a.equipped, + ); + } + } + newActors[0].sheet.render(true); }