From cdefecdeba861146820d7cf1e66e1a6a3bec45df Mon Sep 17 00:00:00 2001 From: LeRatierBretonnien Date: Mon, 14 Jul 2025 21:33:32 +0200 Subject: [PATCH] New weapon management, including shotgun --- .../fr/fvtt-cthulhu-eternal.skills.json | 2 +- css/fvtt-cthulhu-eternal.css | 55 ++++++++++++- cthulhu-eternal.mjs | 3 +- lang/en.json | 61 ++++++++++++++- lang/fr.json | 65 ++++++++++++++-- macro_roll.js | 19 +++++ .../applications/sheets/protagonist-sheet.mjs | 1 + module/config/system.mjs | 50 +++++++++++- module/config/weapon.mjs | 3 +- module/documents/roll.mjs | 53 ++++++++++--- module/models/protagonist.mjs | 32 +++++--- module/models/weapon.mjs | 20 ++++- module/utils.mjs | 8 +- .../rituals/{000173.log => 000218.log} | 0 packs-system/rituals/CURRENT | 2 +- packs-system/rituals/LOG | 10 +-- packs-system/rituals/LOG.old | 14 ++-- .../{MANIFEST-000171 => MANIFEST-000217} | Bin 173 -> 156 bytes .../skills/{000342.log => 000387.log} | 0 packs-system/skills/CURRENT | 2 +- packs-system/skills/LOG | 10 +-- packs-system/skills/LOG.old | 14 ++-- .../{MANIFEST-000340 => MANIFEST-000386} | Bin 178 -> 160 bytes packs-system/weapons/000014.ldb | Bin 0 -> 92437 bytes packs-system/weapons/000032.log | Bin 0 -> 87798 bytes packs-system/weapons/CURRENT | 1 + packs-system/weapons/LOCK | 0 packs-system/weapons/LOG | 3 + packs-system/weapons/LOG.old | 8 ++ packs-system/weapons/MANIFEST-000031 | Bin 0 -> 157 bytes styles/global.less | 17 ++++ styles/protagonist.less | 18 ++++- styles/weapon.less | 18 +++++ system.json | 12 +++ templates/chat-lethal-damage.hbs | 6 +- templates/chat-message.hbs | 73 ++++++++++-------- templates/chat-regular-damage.hbs | 6 +- templates/chat-san-loss-none.hbs | 8 ++ templates/chat-san-loss-unnatural.hbs | 8 ++ templates/chat-san-request.hbs | 6 +- templates/protagonist-equipment.hbs | 63 +++++++++++++-- templates/roll-dialog.hbs | 69 +++++++++++++++-- templates/weapon.hbs | 44 +++++++++-- 43 files changed, 651 insertions(+), 133 deletions(-) create mode 100644 macro_roll.js rename packs-system/rituals/{000173.log => 000218.log} (100%) rename packs-system/rituals/{MANIFEST-000171 => MANIFEST-000217} (73%) rename packs-system/skills/{000342.log => 000387.log} (100%) rename packs-system/skills/{MANIFEST-000340 => MANIFEST-000386} (71%) create mode 100644 packs-system/weapons/000014.ldb create mode 100644 packs-system/weapons/000032.log create mode 100644 packs-system/weapons/CURRENT create mode 100644 packs-system/weapons/LOCK create mode 100644 packs-system/weapons/LOG create mode 100644 packs-system/weapons/LOG.old create mode 100644 packs-system/weapons/MANIFEST-000031 create mode 100644 templates/chat-san-loss-none.hbs create mode 100644 templates/chat-san-loss-unnatural.hbs diff --git a/compendiums/fr/fvtt-cthulhu-eternal.skills.json b/compendiums/fr/fvtt-cthulhu-eternal.skills.json index fc578ab..7b3c68d 100644 --- a/compendiums/fr/fvtt-cthulhu-eternal.skills.json +++ b/compendiums/fr/fvtt-cthulhu-eternal.skills.json @@ -20,7 +20,7 @@ "entries": { "Pilot (Type)": { "name": "Pilotage (Type)", - "description": "" + "description": "

Piloter, naviguer et diriger des véhicules nautiques ou aériens. Utilisez cette compétence pour assurer la sécurité d'un navire en cas de danger, par exemple lors d'une tempête ou d'une poursuite dangereuse. Chaque type de véhicule requiert une compétence distincte : Avion, Drone, Hélicoptère, Dirigeable, Petite embarcation, Navire, etc.

" }, "Anthropology": { "name": "Anthropologie", diff --git a/css/fvtt-cthulhu-eternal.css b/css/fvtt-cthulhu-eternal.css index 427ccfa..3f6a743 100644 --- a/css/fvtt-cthulhu-eternal.css +++ b/css/fvtt-cthulhu-eternal.css @@ -183,6 +183,25 @@ i.fvtt-cthulhu-eternal { color: var(--color-critical-failure); font-family: var(--font-title); } +.chat-san-request ul .san-type-buttons, +.chat-lethal-damage ul .san-type-buttons { + display: flex; + justify-content: center; + align-items: center; + margin: 10px 0; +} +.chat-san-request ul .san-type-buttons button, +.chat-lethal-damage ul .san-type-buttons button { + margin: 0 2px; + font-family: var(--font-primary); + font-size: calc(var(--font-size-standard) * 0.9); + border: none; + padding: 2px 2px; + cursor: pointer; + transition: background-color 0.3s; + min-width: 6rem; + max-width: 6rem; +} .chat-san-request ul .san-loose-buttons, .chat-lethal-damage ul .san-loose-buttons { display: flex; @@ -804,7 +823,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons { display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(1, 1fr); gap: 4px; } .fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon { @@ -824,10 +843,24 @@ i.fvtt-cthulhu-eternal { min-width: 1.8rem; max-width: 1.8rem; } -.fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .damage { +.fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .range { min-width: 6rem; max-width: 6rem; } +.fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .ammo { + min-width: 4rem; + max-width: 4rem; +} +.fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .lethality { + display: flex; + min-width: 3.2rem; + max-width: 3.2rem; +} +.fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .damage { + display: flex; + min-width: 12rem; + max-width: 12rem; +} .fvtt-cthulhu-eternal .tab.protagonist-equipment .main-div .weapons .weapon .name { min-width: 10rem; max-width: 10rem; @@ -2153,6 +2186,24 @@ i.fvtt-cthulhu-eternal { margin-top: 8px; background-color: var(--color-light-1); } +.fvtt-cthulhu-eternal .weapon-content fieldset input { + max-width: 5rem; + min-width: 5rem; +} +.fvtt-cthulhu-eternal .weapon-content fieldset select { + max-width: 14rem; + min-width: 14rem; +} +.fvtt-cthulhu-eternal .weapon-content fieldset input[type="checkbox"] { + max-width: 1.5rem; + min-width: 1.5rem; +} +.fvtt-cthulhu-eternal .weapon-content fieldset .flexrow > *:not(:first-child) { + margin-left: 1rem; +} +.fvtt-cthulhu-eternal .weapon-content fieldset .damage-distance { + margin-left: 2rem; +} .fvtt-cthulhu-eternal .weapon-content label { flex: 10%; } diff --git a/cthulhu-eternal.mjs b/cthulhu-eternal.mjs index 1d4cd52..2912868 100644 --- a/cthulhu-eternal.mjs +++ b/cthulhu-eternal.mjs @@ -151,7 +151,8 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => { CthulhuEternalUtils.nudgeRoll(message) }) $(html).find(".damage-roll").click((event) => { - CthulhuEternalUtils.damageRoll(message) + let formula = $(event.currentTarget).data("roll-value") + CthulhuEternalUtils.damageRoll(message, formula) }) $(html).find(".healing-roll").click((event) => { CthulhuEternalUtils.healingRoll(message) diff --git a/lang/en.json b/lang/en.json index 99ff463..73e5d5f 100644 --- a/lang/en.json +++ b/lang/en.json @@ -212,6 +212,7 @@ "UnarmedCombat": "Unarmed Combat", "RangedWeapons": "Ranged Weapons", "FirearmsBeams": "Firearms / Beam Weapons", + "MilitaryTrainingExplosive": "Military Training (Explosives)", "FIELDS": { "isHealing": { "label": "Healing skill" @@ -268,7 +269,8 @@ "rangedprimitive": "Ranged Primitive", "rangedthrown": "Ranged Thrown", "rangedfirearm": "Ranged Firearm", - "unarmed": "Unarmed" + "unarmed": "Unarmed", + "rangedexplosive": "Explosive" }, "WeaponSubtype": { "basicfirearm": "Basic Firearm", @@ -283,7 +285,41 @@ "shortspray": "Short Spray", "longspray": "Long Spray" }, + "Target": { + "Normal": "Normal", + "Stationary": "Stationary", + "MovingRange": "Moving or on the ground", + "MovingFast": "Moving Fast (ie running)", + "MovingVeryFast": "Moving Very Fast", + "HalfCovered": "Half Covered", + "Covered": "Full Covered" + }, + "Range": { + "PointBlank": "Point Blank", + "Normal": "Normal", + "Range2x": "Up to Range x2", + "Range5x": "Up to Range x5" + }, + "Visibility": { + "Clear": "Clear", + "Obscured": "Obscured", + "Darkness": "Darkness" + }, + "Attacker": { + "Normal": "Normal", + "Irritated": "Irritated/Annoyed", + "Corrosive": "Deeply Annoyed" + }, "FIELDS": { + "hasDamageDistance": { + "label": "Is damage distance based?" + }, + "hasSight": { + "label": "Has sight" + }, + "isStunning": { + "label": "Is Stunning" + }, "hasDirectSkill": { "label": "Has direct skill" }, @@ -526,11 +562,14 @@ "Unnatural": "Unnatural", "sanLossViolence": "You suffered a SAN loss due to violence : violence progress path has evolved.", "sanLossHelplessness": "You suffered a SAN loss due to helplessness : helplessness progress path has evolved.", + "SANLossUnnatural": "You suffered a SAN loss due to unnatural : you may gain an Unnatural skill, check with the GM.", + "SANLossNone": "You suffered a SAN loss, but no special consequences apply.", "adaptedToViolence": "You are now : Adapted to Violence.", "adaptedToViolenceShort": "Adapted to Violence", "adaptedToHelplessness": "You are now : Adapted to Helplessness.", "adaptedToHelplessnessShort": "Adapted to Helplessness", - "SANTest": "You just rolled a SAN test : please select the SAN loss with the buttons below.", + "SANTestSuccess": "You just rolled a SAN test with success, but you may still loose SAN points. Select the value of SAN loss with the buttons below.", + "SANTestFailure": "You just rolled a SAN test with failure, you loose SAN points. Select the value of SAN loss with the buttons below.", "breakingPointReached": "Your SAN has reached your Breaking Point : you suffer a disorder (to be discussed with the GM). Reset the BP to its new value.", "rollNudge": "Roll Nudge", "rollDamage": "Roll Damage", @@ -613,6 +652,11 @@ "biography": "Biography", "notes": "Notes", "weapons": "Weapons", + "melee": "Melee", + "Lethality": "Lethality", + "baseRange": "Base Range", + "Ammo": "Ammo", + "armorPiercing": "Armor Piercing", "HP": "HP", "SAN": "SAN", "current": "Current", @@ -678,7 +722,15 @@ "killRadiusInfo": "All targets within the kill radius suffer the damage", "ammoUsed": "Ammo used", "lethalityLethal": "Lethal !!", - "lethalityNotLethal": "Non-Lethal" + "lethalityNotLethal": "Non-Lethal", + "WPSpent": "WP Spent", + "targetMove": "Target Move", + "attackerState": "Attacker State", + "targetSize": "Target Size", + "visibility": "Visibility", + "rangedRange": "Range", + "aimingLastRound": "Aiming Last Round (+20)", + "aimingWithSight": "Aiming with Sight (+20)" }, "ChatMessage": { "exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points." @@ -699,7 +751,8 @@ "Tooltip": { "sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP.", "setBP": "Set the current Breaking Point based on the current SAN value", - "addBond": "Add a new Bond" + "addBond": "Add a new Bond", + "rollDamage": "Roll Damage" }, "Chat": { }, diff --git a/lang/fr.json b/lang/fr.json index bf23b2a..06483c0 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -224,6 +224,7 @@ "UnarmedCombat": "Combat à mains nues", "RangedWeapons": "Armes de tir", "FirearmsBeams": "Armes à feu / à rayons", + "MilitaryTrainingExplosive": "Entraînement militaire (Explosifs)", "FIELDS": { "isHealing": { "label": "Compétence de soin" @@ -280,7 +281,8 @@ "rangedprimitive": "A distance - Primitive", "rangedthrown": "A distance - Lancer", "rangedfirearm": "A distance - Arme à feu", - "unarmed": "Non armé" + "unarmed": "Non armé", + "rangedexplosive": "Explosif" }, "WeaponSubtype": { "basicfirearm": "Arme à feu de base", @@ -295,7 +297,41 @@ "shortspray": "Barrage court", "longspray": "Barrage long" }, + "Target": { + "Normal": "Normal", + "Stationary": "Immobile (+20)", + "MovingRange": "En mouvement ou au sol (-20)", + "MovingFast": "En mouvement rapide (ie course) (-20)", + "MovingVeryFast": "En mouvement très rapide (ie véhicule) (-40)", + "HalfCovered": "A moitié couvert (-20)", + "Covered": "A Couvert (-40)" + }, + "Range": { + "PointBlank": "Bout portant (+20)", + "Normal": "Normal", + "Range2x": "de portée à portée x2 (-20)", + "Range5x": "de portéex2 à portée x5 (-40)" + }, + "Visibility": { + "Clear": "Normale", + "Obscured": "Obscurci (-20)", + "Darkness": "Obscurité (-40)" + }, + "Attacker": { + "Normal": "Normal", + "Irritated": "Irrité/Gêné (-20)", + "Corrosive": "Fortement gêné (-40)" + }, "FIELDS": { + "hasDamageDistance": { + "label": "Dégâts basés sur la distance ?" + }, + "hasSight": { + "label": "Lunette de visée" + }, + "isStunning": { + "label": "Etourdissante" + }, "ammo": { "label": "Munitions", "value": { @@ -531,17 +567,20 @@ "sanLoss5": "Perte de SAN de 5+ ({value}) : vous souffrez d'une folie temporaire (Fuite, Soumission, Lutte ou compréhension de l'Inconcevable).", "sanViolenceReset": "Le décompte des pertes de SAN de violence a été réinitialisé.", "sanHelplessnessReset": "Le décompte des pertes de SAN d'impuissance a été réinitialisé.", - "sanLoss": "Perte de SAN", + "sanLoss": "Vous venez de perdre des points de SAN", "noSanLoss": "Aucune perte de SAN", "sanLossInfo": "Sélectionnez la perte de SAN à l'aide des boutons ci-dessous.", - "selectSANType": "Sélectionnez le type de perte de SAN à l'aide des boutons ci-dessous.", + "selectSANType": "Sélectionnez maintenant le type SAN perdue à l'aide des boutons ci-dessous.", "sanLossViolence": "Vous avez subi une perte de SAN due à la violence : le chemin de progression de la violence a évolué.", "sanLossHelplessness": "Vous avez subi une perte de SAN due à l'impuissance : le chemin de progression de l'impuissance a évolué.", + "SANLossUnnatural": "Vous avez subi une perte de SAN due à l'inconcevable : vous pouvez peut-être faire progresser la compétence Inconcevable, vérifiez avec le MJ.", + "SANLossNone": "Vous avez subi une perte de SAN, mais aucune conséquence spéciale n'est appliquée.", "adaptedToViolence": "Vous êtes maintenant : Habitué à la violence", "adaptedToViolenceShort": "Habitué à la violence", "adaptedToHelplessness": "Vous êtes maintenant : Habitué à l'impuissance", "adaptedToHelplessnessShort": "Habitué à l'impuissance", - "SANTest": "Vous venez de faire un jet de SAN : selectionnez la perte de SAN à l'aide des boutons ci-dessous.", + "SANTestSuccess": "Vous venez de réussir votre jet de SAN, mais vous pouvez toujours perdre des points de SAN. Sélectionnez la valeur à l'aide des boutons ci-dessous.", + "SANTestFailure": "Vous venez d'échouer votre test de SAN, vous perdez des points de SAN. Sélectionnez la valeur à l'aide des boutons ci-dessous.", "breakingPointReached": "Vous avez atteint votre Point de Rupture (PR) : vous souffrez d'un trouble mental. Vous devez re-initialiser votre PR à l'aide du bouton disponible dans la section SAN de la fiche de PJ.", "Violence" : "Violence", "Helplessness": "Impuissance", @@ -627,6 +666,11 @@ "biography": "Biographie", "notes": "Notes", "weapons": "Armes", + "melee": "Mêlée", + "Lethality": "Létalité", + "baseRange": "Portée de base", + "Ammo": "Munitions", + "armorPiercing": "Pénétration d'armure", "HP": "PV", "SAN": "SAN", "current": "Actuel", @@ -692,7 +736,15 @@ "killRadiusInfo": "Si la cible est dans le rayon de mortalité, elle subit les dommages.", "ammoUsed": "Munitions utilisées", "lethalityLethal": "Létal !!", - "lethalityNotLethal": "Non létal" + "lethalityNotLethal": "Non létal", + "WPSpent": "PVO dépensés", + "targetMove": "Mouvement de la cible", + "attackerState": "Etat de l'attaquant", + "targetSize": "Taille de la cible", + "visibility": "Visibilité", + "rangedRange": "Portée", + "aimingLastRound": "Visée lors du dernier round (+20)", + "aimingWithSight": "Visée avec lunette (+20)" }, "ChatMessage": { "exhausted": "Votre protagoniste est épuisé. Il perd [[/r 1d6]] Points de Volonté." @@ -713,7 +765,8 @@ "Tooltip": { "sanBP": "Perte de 5+ SAN en 1 jet : folie temporaire. SI la SAN atteint le PR : trouble mental, perte de conscience et reset du PR.", "setBP": "Positionner le Point de Rupture à la valeur courant de la SAN", - "addBond": "Ajouter une Attache" + "addBond": "Ajouter une Attache", + "rollDamage": "Lancer les dégâts" }, "Chat": { }, diff --git a/macro_roll.js b/macro_roll.js new file mode 100644 index 0000000..2e864be --- /dev/null +++ b/macro_roll.js @@ -0,0 +1,19 @@ +let nb = 10000 +let sum = 0 +let results = [] +for (let i = 0; i < nb; i++) { + let r = new Roll("1d100") + await r.evaluate() + sum += r.total + results.push(r.total) +} + +let mean = sum / nb +let variance = results.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / nb +let stddev = Math.sqrt(variance) + +console.log("Average : ", mean) +console.log("Standard deviation : ", stddev) +console.log("Coefficient of variation : ", stddev / mean ) +console.log("Min : ", Math.min(...results)) +console.log("Max : ", Math.max(...results)) \ No newline at end of file diff --git a/module/applications/sheets/protagonist-sheet.mjs b/module/applications/sheets/protagonist-sheet.mjs index 1eeebcb..e3c7ad4 100644 --- a/module/applications/sheets/protagonist-sheet.mjs +++ b/module/applications/sheets/protagonist-sheet.mjs @@ -225,6 +225,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS case "damage": li = $(event.currentTarget).parents(".item"); item = this.actor.items.get(li.data("item-id")); + item.damageFormula = $(event.currentTarget).data("roll-value") || item.system.damage item.damageBonus = this.actor.system.damageBonus break case "san": diff --git a/module/config/system.mjs b/module/config/system.mjs index bc36cd8..3acc9b1 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -154,7 +154,8 @@ export const WEAPON_SKILL_MAPPING = { "rangedprimitive": "CTHULHUETERNAL.Skill.Firearms", "rangedthrown": "CTHULHUETERNAL.Skill.Athletics", "rangedfirearm": "CTHULHUETERNAL.Skill.Firearms", - "unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat" + "unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat", + "rangedexplosive": "CTHULHUETERNAL.Skill.MilitaryTrainingExplosive" }, victorian: { "melee": "CTHULHUETERNAL.Skill.Melee", @@ -245,6 +246,45 @@ export const WEAPON_SELECTIVE_FIRE_CHOICES = { "longspray": { id: "longspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longspray", ammoUsed: 20, lethality: 10, killRadius: 3}, } +// Melee stuff +export const WEAPON_MELEE_TARGET_MOVE = { + "normal": { id: "normal", label: "CTHULHUETERNAL.Weapon.Target.Normal", modifier: 0 }, + "stationary": { id: "stationary", label: "CTHULHUETERNAL.Weapon.Target.Stationary", modifier: 20 }, + "movingfast": { id: "movingfast", label: "CTHULHUETERNAL.Weapon.Target.MovingFast", modifier: -20 }, + "movingveryfast": { id: "movingveryfast", label: "CTHULHUETERNAL.Weapon.Target.MovingVeryFast", modifier: -40 }, +} +// Ranged stuff +export const WEAPON_RANGED_RANGE = { + "pointblank": { id: "pointblank", label: "CTHULHUETERNAL.Weapon.Range.PointBlank", modifier: +20 }, + "normal": { id: "normal", label: "CTHULHUETERNAL.Weapon.Range.Normal", modifier: 0 }, + "range2x": { id: "range2x", label: "CTHULHUETERNAL.Weapon.Range.Range2x", modifier: -20 }, + "range5x": { id: "range5x", label: "CTHULHUETERNAL.Weapon.Range.Range5x", modifier: -40 } +} +export const WEAPON_RANGED_TARGET_MOVE = { + "normal": { id: "normal", label: "CTHULHUETERNAL.Weapon.Target.Normal", modifier: 0 }, + "stationary": { id: "stationary", label: "CTHULHUETERNAL.Weapon.Target.Stationary", modifier: 20 }, + "movingfast": { id: "movingfast", label: "CTHULHUETERNAL.Weapon.Target.MovingRange", modifier: -20 }, + "movingveryfast": { id: "movingveryfast", label: "CTHULHUETERNAL.Weapon.Target.MovingVeryFast", modifier: -40 }, +} + +// Common stuff +export const WEAPON_ATTACKER_STATE = { + "normal": { id: "normal", label: "CTHULHUETERNAL.Weapon.Target.Normal", modifier: 0 }, + "irritated": { id: "irritated", label: "CTHULHUETERNAL.Weapon.Attacker.Irritated", modifier: -20 }, + "corrosive": { id: "corrosive", label: "CTHULHUETERNAL.Weapon.Attacker.Corrosive", modifier: -40 }, +} +export const WEAPON_TARGET_SIZE = { + "normal": { id: "normal", label: "CTHULHUETERNAL.Weapon.Target.Normal", modifier: 0 }, + "halfcovered": { id: "halfcovered", label: "CTHULHUETERNAL.Weapon.Target.HalfCovered", modifier: -20 }, + "covered": { id: "covered", label: "CTHULHUETERNAL.Weapon.Target.Covered", modifier: -40 }, +} +export const WEAPON_VISIBILITY = { + "clear": { id: "clear", label: "CTHULHUETERNAL.Weapon.Visibility.Clear", modifier: 0 }, + "obscured": { id: "obscured", label: "CTHULHUETERNAL.Weapon.Visibility.Obscured", modifier: -20 }, + "darkness": { id: "darkness", label: "CTHULHUETERNAL.Weapon.Visibility.Darkness", modifier: -40 }, +} + + export const RITUAL_TYPES = { "simple": "CTHULHUETERNAL.Ritual.Simple", "difficult": "CTHULHUETERNAL.Ritual.Difficult", @@ -277,5 +317,11 @@ export const SYSTEM = { MULTIPLIER_CHOICES, ASCII, DAMAGE_BONUS, - RITUAL_TYPES + RITUAL_TYPES, + WEAPON_MELEE_TARGET_MOVE, + WEAPON_RANGED_RANGE, + WEAPON_RANGED_TARGET_MOVE, + WEAPON_ATTACKER_STATE, + WEAPON_TARGET_SIZE, + WEAPON_VISIBILITY } diff --git a/module/config/weapon.mjs b/module/config/weapon.mjs index 26fbbfa..a5060b2 100644 --- a/module/config/weapon.mjs +++ b/module/config/weapon.mjs @@ -3,7 +3,8 @@ export const WEAPON_TYPE = { "rangedprimitive": "CTHULHUETERNAL.Weapon.WeaponType.rangedprimitive", "rangedthrown": "CTHULHUETERNAL.Weapon.WeaponType.rangedthrown", "rangedfirearm": "CTHULHUETERNAL.Weapon.WeaponType.rangedfirearm", - "unarmed": "CTHULHUETERNAL.Weapon.WeaponType.unarmed" + "unarmed": "CTHULHUETERNAL.Weapon.WeaponType.unarmed", + "rangedexplosive": "CTHULHUETERNAL.Weapon.WeaponType.rangedexplosive", } export const WEAPON_SUBTYPE = { diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index c7c726d..aac278a 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -106,7 +106,7 @@ export default class CthulhuEternalRoll extends Roll { } static buildSelectiveFireChoices(actor, weapon) { - if (!weapon || !weapon?.system?.hasSelectiveFire) { + if (!weapon?.system?.hasSelectiveFire) { return {} } // Loop thru the selective fire choices and build the choices object when enough ammo in the weapon @@ -144,6 +144,8 @@ export default class CthulhuEternalRoll extends Roll { ammoUsed = choice.ammoUsed // Override ammo used } + ammoUsed = Number(ammoUsed) + if (weapon.system.lethality > 0) { let lethalityRoll = new Roll("1d100") await lethalityRoll.evaluate() @@ -175,8 +177,8 @@ export default class CthulhuEternalRoll extends Roll { } // If the weapon is not lethal, we can proceed with the regular damage roll - let formula = weapon.system.damage - if (weapon.system.weaponType === "melee" || weapon.system.weaponType === "unarmed") { + let formula = weapon?.damageFormula || weapon.system.damage || "0" + if (weapon.system.applyDamageBonus) { formula += ` + ${actor.system?.damageBonus}` } if (options?.previousResultType === "successCritical") { @@ -205,6 +207,19 @@ export default class CthulhuEternalRoll extends Roll { }, { rollMode: options.rollMode, create: true }) } + + static computeWeaponModifiers(rollData) { + let modifier = SYSTEM.WEAPON_MELEE_TARGET_MOVE[rollData.meleeTargetMoveChoice]?.modifier || 0 + modifier += SYSTEM.WEAPON_RANGED_RANGE[rollData.rangedRangeChoice]?.modifier || 0 + modifier += SYSTEM.WEAPON_RANGED_TARGET_MOVE[rollData.rangedTargetMoveChoice]?.modifier || 0 + modifier += SYSTEM.WEAPON_VISIBILITY[rollData.visibilityChoice]?.modifier || 0 + modifier += SYSTEM.WEAPON_ATTACKER_STATE[rollData.attackerStateChoice]?.modifier || 0 + modifier += SYSTEM.WEAPON_TARGET_SIZE[rollData.targetSizeChoice]?.modifier || 0 + modifier += (rollData.aimingLastRound) ? 20 : 0 + modifier += (rollData.aimingWithSight) ? 20 : 0 + return modifier + } + /** * Prompt the user with a dialog to configure and execute a roll. * @@ -311,6 +326,7 @@ export default class CthulhuEternalRoll extends Roll { rollType: options.rollType, rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class weapon: options?.weapon, + isRangedWeapon: options?.weapon?.system?.isRanged(), initialScore: options.initialScore, targetScore: options.initialScore, isLowWP: options.isLowWP, @@ -324,12 +340,26 @@ export default class CthulhuEternalRoll extends Roll { choiceModifier, choiceMultiplier, choiceSelectiveFire, + choiceMeleeTargetMove: SYSTEM.WEAPON_MELEE_TARGET_MOVE, + choiceRangedRange: SYSTEM.WEAPON_RANGED_RANGE, + choiceRangedTargetMove: SYSTEM.WEAPON_RANGED_TARGET_MOVE, + choiceVisibility: SYSTEM.WEAPON_VISIBILITY, + choiceAttackerState: SYSTEM.WEAPON_ATTACKER_STATE, + choiceTargetSize: SYSTEM.WEAPON_TARGET_SIZE, + selectiveFireChoice: "shortburst", + meleeTargetMoveChoice: "normal", + rangedRangeChoice: "normal", + rangedTargetMoveChoice: "normal", + visibilityChoice: "clear", + attackerStateChoice: "normal", + targetSizeChoice: "normal", + aimingLastRound: false, + aimingWithSight: false, + modifier, formula, hasTarget: options.hasTarget, hasModifier, hasMultiplier, - modifier, - selectiveFireChoice: "shortburst", multiplier } const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext) @@ -386,7 +416,9 @@ export default class CthulhuEternalRoll extends Roll { if (options.rollType === "resource") { rollData.targetScore = options.initialScore * Number(rollContext.multiplier) } else { - rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100) + let totalModifier = this.computeWeaponModifiers(rollData) + Number(rollData.modifier) + rollData.totalModifier = Math.min(totalModifier, 40) + rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.totalModifier), 0), 100) if (rollData.isLowWP || rollData.isExhausted) { rollData.targetScore -= 20 } @@ -395,7 +427,7 @@ export default class CthulhuEternalRoll extends Roll { } rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100) } - if (!rollData.targetScore) { + if (rollData.targetScore === undefined || rollData.targetScore === null) { rollData.targetScore = options.initialScore rollData.modifier = "0" } @@ -456,6 +488,7 @@ export default class CthulhuEternalRoll extends Roll { this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical" } rollData.resultType = resultType + this.options.isLowWP = rollData.isLowWP this.options.isZeroWP = rollData.isZeroWP this.options.isExhausted = rollData.isExhausted @@ -601,12 +634,14 @@ export default class CthulhuEternalRoll extends Roll { rollItem: rollItem, rollData: rollData } + // Get array of gamemaster ID let msg = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-san-request.hbs", msgData) let chatMsg = await ChatMessage.create({ user: game.user.id, content: msg, - speaker: ChatMessage.getSpeaker({ actor: rollData.actor }) - }, { rollMode: rollData.rollMode, create: true }) + speaker: ChatMessage.getSpeaker({ actor: rollData.actor }), + whisper: game.users.filter(u => u.isGM).map(u => u.id), + }) await chatMsg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData) } } diff --git a/module/models/protagonist.mjs b/module/models/protagonist.mjs index 5c53a74..3be2484 100644 --- a/module/models/protagonist.mjs +++ b/module/models/protagonist.mjs @@ -90,6 +90,10 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData prepareDerivedData() { super.prepareDerivedData(); + if (!game.user.isGM ) { + return + } + let updates = {} if (this.wp.max !== this.characteristics.pow.value) { updates[`system.wp.max`] = this.characteristics.pow.value @@ -123,8 +127,6 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData dmgBonus = -2 } else if (this.characteristics.str.value <= 8) { dmgBonus = -1 - } else if (this.characteristics.str.value <= 12) { - dmgBonus = 0 } else if (this.characteristics.str.value <= 16) { dmgBonus = 1 } else if (this.characteristics.str.value <= 20) { @@ -137,9 +139,12 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData // BP (Breaking Point) management if (!this.san.breakingPointReached && this.san.value <= this.san.breakingPoint) { updates[`system.san.breakingPointReached`] = true + this.san.breakingPointReached = true // Force local update to true ChatMessage.create({ content: `

${game.i18n.format("CTHULHUETERNAL.Label.breakingPointReached", { bp: this.san.breakingPoint, san: this.san.value })}

`, - speaker: ChatMessage.getSpeaker({ actor: this.parent }) + speaker: ChatMessage.getSpeaker({ actor: this.parent }), + // Get the user id of the actor owner + whisper: [game.users.find(u => u.character?.name === this.parent?.name).id ] }) } @@ -195,10 +200,6 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData } async applySANConsequences(rollData) { - // If sanType is "non", do nothing - if (rollData.sanType === "none") { - return - } let msgData = { sanType: rollData.sanType, sanLoss: rollData.sanLoss, @@ -265,14 +266,21 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData updates[`system.san.helplessness`] = [false, false, false] msgData.adaptedToHelplessness = true } + } else if (rollData.sanType === "unnatural" ) { + template = "systems/fvtt-cthulhu-eternal/templates/chat-san-loss-unnatural.hbs" + } else { + template = "systems/fvtt-cthulhu-eternal/templates/chat-san-loss-none.hbs" } + console.log("CthulhuEternalProtagonist.applySANConsequences", rollData, updates, template) let content = await foundry.applications.handlebars.renderTemplate(template, msgData) let msg = await ChatMessage.create({ content: content, - speaker: ChatMessage.getSpeaker({ actor: this.parent }) + speaker: ChatMessage.getSpeaker({ actor: this.parent }), + whisper: game.users.filter(u => u.isGM).map(u => u.id), }) - msg.setFlag("fvtt-cthulhu-eternal", "rollData", msgData) + await msg.setFlag("fvtt-cthulhu-eternal", "rollData", msgData) + if (Object.keys(updates).length > 0) { this.parent.update(updates) } @@ -284,12 +292,14 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData let san = Math.max(Math.min(this.san.value + rollData.sanLoss, this.san.max), 0) if (this.san.value !== san) { updates[`system.san.value`] = san + rollData.sanValue = san const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-san-type-request.hbs", rollData) let msg = await ChatMessage.create({ content: content, - speaker: ChatMessage.getSpeaker({ actor: this.parent }) + speaker: ChatMessage.getSpeaker({ actor: this.parent }), + whisper: game.users.filter(u => u.isGM).map(u => u.id) }) - msg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData) + await msg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData) } if (Object.keys(updates).length > 0) { this.parent.update(updates) diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index a6709a6..ab55b36 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -13,12 +13,23 @@ export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel schema.weaponType = new fields.StringField({ required: true, initial: "melee", choices: SYSTEM.WEAPON_TYPE }) schema.hasDirectSkill = new fields.BooleanField({ required: true, initial: false }) - schema.directSkillValue = new fields.NumberField({ required: true, initial: 0, min: 0, max:99 }) + schema.directSkillValue = new fields.NumberField({ required: true, initial: 0, min: 0, max: 99 }) + + schema.hasDamageDistance = new fields.BooleanField({ required: true, initial: false }) + schema.damageDistance = new fields.SchemaField(Array.fromRange(6, 1).reduce((damageDistance, i) => { + damageDistance[`dist${i}`] = new fields.SchemaField({ + damage: new fields.StringField({ required: true, initial: "1d6" }), + distance: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + }) + return damageDistance + }, {})); schema.hasSelectiveFire = new fields.BooleanField({ required: true, initial: false }) - schema.damage = new fields.StringField({required: true, initial: "1d6"}) + schema.hasSight = new fields.BooleanField({ required: true, initial: false }) + schema.isStunning = new fields.BooleanField({ required: true, initial: false }) + schema.damage = new fields.StringField({ required: true, initial: "1d6" }) schema.applyDamageBonus = new fields.BooleanField({ required: true, initial: false }) - schema.baseRange = new fields.StringField({required: true, initial: ""}) + schema.baseRange = new fields.StringField({ required: true, initial: "" }) schema.rangeUnit = new fields.StringField({ required: true, initial: "yard", choices: SYSTEM.WEAPON_RANGE_UNIT }) schema.lethality = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.killRadius = new fields.NumberField({ required: true, initial: 0, min: 0 }) @@ -43,7 +54,8 @@ export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel } isRanged() { - return this.weaponType.includes("ranged") + console.log("isRanged", this.weaponType, this) + return this.weaponType.match("ranged") } isFireArm() { diff --git a/module/utils.mjs b/module/utils.mjs index 5963bcf..b7a7833 100644 --- a/module/utils.mjs +++ b/module/utils.mjs @@ -196,11 +196,6 @@ export default class CthulhuEternalUtils { ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noSanTypeFound")) return } - // If the sanType is "none", we don't apply any SAN processing - if (sanType === "none") { - ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.noSanLossApplied")) - return - } rollData.sanType = sanType await actor.system.applySANConsequences(rollData) // Delete the roll message @@ -253,7 +248,7 @@ export default class CthulhuEternalUtils { }) } - static async damageRoll(rollMessage) { + static async damageRoll(rollMessage, formula = null) { let rollData = rollMessage.rolls[0]?.options?.rollData let actor = game.actors.get(rollData.actorId) if (!actor) { @@ -263,6 +258,7 @@ export default class CthulhuEternalUtils { console.log("Damage roll data", rollData) rollData.weapon.resultType = rollData.resultType // Keep the result type from the roll message rollData.weapon.selectiveFireChoice = rollData.selectiveFireChoice // Keep the selected fire choice from the roll message + rollData.weapon.damageFormula = formula || rollData.weapon.system.damage actor.system.roll("damage", rollData.weapon) } diff --git a/packs-system/rituals/000173.log b/packs-system/rituals/000218.log similarity index 100% rename from packs-system/rituals/000173.log rename to packs-system/rituals/000218.log diff --git a/packs-system/rituals/CURRENT b/packs-system/rituals/CURRENT index 91e41f4..9aabe0c 100644 --- a/packs-system/rituals/CURRENT +++ b/packs-system/rituals/CURRENT @@ -1 +1 @@ -MANIFEST-000171 +MANIFEST-000217 diff --git a/packs-system/rituals/LOG b/packs-system/rituals/LOG index e163bbe..cc9592c 100644 --- a/packs-system/rituals/LOG +++ b/packs-system/rituals/LOG @@ -1,7 +1,3 @@ -2025/07/09-17:04:59.082095 7f2a0effd6c0 Recovering log #169 -2025/07/09-17:04:59.092675 7f2a0effd6c0 Delete type=3 #167 -2025/07/09-17:04:59.092780 7f2a0effd6c0 Delete type=0 #169 -2025/07/09-17:18:46.206680 7f276ffff6c0 Level-0 table #174: started -2025/07/09-17:18:46.206717 7f276ffff6c0 Level-0 table #174: 0 bytes OK -2025/07/09-17:18:46.235941 7f276ffff6c0 Delete type=0 #172 -2025/07/09-17:18:46.287862 7f276ffff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/07/14-21:08:15.948300 7f3fa67fc6c0 Recovering log #215 +2025/07/14-21:08:15.959041 7f3fa67fc6c0 Delete type=3 #213 +2025/07/14-21:08:15.959103 7f3fa67fc6c0 Delete type=0 #215 diff --git a/packs-system/rituals/LOG.old b/packs-system/rituals/LOG.old index 05e4dad..3a6458c 100644 --- a/packs-system/rituals/LOG.old +++ b/packs-system/rituals/LOG.old @@ -1,7 +1,7 @@ -2025/06/29-22:25:29.091880 7fda6d9f96c0 Recovering log #165 -2025/06/29-22:25:29.103184 7fda6d9f96c0 Delete type=3 #163 -2025/06/29-22:25:29.103305 7fda6d9f96c0 Delete type=0 #165 -2025/06/29-22:26:56.370766 7fda5bbff6c0 Level-0 table #170: started -2025/06/29-22:26:56.370832 7fda5bbff6c0 Level-0 table #170: 0 bytes OK -2025/06/29-22:26:56.379673 7fda5bbff6c0 Delete type=0 #168 -2025/06/29-22:26:56.380010 7fda5bbff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/07/14-10:18:19.443254 7f3fa77fe6c0 Recovering log #211 +2025/07/14-10:18:19.474975 7f3fa77fe6c0 Delete type=3 #209 +2025/07/14-10:18:19.475128 7f3fa77fe6c0 Delete type=0 #211 +2025/07/14-20:48:52.882063 7f3fa57fa6c0 Level-0 table #216: started +2025/07/14-20:48:52.882164 7f3fa57fa6c0 Level-0 table #216: 0 bytes OK +2025/07/14-20:48:52.889652 7f3fa57fa6c0 Delete type=0 #214 +2025/07/14-20:48:52.915102 7f3fa57fa6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) diff --git a/packs-system/rituals/MANIFEST-000171 b/packs-system/rituals/MANIFEST-000217 similarity index 73% rename from packs-system/rituals/MANIFEST-000171 rename to packs-system/rituals/MANIFEST-000217 index 66c5cfabed0df2ddadc34ac3194e26b9a2e07c74..6431ccbde89d46c58f48c19b3bc326c39b73376c 100644 GIT binary patch delta 24 fcmZ3>IEQgUx1eMBOGz#UMy6YgoD9sj8CgsKTe${0 delta 41 rcmbQkxR!B3w-W3A`+8gqj7)17IT@JOGP0PI=>~Fv1lEEC)&m6q+vNze diff --git a/packs-system/skills/000342.log b/packs-system/skills/000387.log similarity index 100% rename from packs-system/skills/000342.log rename to packs-system/skills/000387.log diff --git a/packs-system/skills/CURRENT b/packs-system/skills/CURRENT index 757ec85..0884887 100644 --- a/packs-system/skills/CURRENT +++ b/packs-system/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000340 +MANIFEST-000386 diff --git a/packs-system/skills/LOG b/packs-system/skills/LOG index 5d2a756..4e8fe04 100644 --- a/packs-system/skills/LOG +++ b/packs-system/skills/LOG @@ -1,7 +1,3 @@ -2025/07/09-17:04:59.062504 7f2a0dffb6c0 Recovering log #338 -2025/07/09-17:04:59.072990 7f2a0dffb6c0 Delete type=3 #336 -2025/07/09-17:04:59.073130 7f2a0dffb6c0 Delete type=0 #338 -2025/07/09-17:18:46.236069 7f276ffff6c0 Level-0 table #343: started -2025/07/09-17:18:46.236095 7f276ffff6c0 Level-0 table #343: 0 bytes OK -2025/07/09-17:18:46.287671 7f276ffff6c0 Delete type=0 #341 -2025/07/09-17:18:46.287875 7f276ffff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/07/14-21:08:15.916959 7f3fa5ffb6c0 Recovering log #384 +2025/07/14-21:08:15.927715 7f3fa5ffb6c0 Delete type=3 #382 +2025/07/14-21:08:15.927846 7f3fa5ffb6c0 Delete type=0 #384 diff --git a/packs-system/skills/LOG.old b/packs-system/skills/LOG.old index 4f901d0..ddad229 100644 --- a/packs-system/skills/LOG.old +++ b/packs-system/skills/LOG.old @@ -1,7 +1,7 @@ -2025/06/29-22:25:29.069935 7fda6d1f86c0 Recovering log #334 -2025/06/29-22:25:29.081064 7fda6d1f86c0 Delete type=3 #332 -2025/06/29-22:25:29.081192 7fda6d1f86c0 Delete type=0 #334 -2025/06/29-22:26:56.360514 7fda5bbff6c0 Level-0 table #339: started -2025/06/29-22:26:56.360577 7fda5bbff6c0 Level-0 table #339: 0 bytes OK -2025/06/29-22:26:56.370559 7fda5bbff6c0 Delete type=0 #337 -2025/06/29-22:26:56.379992 7fda5bbff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/07/14-10:18:19.359761 7f3fa67fc6c0 Recovering log #380 +2025/07/14-10:18:19.394536 7f3fa67fc6c0 Delete type=3 #378 +2025/07/14-10:18:19.394680 7f3fa67fc6c0 Delete type=0 #380 +2025/07/14-20:48:52.889840 7f3fa57fa6c0 Level-0 table #385: started +2025/07/14-20:48:52.889882 7f3fa57fa6c0 Level-0 table #385: 0 bytes OK +2025/07/14-20:48:52.896159 7f3fa57fa6c0 Delete type=0 #383 +2025/07/14-20:48:52.915114 7f3fa57fa6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/MANIFEST-000340 b/packs-system/skills/MANIFEST-000386 similarity index 71% rename from packs-system/skills/MANIFEST-000340 rename to packs-system/skills/MANIFEST-000386 index 30160094397e1a816b0671efcb451699e7a4671b..5c2b1ff6f24e02f35090775eab6879ab29516a53 100644 GIT binary patch delta 25 gcmdnQxPWm&pU|CfmKJUXMy6(FP6p-{W|lqN0AK(HG5`Po delta 43 tcmZ3$xQTH>pGw%wi;mn3j7(RVI2o9)F|q97)}GIt1QNLh61f2q0RRoj3i1E| diff --git a/packs-system/weapons/000014.ldb b/packs-system/weapons/000014.ldb new file mode 100644 index 0000000000000000000000000000000000000000..bec309b074182332289844ea3a4f7e588b5103eb GIT binary patch literal 92437 zcmdpf3w)F1-FEIhZJsu5W32@%0ydRXp{+@pW96+RZPN28J$HM%JxQLVNpom(YEuUa zNI4fMw44!&GDSfYP*FFBdp&)deAB5LZqwoSZLdy2ok!e=-~WD|oSL-2u(Trb@HiV5v0sHWtDkI4C<>`12atM$_4?G}YsDxZ$S; zr_JfgDROviw!9p-)8(-^%<%6i_@f_MjBu;?$DC65#z?yjE=!Nc;&i|dbCMPHIYq*} z9FvVQyK{=}Tnc~P?V&s!&iVk6X4-(}%>9|kO;kEi{wvS933#VXr%>QT zaIH9j=Ds@WChB((g+{xy z`(`CpZzmLnk{+d}U)H8B@A7!y70&coh>nvev&IP@VMoDnlx`>#(<1)Sq}t=C*vBy) zM;v9~IAT}s@pOe)Tqy5^zo!rvN=5sQqv}J1Ql=ZA2f8SCgV%28sP97ieO-jLgjcTe zdYpF3V=-h?4r6vXP5Jys8+gU*IHng-z)Qfo;3e$dKm#wQfd{_;m7}#@V=a?*n8Z3$ zm(z}x_`JlD9KTEJ@)mkbW=%_57rb46eVZHeE~YAEa-qpbB+nXsn_E3Xl!{G0TZ`Es zkvc0?^5#UKapJz&QF!g zR(kX$64S0eH#A^aA=E`{!5X=!y*U9tgD8O8^h4ST(FZs$I=O*V<%B&tt~N%#dV6- z0h!%vaH9anbrM6zPxAL?19a5TMhopr{8j!#a5>2g5`_dkUwaI(ms5fQL&izGE}VqR zIbE&<0EFu)Q?8VXgn7G8V#uiIv#Ip@_BM4bWp;X-v6&K4;%=3r zuupm7h1vKc$38>&>VPXnZK3 zXmZg=?>mJ$-sI*5fwz&e*xctfPG6M-z^kAXQXzHj$;x#}ELw630|1%K$~~1JlRGvg zrNSN{J@gj0wAv~WHFea}_2M3-$Y<7~+3(Ive9jemgF?^8Vn349Qo;j#v=a$qMDc^% z1VAQ0L_4v#-s$#at9qOU%I1f?&rr}yWC~4Ui9y`aOBCPDF+GVMTp0KnV%LhFp#+(7 zmy3Y6W+!3L)@i#ut&O??t4Y&bjx@f7iM8(}yz+lu*q+3xg^L4U%?#MXZz=c0z`Vr! zOGaG;06{}jx4lhTSSbwQ$O1dR=xM2lm$^b6Iz*xwJc|8-WwYk}WS1QhZYzW0}X zId^jedn2IG;A#`K`z*c+XH#W~NM%I*h=V3#6AMD*0P}~L9~TFy1AM$&oi292$gYSG z3HYEZ6k>x3elii8Xehdqvm}mAq$$#KibQx1Exk%gasL%5MSqA=EW27@5D*bgksAgE zg`!XiM2F=R+F6`A(n5J&P86|NJ_$NB)_bel^mci-bD-KR?{c9#k>E-FDO8#hyKCo2 zU(5>PYyKJZ)7+oue#miGK8-NqKOMn{+>^o0{3L=8E5O5EqS@rAFDvu)$V&|+daI!e zl>$7#XC?NcQl1RL!wH11n-g$FQg-&Txo`^Qo=TU=F<&`_@AwpgjXd_lhW-PtO3Ur) z`H87oug5$0dAlAiMYWmEqZXCGC1-kr zo29h?&ve;`?@21|;{+Z->~cJUUOC!g#6b862EwgGdrOPaNmWvf9VU&-??kr_97T&` zcT>ONv7@L6?&m0Cm+L6vNF4qoctuB1!akztWJ&_s?t7lw(Vw*N-Zb(4v~;0DDH8Kr zlWLbGRf31c~IFr(1Cg6i1DU=+#E2-2hE-#lj%N4b%I*qrctscEF z&_$Sj$$jpF6wGND(1WiIJMqeqmJ{&%9)>J)Xz+UkWC zL{Cm1%son7cZ*(IYVWD6P;}EF`tamGNgq)4e=G7J7b;|v)g4RQ;_D9Hjr)im*-Dgv z?qbMy?sBL$?#0zc2>^>5DkWRC#zmngavy=KOhW5Lv#ghN^}?7l;vGuKq8V1u#| zQ>{U`nulg3G919(-P-MKZ}1!Jc2y%)hS0#w#Ko~#S9Bab_Fx*P4}Q7P&x$RD^sfTk z4V}Qh+TBEKp@P2eJBc`sj78TS;m@slN4ANK1rGWNlGeH)jWYxp#~9;{v<8J7&2b^@TVW#>fzjSfh({;Jr2zW zk;Sd8bL!OgQm07X-h}D^1wJ0UGl%U?0O^k1i`Z))cP7-7-|3(|@PlBhqK|1m!1oqA zZZ^0X=I*|2BHDf%To1IzeVfGq{R-ym57~cR;P#o}9)eAZdpQX?d1=k1(29s@RiK;e zX%FsdK${|mGSg0z8yF@0<(6JT5QX zgPwBJ0Dp-KQ{k_;P)b{~!{UMG;-_3j_=%17bWt{o$Di1PhEsKv(Sp>AfpEa4<8;+q zXqN$=d!m5TH@7RP(W}qz&x1R(7)LBW6h2>fw?o>5oTzv$p@@MP^oV`!0;Z{u-2-o~6HTv~ zUNMi86Br_v4i(+UkqQNmJBEmazCJ-o@@D%QI+0^+KM~kW6mKRHL}J|*qULPDFaf=x zz&1j+jgStheh2?HdJPW|=?Vp~qs}4Rpcx{{zv4D@Rm(eSJdL&WbynX%EqadLSa2h$ zh$#wAbL>NTOZ7omsh=;CK?B4%|Zi^%gR) zk?7b+1O#OCdRssOJ5xwSom=q}*h-WKxLs}1QgM~j+}EcQQLP4aNWGO%#Pnbm9_Gz~ zMi%YLHc&48^y`uXIix;^EV`c)7$NA9z+Cc^xzjiDa!&9LWs`#fG6^bL@#8$esz;Lt zPw}!{786`Zl#9yW5y&H>*H|8D|8dJxxE|X{RA1s+Wabiob&s@3t1Q!WwWB?NI}1zr zOJb2aC#QseJ}6)7Y1|J5WF#Eg(4x-5$d7^Ma>&>5Wag zere!mJl)TD0TCI!-W8Flg+l0liAccS9Z~$~hR=UIxN|<>;`uNx+G>RZKC!-{vZBw@ zR#Ahx;Q2in1&gs;5qxl=lESc9V)N?ZJHSN5FO7#pq`&)$h?vaf{4lv#I35f4Tpbn~ zLR14|A*U&MDxeTulmHYi!dGVy45v>FhIv;4Ll@dMIT+^Vr2-Usl7BlM3waC{?g(Sy zCzE60|Bk}KbQTM3fQ4yOj)jj-0T#|mXS(C6Cn~mbDpWtH9sQo*cFjrXgeM3K1b@hm z;NZnD4$6f}@#S#vM@yHISr@q?as7a|TUjb?(fZ8g9aSg;1L5Mn7~bLs9K;<~vx|06 zM!|)e8!P4m4sId*TZ#b(MS>?BTZnWhk!crNm%Pq&Js6zOOuz%#2%+0d)cmes z3kJg#TZtr*G*7&Z;E3Q4W0q?K5K&wx5_OK?>S~0jPrC6Ex3Jx+={5JaEegJIA;mJ2qc8kql z)Y$E!99GK@a*7w2Kz_-d-pf;Ddwa4y&TNs;Z*9WRlN8%xRah~nvd;zXMeui zG5~y_NbhvPo1G6ox!q2=%oazHut4gf?b*Vf{@X#RaoTKp%9Y<|fnP(Br_17q`XM9v z6uHd$1;C683-hR{kRFOO{J2@dC_x8${ImwxM@Yr;bNLnBg z_w=V_pnqf)Ih?qDNX}T|qcH9CY!5H2*c8qDUeX-VS63 zgq(bMOZc*s>+krH)78^OIow6!+dXu@C*R^Q(hg4%yoTiTY7e|SZWBBJJc@(99bO82 zobprq;FV9SLIpGP`)GZ)#gm_?&2)QQ&Tcxt1kFzG>jJ)-D4h1@0zGBuHoKf&hcRDy zn?x*u*CLkS7hEXLOOsSty%2hm))9oXttLh-Y(z z@BuSBia_0Rd47;HJn+3N7j5(!Xrsm@DHRE`;VHuJ>)pGzi34|kZ?g5j?*1M}rnxIs zEL@b$S6r9i&fOb0V4R22Q>~yF6#wJ8>5kOEYe}82B_)WB84o5UP(8&&dZjy+BMtl} zspU6G9QPY%1Ft7Vud&ym*C|sJ>TRiTrM#XLq3??i4Rii;4s27SWRSj#Xlb?3YW2Fx zT&2eLvIdk3+ti<;wkcCg10%9cm3nC#eB`q0F$V(T%xqX$6KzO(@dbe-izBSw#b|Sh5>8&)G1$m{x*t9{pqT_IGCbqSxV>fC zmC60h5^>Cqmd?=oX$#XCW{*~8!Co#F=Hw-Bo|M{q(ROw>(@ae5H?jNKy9qs({6|t5 zA+>8}kkZr0kvERg7e^@lSa=)j%ui#tvGuTx@uqwmdtwTFqv;-J@0ZqF3oh3mzku#P-5+ypKs5 zJv430_c-Znz0>IlJVsa_BZ?1kq=kZ0vd0K?vwtUhMQ$ZBy$-0sXw}z1oMjvF79!ED zC(@asPP~qwW>6!6HH3H#fj>gjBB8J@$4G~RAH~x{7)(i+OR7;D{@6(E_ zok)i0p-XotVw9QXbI#up+*8giII{D>2VuWekQWskF>EbV_p0A(2Z?OBJlL({<%fjh zc8+s*%z-}(;#6W*3{L6iaX7NXxeOScej2a{Riah?k28Bf?Vx(luH-;qklZy$azy98 zKfH?MNYTQ;B|>|N;2%uNy%hM0h+bn~!GDwYv<*UWRL@F-S z(IbJCWbsOp-;=CeOTg{;HL#LQ#RNjX5^v+{iSn^i=%g>xg8wj)(xTXFLE$^;9OPBf7tn zI^x(A0PxIkPen5f0Q~*hkq7`sl@Syv2^ne_CZ4BqB(Z*)Oh)!{CJUn4DP-0M+(J=H zPqW6|WGy$D)jql$@egk&vYK#zASW-dme8*yiuZD)3kAnsSj%3>s?oq|LbjSvJ*yie zYR7bTZYvSEiHu*%ZX%&0DirE(!sY)>Bs_x)+;VlD z-KuQwQP|XOsalNQ;~(L1I0cXJ7FWh-;PW2grIu1=Gu*N7CbDQBXKWpjWoN7a6yK91 z2Hd)tY`K|Ch0pgQ{tHQgF<$(7Zj6^I2Y(I!iIf@3d9r75J7g_UewMUW$<500vYI|o zmqz00KrZ#oWNhO~^~du!hw72O8OKvAK8MXCk3TPu&nd)($-1bWWBPMxUE{V6w%oX? zy@UToT5$82H_C@L7Y3Ms3l! zq!h};*cr`eV~f}bc4A+K*FKKW(nz!Lo$h~S6?1>PZcy+b6(7OBYLKN0X<{OWxN8wTX!&UbK+<{gaDpKwdu^44~` zN$zqPy?${!TC46Q6*105mF9e}Vmt-U3Ajj;i{wZEr>Q&dFVwz;ncrx7U!OQ9PqsNk z!%zPT z@{hPJjjfcmPtx4pU+y-v7NQMmE4etxd>YYZWP#Nreib)9aHI z)+??33e==tPb`kr(){aLcVo7@ht_;DBQb4yCJ!)ukUwvbUwn{b-9QN8qfh~+TQlu& zdfkVg<^}F0I`1VoijL#FzyTtD4ICh5?Ba3kGrWA+aXvhu15tSUZ^wt;`OP@}PwH%{ z7-*=Yl>JV%%ulzVm!W|WO;zKHtthJMruERO%T`lC4G>MAh@@Jt5pD0g4BAF@32>tY zTHRZKqwbpm)en6Js-Gf)u-}R5mphkj47@R(pc3Co^rHcAr(X0s91XbFDEdv05Y!ET zxXrbjCPv&S!H=o0FViAu!-C&GxC3HOLqk)WUZJy4{q6N=Grgt&H@aiwe*fAemD??_ zq%#6lxY50iSh^0REvC^8WG-~^ZzO0QNPefj7$Gcn@3xTO2U?eK#RxPEgn2KF5_5;r zvCgHp+@m@d*iJ;R(d`7QGi}EvvaiZkr$zrqy@QA&nM-$Y z`awtp`LTF6XKW};FqeP4_SV2ma$qJ20DeFnm`%p77iN=5m|7Mly>hAOc1*PxmVKUE zZ*`ZoHEWzcb&o@CSEEh9vg1(EKRB}qOxImhUw7aj&w7x@krnOdjIAd+fJ-0ZO}1o* zcrX90V-0ptuOX^0a$6gl6*`H{)GDfOt#h>_AEMVTyp11AWlz&HZsRWq73I(-2;4}z zZe*mr4On?S{S$Ep$#L-?O2gIpseqJUDdoc+aUXB`OT2=EL6xuQeqJh6$eutEKW6=< zh#wSS4`SEkwkQldRBbRmcPntt_d=XgX0_;REB&f!JuQ)Gb#`?jNb_k zJ~#z9I4#6HZwB+j`k?t?Xc8>^EZi<-Sk9HO@I2R6=IT;erHun-y~*A|qc&E$EsJY-#|k1s7=KXlI8dX3HNZ6Bzwzq~^ha5)xCXPHH5lZ+ z;>snBiYj%7hOQB}Qi=f|x?c_cix`i=(xB>C#;A_eoFn&ETm;f{J$dnZP#vMBXKfD9 zuiR?i@cfpL;&=$kYZ+Acn~7I`RB#iSAQG;)8T<#*Jix`6b!cYD{jd!`xoyO`nMIA!_%T=M*0s~l661iSy}R2qfIh}vhxvR(OpD?4t{L6D7|h5pD(M%3~+rE z`dvEo_QRJj`dtd4pS-cqQPOX$Z!4k7%@y4y)X1P;aa6l9c7i2>er1%05s}Kg4)|fT z4Gg7chh1REay1k%;fH;Rv7U#6m*Ie=kw#^x34}H#w=wpwDJ{CEXGiGZ^}&LBZm{59 zHj^p1u}rj~C(^1M=Kuo_yfiN-WPB)FEQ)o3ZB70IgMusa++Mw%GJvj2o4x2CYysXI zX;}KkH!L*~#pt21VnpX(&lccbz(M|$7vN7#0S?X!;b5L-5AZ>{_TGsxkV+0?paOU9 zu7rU*NLPclty}08i@FQz)tUyhh#Cb91fmtIgZg(UwD8IG*uZ1Oc8t)=H8)o*0=pqt z3;cVF9^gnNf~UY^@FS?e#ueI8Vx|A_Oje|%U&SJ2;0a>*2?82`vPFWoMxP-DpT@3) zr{K#FeCZKAqPi3~PDHQa;{c;r4eLCP(c(B!{w3EfGU^6Awi;z~TQyZ@K~0CN$kZCD z-*S3=-~mGa08zA;LwQyOv=88ldQ(6{US_?kA*++8f5h$WuBeum_gL!7>g+8hRHNP! z*J!0y%=iN@J46C=0%v*FvpkMlwx2`!zt|Qmh~G&Lyvmck%EQhJ-Rrzy#r_)}zk|nr zo2UOZ@65DN&3+^W5IcH}!MA64^UmkFvpH5p?*=8@JkzIX;r-<=X@$XHs zuS=~0cBpy-?ne(cxV@aQ)x^w@#fkr;6i#2pll&PE@}SM!xticeCTusKSq&vRcFuH; zVKz9%i>NnGAKiQF-!UG39mYdnf2%_7uB&NxcPl-$E+mdsZ(<}ptYrk%n_<4j3IVwu81v--yUBYU&m0wo=KrFO1n86hC*Y0&;!;BP&oA-u*atW3UeZ* z@eY7Os&+REg&>}*zKIggxe+A9qU@EB@NROTySrcOYbr7H_SJUODA66%RzSiLLJ>1I zD)_5?gwv$?U3xaY&;;j$Uf2<0=}5>6J3@p|?ih3`kM3YK^W8zsoRWHXv7#w8pE_*c z%T#25n}B?Kh`{dH<${05BHnJy&30qrc#*3RR~q{*buOp5O{}8ra`d!%4-xB)RrTBV z%q(#^-EO@TTfD6KWHGQa@PabF*yZB2i^O^4**f?mSw5K#2(?J8+fKaVEf9m)Jt!t) zJZbRlQLv@4KG}#Z?QdME)lqL~XpgRac`D9TJseP6QPK20s6wJQN zme;uv?+Y8Tf48)TGSyd9GzwdqYb~a3RI3({OJX~UIXODMB1S}>(U%M_RX;)$J;WIs ziI9B$yi_s#ZdqNI|56(CFl5lW!1^qIAT_X)h+og`4AK6b__wz+idinne}B)fu{mi) z$eg688?cl%DP7Xq>IR9jx*q);c<;x{qljgU`5Bw-gGd@|4KRSp779T?#SYteQ!Sol zxT32zJZFGnY35bx;mpSj?MmpQQ8T0M%nTtb`b8H!_sNmDDl^Lb1IQuvK5XXA+vp4}&X%1y=&szi|z%jRWp}QA3NXN>V2Ep!4*eg1zzGJpbMW z)lRV3L3bb07hqbzx(!PW(gMK=$F^`yC-`B-Df=kngHi1PZCkbpUxSK8f=9L6LKvIp z-MV53ATNX15g`#%;KbMD+!(O>QgGxJ#^`c1gF)>DS@{L-&+K1X(HjG<-4>Q zDV4tmDNh*qJrTc(eox>rSh4>1xcv6`w^dM~Irw3y$K8?!qy`a*QM1 zvci9CPI%r)Z`r5%d*D$bWugWZLC@gn4&HWYTeib^Yew0`o8~fycR9NRS zTELv@XN;2v_8)nf(-%;aYBh;9^i}sKYER*ce}AMu8Ym_wTeZcZ9%wN}>sKMlOb`|E2V zHD*4UV4^cNB?W%Vi&<~|md9%3`kfe)c4EiuMXt(K+g@JbYc=%r4>Z=v(Fme~Jg;POKafa8p(J%ZY3od6q znpg$8#wMt7+%Rlt+||g8#9luEP1OZkp-Y)os1Ub8*I$ODLdlPU4S=$Ek~*B5&ydtR z=dR0Q^;L&pIM@eGXPooNH^dOsNxGoH(%W!3p!B~b)CHXj1a%~+2JM)Hq9%m# z@v79I&$#vGruuHGK~kYD6&cDZ(27`Ng%2$-l+CeJY(M; ztQINa3mAia#5>H`=RqewRj`d%v4uFZIb@r+tIh(Kjb6i`?69@=CS22QBA^YZvxw`| z72QT3EtI*8ZRk364!Jni9qr!~k)~M`hpHb4Cu2`O_Y-hlGUS=s2hG1?XaXuGYXY(c z^40j!R}pLy&OHp>#Yop-HQ`uIU`=RsSQBb_ zfQLVsb_?IhyKtD7ahRtCc}lT}KPzSU7!Mi`kMQEf`lGYSpiDFy!!u(N_?)X2)(tfK zjqL^-xFi~kI!5}Qf|BNr5M+V@rCRxScUuA4c zTQIZT5=9H!|FmP~JJ^Le7^>XWHg%)3SkND{pJi@`Vr|!gw!vd-!-BIRagXOBe#H~~B(7a^=gd8UpiKSN% zi(qmuN-T=+kOsw~yXFps5pwjJ5HhF};Szr8b)u;(;bF3eG}F!{8T74aFdZcXoG zZcTf71(J!cbp+kCrSRC7xDmp+cura+pHZS0R)y%BO1I2nb zv2=IQgB+<;@U(0KR?8&rr*mh3C`Kp2R8AUTJEuS@mX*QCsTJxsg-7lZaD!T9bNr&WUQ1%t$fKNa2)VPo@X+kxv+IZI(#ztde&IQ_(v zzmfeGv)8a&zQmyOODh^hW?^-8pU3S&h5v+B#UM2Ei4IMF{uj`yu934&7~q1w!ESkQ zMP1e{&y09pqgy^#!WQ%Aq(P4QPfvFS&GML~PQ6)vYFVmg1e&OwwLyl81*(5U3V4bL z6I5nu@Jc<@kGL*dlTcJ=uJJY*L>h+*tx*pXOX7TX-r@08vEZYcjEWop-)+RwZBP~m zDJq^)nGInro7r)~hrzH^4BjP)4wPSZvU8B2rc+x2_YmTHh^(O5Y>QF#dW@la7~I@! z@fdM)zsD`@sPAcNvk9e|8bg`gRf$a4%^e$t5X)bN2c2x0 z?t!bF35vM~U+wo`*!+fT5-MR#$!*jL`+Npz3)-e$NyJvg{9AZ4_VY^Pb&}KOzzt;Q z4J72#KEye^iBR7_KED~eD1Q#)Na``3?nZLP`^g3S*s8s7#VjyUiSxu`JdOmE@pz_s zVK({x?CMXr8j;u2Y_afLc30=_-XzI$dP9_EJxnT&0zAbNEU6UAek zvEc|tQa=vNCx_>g{B5aPF+cDSFMbU?#7o5jm}x#Xvd$+XHT;TKtk->nJ?vq{UL$Ta zR!|KltFyt-BDX8i2sAN&9?ex_?7)BsL77R1^J?H*>|9FBU5qPl_%32xGF+>1Y42r> zOHo`jXgP+*Om4wk^uSc&pMbBx__rtu0dEZ2mlg$U_Io1srQt~jhWgOXpkNq&-(I*&}K_oj;w`l==Y-Z8Ddrvgd|M_S-b~0vLAHj!jao zN91~DG~`NX2$FMiO?i{iUoUY>dmHM?k%Qib#rhaW40;vB`f9<;N!e7t;8IOy#T-Dw zoy5|eMF%+2e8F+oP9iH9|0DQe@~C|`3x|&dwi3l#@$3(1O2Z*U+=3&kbdXfVpyAG5 z)o)|eC6JO*F;~)W4C+c>a~m5=MCES3*+MD$Dl`_Ua`v-l0d3;yRlblTZ~u_!gWv)$4dR^ z2vPn8*QjgMY8niEWkzL>tl5e_W8SnlQ@wvg($we7$5Yj`k_)>hFQZd(+0k;fp2l-)bsaM^4C=WgB0ey zP>H82M{`G_=`7p^Mw^N)A^HUvDZzUXmV3U*yzuPnm@ob#)a}&RsG3@@r@lhcpfhRx z7IafAU!1(Gk2353%e_sL&7?>4_h-JH{*EriNI#|VS%2uRkPbg?z7jKe!0*UpdN>qh zg7&5$`RyQM952FO&xr6*PS43l(_f1c;cs98(+z-`KIMS<9*^p`N48gd3b36;UdjTU{m>dhmqo$@ zbq*2-x`(dEH{+KWewa#rk_rX>S6r>!*VU-+cc~OQRYP@sCGf*EGH&MSVj5sD|MsLH z2%q)?x_53QiUEW-64_zmu~Be7^Z6|>+5JK?xaf;vzzF8LAK=aSAi3Z{9!FFRqd(c? z``LiV!~DM{2ln%#*YN(JuG6_68!KmEk?9j|S(RLAmh>8=4U|zLG1j3uFw7q3wfAqE z8Hx!BJir@xfQQZhTf<#d*sr1k4P$Q01T5&m3xdbp7zKJo3ynWNkLlq@AT*ys*XFZz^TI|@k;kW1(CU^1hrshL(W7dv-`2>%fH52d#WPQql_k03P&SOmE~Wq%{xE$`Te-ud;zH4-}1;{9_RQZPBxWOEF!al!LBVLoa!SYtM4Ye zY8tF{7LnE3VyLcF`H>RQ_d%|wBu18bamLfUdL}CH-McrB3k#%@1B*%hVzTHcXY5b} zPhRF(?wj{1wyzhz%7eU670EG8pPy3jYaSpT%u(wO5YjFD>Ab+N#;xIBh30vJepRs3 zpXc^aPJ_IzRpoYS=(-Y=uiix{Vup$MXVdJvBEprJbbt%B3*7Vpm>g>6cQ*4|pfAwK zk6#0ge7m(J2kSy$b`R6J4JU59^9@YrJ`EvTxwceW>u5I1Y6c`dP0BJf6ieqO*RG=i zaR24)zbHD#!~vvj1_#gHsVsfb-=XO$Laxlq#O=i1p*caI z0}CZ}u;#joTYx%kB$jRr0-a-H#7Fs~I;&n{L`26&UrMs~t@1Wf- zdkEK>0F;-wv{qYhYHzLU=#lh!Rc>^B{ z3z-C-=i#j(VPFR<3|zpB3o6v;^)}et**vy+7#Mb7t>;5-MPsc}*jDB%^EsWRZTdoV zNU2vD9`#R58LLUo@QZD9}^u(MkS2L+qB#-56G&N3KbM{%=~~zsO#1ZLe!;rb-I6dI}w;wgCo?5{qM|rMvv2rSXmm%?$v9`w8oQ zqUaHh^mf5%$Nuoxbj9=VC%XMa&Ci}Y0OKao!2`eoSHMkaUfLgG0%I;5AnXTN3Hbo7 zqz+(MSwU86R5FLUN2^wP`|K`>6Y10nGOo+#A6uZY(KzYXlU?RLz4yo|O9DJCIeAfz zYq_W~7{)-pix>uNvk(f8!oU);U2@a4=@u)Gei3mx}MlEzB4NR?B$ z_ZL=m8_;i|{9O2Jeyk$T{~mwFulWf&OW-BG?*tqedtW$<>0~(b zzN$*rG0@-Nrgk>B(Djafv^sQxN;y=@!wlK~&+cFpot%O?8GQ;}K^av4-{lD) zxpO8ogn#dUY6b=ydM`Lou^vceQ|%BAy*~n>_py+wilp9O6|MZ3YwmOStLa*0TV-== zX-O-xQiA}gYbH`r*34wf#tkNElFPyohEwm-)y+{NVW$1An)6EU_G;!*kVxgUS!diva2wWGFOQ(h}AZ|Xu9 z)U(NWrk!($mjt6gkZ$RMbjv+B^dh8-KznkMwJeL3L!L~Tv4SW2IZm@&MU<~3ee^)L zy~5~gca%6xZGGsHdKIxa_5dsYs`5s!tq0zMY`2r@25H7%b9$(S&{@z!XW?Pa1?I?+ zTS?cgBuCtF2Y<%uw1Opk{;T}N4FMHDer2fm_T?A$5%j(Yhb%t-{ELs`k(XbDyp7dj zaaUcHzC_rqbyz5C7b*ih{x~}BA~viq(hn@591vO$foCokZ5tOfiDs9^PbDJP)iehu zIO^kJRz3c>dcx@Rt2ugLTw+07G~gshC%pw__Tj|P)ck``zB>Hc#-EuK6|jCFETVMg^H>q(F(|~z zDHl4)H^FmGTJkx&Rs)W0bxJlj?8#Av<4SnFk6F(Iw@B3JHp z>ZvMo3eh=)n`Z6lVbEh@7N%nmh8t>vYC zN_4$C7sQvClT`}Hlmr-PygnHoLN6fkJSEictYQ5j0Jy_*a859oJ3(+32?rODXSNa< zk0qrtMNQItONo~DFZmd$FSJVs0#j#P1{%v7DQXc8Z zW1a=%cwkRw@jTW@30q1nlPSj+q-gKpvtB8F4KJsdzv2-d~_F||zS*>Scaka;CB1|-vXD7v%H(Fj4Ob&Khx0TxTpK(F%k;a(OU-POh9i=sF}c({K??eR zza))VUP&c}+m%=4&3T<{lz7UGEzNN3w6wRovKKu|Z-r@>xO57SecME57ok^bW>*vd z!Q4wM-3zQnsu27P;xVG^;==5r?4Vy9&Ye+x{ewyD;(2NFIMT3V{1)W#e-U(yznA=> z_;bRa75IWE{sM@q?hC@cxZq2ITE6^yfzJu}Gcb=U10NC5YxE-`6(13&{|MWAJ|e1@ zlN~MHntDp#r0KU0INVLB7SSJHTDc_F3!U@%$~?8#1V<@4v$2Ct^?BeuLjN8%_)wnv z)!O%%V4{f8#|tjN!w`K@Xgu&|?HaNYZi3{pj%-;68IOXkY>?*r{cyBX^cvd}a{TPU zxVMKW|BS0Q$oi`tzTOIVhe6*UL=A`c5Hm|@mkUm^q4_I#L0iuOFtM}EQwR2|A6f|c zAAv<={5rqL?rNC(Jj!)N48_;yclFf-^GzX6Q0+3nc?jz zI$Po&F{oM{Z{mqMurvB(iJ_>IB`$kjXKp@AIb)8fOJS?^s{z#sj_brx=~F+xJuWK! z8k2iNS?PkCu8@@;nNPf``R!N8dX+~hu59sp`&*3)tp+_q4?|FT9H_eNTfxR6CV}D>!@=lY2-OLLsphM^@a&C9nyva<+ay?e{oDkhP#Zmc^VcAj{wetb`(J2^ zWAvxPs7>*Q7^`&W3A;3Kfmm??TND425(C~vui^JX^2mD_s@}t=(=^*Us;v!DZ>!bc z?(Ws0E$a8;C#^5u$s}Jq`0K#Cg#KN8yd34cU#fi<11Jo@GLwC-;$9Nk4!FZ7-nSk< z9qRGK&4C}2;vbXjXdS~Ecg2wCLnFZy;t>q*;FtWEtCw}#eG00n#NVrOmk7~1^~eN4 zz#~z?M*k}r`l~Rs4Qd;;?7~iV(DIxTXrl~hBUmNP$$_Ml`1M>;irvwYghyzbGdbnP>|a7rov z(G)SHC+#L$cH>Mcg$^M8AU}RBI|!keIM<$$&R|q4tf@PH@td9RVz*E@5u;{6E?4#1 zq;>6u6-rIt06Gfr`cjlzC`MfCh_KdBbSV4;C%j7 zMFxs6Hjq2k1na{=f+ipV<1yAn6wFc!9rh^|f}uQq$>0P~JOQ{BPXKPkqbw`PlCFNC z*U{`Vmda)No(lATVag}YpnY*hc}!#(lj^;faO`C=%l3vf{^fsvx%vG3AgemP8!r9g z-2{-T19j2d4j>XCPF_Grvg>C;woR!?I)7bJ4OW%*5-`!Ct*Nck)JyFmkKRq$`j8&c z`xZXIi<|3Nx;N(hp&bO!N__s%4xCj^&4agM-&R5g2OdAei(doJfP;wXW;}x%q;OEh zXWWL`KB2qcTv^{^&Bt=IYq2q8OdogUQK1vlC}JKT0W;1$IY#U zSPs_ouZ3yC3VsXri$eesoE0&C0H6I9`Y*wLH6FtU-Wx%~+U-Al;vX0dcZQm!wH=xk ztH)$*6Z?H_CchTV2Q(btES>a#$$xRP^uOpaliz6r6i$!d5Y+;G_*=F>*L)`}&=XSt znaWTLbe`rBz|8*I$0qTS&kYy%SK^@zVxH&LiT#ZoaMZG*N~_ga%5>;g^ofF#L|ij% z=}8FtF?7?OY&h94@GxP0n1B;n@LBP)hcR2*%J$V@WCkB-sM-a35@;d8;lq0fY8tgE zu#yn342|1Rs^74_nDEzOh_qmjm0XK2Ovq46y74`(qT1A0S!S@gN*k2!1`5$|pu(kp zi^C}Ynux!A+k^K(yFo}^6mse?qqMAgbJ;x@sg}Q(y!m`OJdMtk;5FAK!7+<)*kbG& zfal2K)k;ieSK@Oay<}TT9pIgTo?D-F+%<%GL$1z^6Bg$8kCb?GBR?~0lw-~${g9+_b zLyTN(|IoiqGTte{KarM-$I=3`NY^Y9oD!TIQw<;8JnsN6%&qU^WeDJ)c)ni5-&erL zz3LT5AmAP5ZAARJo7mRG^tt?)RE^-GyjNX_3-f$beG0%!kQ{XVOf3L@e;9e$pYyC0Bxo}XB`=Qk7yDPH;)bB$FF~i~a$@Q7;Mk3CIn=Mk%Lz>Y zc;yj5z2db{w22oXk9Gr5^Lhb3iWi9GW_+eRbOkpDkJnkI`aMh!Mz3Kwlb#*X4kp<^ z<8B*SFD;jt+N8R2e@Sz@x}gkJoVx+k|7m3W*=xhXac5sIZwDIL2~6@3$GST{7cMBC z;IbN+)Dg!e!R=_nyN^%&PZ8AD0SN=UYE zfp&?(SNs9Kmaz|l9m!efC)G6fXY)ru&Q@hwB;MmmVwD-7~k!_~nPQ?;@V)Vfi-?H5P z(}emvlk&nO|3c$l5lnc=wwSW*a4NlrHZlj9tE1YTOo~cg+LKU|KcA?|3Z7t&E?i|{ zUK$_BhVntQrp$tz%XmG1hV>%}4jWpR6+D>&{i+n+z3`}F@L-DJ;BN0g{>eUs7k+hT&8543NxKwa-pM zGUtU!=2ab2_D8bPSEW%)rH)40sI-*H&?w6>;|R>jRP1TY{d-M@#fK+)P7wYRaJ@-k zZd-kV$Yc)%w`7k$6r4J8wTFUJ($JycUxxTk;A_J7HDSLg`S+RdX#t-j^~Ufw1U}Mr z)mlB=5H1VAm&yPky+osH)d{{qjPKTa3C8 zeeu$fc)t2oFnIXDpWuG0a-mDTf64`J!}i>;V*tn7O!A?e0P)Y z-&b%Kd5%1{F0hOcFAEatd2LBCRCX+m$F3nwJ?&-vrCsHX9dxhUMWbSd$Huw{_-bB` zFh$~W_Bn#*Gs4`{^UI+Z0v?8DGg#+j{ z^?mU*$;J6|8v878{+QlI8KEh?m+0J!tCF$3MC~y?%wKip!NHpF-}rR~e)tpq?4R%> z)&H8ePM-e{%v{5hlMT8yPh+*w+f&ir-&fZ!LCFkrT_4pAjm_$dfO9w<-(~y`*=qxI zKvLoUC(C_{8Z`=@X3h!4zDTpY8e_Kij;FBy^LwL8+#5}R zz&EBn`u&O8qkoSb8n?!p?n7=T#&mz4>!_~j_PffBnpSI}q`4L?#bsn1-C4H)@9@mg zrh1CnA3PCbJ+X9s=tK;#d>9Fu)WuF~fd)2Igj1t{OZI45tC>wEd#4n)(uL zt<`MRqEz)7!jwUd&pA5K7qo;zmvJ4zu?MD+ho?bOk5K~CPx0#v{BRoi$utH$bjrGJ zm7`JGUhnsNyv=fC#6z92HRi?XnXG9W<`Gvg5x-;1(Tn`{r1uX6rjrBHN&cmzz&>95 zdSM@g^GKA!P8{|=I-M;4gxjRn4j8&*zD7|?b)8&-R`ciafqpOG$13L(Ib#7I-kg1K z>MjfkM9$oWbfSHbKLjK;ZoRevIwMSWB|hqRXhRgAd~Wq;_x%oo*55<6BVAj4WnpWp ztfsfGk#_pqQ5FWRXn{P|tQEnmaoHTfvG0GKKpu}($<0{Cxkg9kWoCrXrOWU}<{Td; zr1Em-_~4Mr5OIvRW^PFi@y1ll8*@iE=DFM0?&PGLF)=F0cLLtn^PTX~*pC?*Zcgm|a>x9maU=NJk&|F~|#qC3ja zUYPA+&${m^hRjvAC}QHt>1=OLw#S(*68eqq?AxryFR_)Amwz3^Zp@u|jUXHwOquu_1+L1+N$Rnt z_*D2CQh_#cC{niP!S5towkNvL2wSpi;*nPXP0tS*#`q7xoe5^I;1UbFmQdh^Dmx}W z{f@{fk_W@K_#fs6lPTW^*q!?M^r<*HZC6l6zc<0{r_vKDjMVoNd>-`;gsL(zX9BuN z-4!m|uSy%b$Ze8zHQ7zA9qu-9gQ>UHi(XpAFSsrtP8-^JU3J{G4n6z8v;@<%1aJc~ zmd|MkP}uHeRif>oQ@1D%AdPGbd+3(nlolqz*|eYc&+wRyi~nLWK&bjwau-lU@TSKtG5q9l-t5PD zuu*)()hT?XMnzd!oxZ8CyRR0#j^o{9x{3UOv>E@w4_ioKgvvFWgfTGS!nF_aGESrg z)O@{~-#LSvu^~;Y=Cl3jbS5@8BQY(ogde^3E#c1?;G&%Kv3pYSgslHNxZNIO^9|$5Eq-YV@We43f~> zyaGkd%?q|RS&BLg6m`qDqo~-&IrXj0sq}HG=3KRp^Qwj}Kj*p)RULiOeuGNeruDig zRH+6Rr^?Yd&8)+_xumh)SLJsqx+tr) zUgk#yK;L4s8kf(vZ%Km0h~;0WGZssT``%1+Zf4TcHit8XAjKAz4$i#+JNp8%V*xpL zD3d+4Qh!#m*iA;|V%Vj6c~chn9{o!5}MKF>gxw@Y7ZYcaQ5+tH8sr!bX$nim(r zH1Fwf)^9L_2@kL`JwH91wW*VV=NyI#C^PLexhV^OOOiOBeEu-gl)UgfFXMThR)P+Q#QJ<;hvNw6Wg{&^C-$COzy!&fEG{_hQ1B27 zrPms1iRX-_KGJe3XlLle-YZ6eL}dVjD-sTUhX%C8Wa)^X#bmmZUvVAA22Y8orCZx> zb~<|WsE>`aHP_U&HMIGqPEm)ftzKyHvlEUR2*(BjCLE>n1xMgk_?QGid&O}G)@5fL zsdk`|sv#I_T(^y=`7J~WW09S@g*q5---Mr7wz7f0K?f&v6TjrPlr{G0g_S*W=7vjiCIH!g!ss5}f60)<0=y)KP zgyBifq63vf;M|_bQYr>Q%$DC zdB!fi*X?E}(fJ#Afo}*9?XW_%G{cpu%}q&X4zE}3$jip(@JQIg8BVV>-A86T#tWPz z^e1uSMb_~!S^GE)dy=}NBzPB&g7O%>#!e9D*SDO(wDv?)vtjY}qiIaQ@ModsYm39# zr*RaP>*S@C`ts&#RLUqu(cOj^ZV-jWp%0Laa(t)V2K*#L-G&J#m7)ywp)v>vNgIye zJQ(C8S1H}cmjA43pB{tE--Y)nC>!;U1LgZ!P`=hwuiI0i};U;3lioy0If&a!Ye5e{Le_$Rvx*12GyGqqP=Bg&i zfWuhY&}K(=^(~~rUEbVBw^y|3^wwHKrEd8hpWl+?(p&EDKXTx~M{z&lCi3D<*uS%u zaf6O*JDb3fvZ$|n_KJ#J)E>zF0N`sT9Eim zxAQ~3)cbjk`+1yJ{3bxJK+1nk$`9Pni(jw752gIs(kOlWZo#bFKVx_N2O+d;EpKUa zxk`E<*`!43E0dxIV4l&Z=f+MrMQV85;s`R%f7$7|lcau(0_{9F1!6e52(SimhTrX| z(838vg_6G2sL+3XT!Z<`%V%(Y8OF46$sd!E&9Av_Dvz~FW9%+diJVP#AsVJv6%59E zs+SIi=Y-Y~4kn^VnkRS+Zp{qEBS2;(od}-J6D)`&DHe%guDRwd80Q2Z(JL^j2sK~a zqDO+57K->-O?DS5`$bY6xJwO&cBu(1!{dqZ?00dfZ^rR34`x%Bn84t^dZ;C@2AAIE|oXc-c-Mew$<@yjxn1gBr<&=dQF?50rP+E09b*HUSYH3x{s}zxKWazNs=@KZn!iw5REzWwR|5n+gR= zsY#loX-7LGP17db(k)%aK~I{bO`4@mleFm!j38UtDNq(=X%Q3@#C^pP6le5aof+rq zb-6m?3^Ss@fFg=Y{J-DH+9XBP>fHam*WdR^8nG>%F?f|5%!qxFpF0%VX<;}%1S#Lp&TOcdN5;6U%Yy}nWF;DlV zDJb5Emme$z#uM6E1j{7`#tU9Wyapt3f*FLLZaS9e`7K!lOO(}Ab_&QX5 zuL~*tzUttb`%xRd(a$qA70Bgz&PGkOTISS<#ATQU@l2swq0!N>0*M7PLfY^jB}TU? zs1>WpoAtIgS+lhN$}-93u2^vXFUqk!kbs3?4H4A7H1_b2gW2X<%$!wzj7 zsV5>C0Nv&%iN2#Ndp{J0iDRzmd~gi7`NE*4^B2I)yOE&iVQ*asig@mS1r_mh`ZYr+ z&^&Jhxvkc$cc8&*KP3*T$@z|n)W=6)6gfYrPXu`mL?m-4cSD7AICc(E!_2=O#TC` zeDV?3^o-|OQuQpdX`e^H#<$l*{#-6`I#;zF4+GElj*(}RG{;Z?1v6H?z}6H?1r2S* z8jGgALfS3Dx+XkF=31zm!qSw)S;xqfx>iW;b05(`Os$tF3LWjob{wU+hrl{bkHm7d+H6)nAcrT+H>{iV13y75gDz#2W zhNE3?v}bh2&pofy+RTpbjP6d_Y|a3)Jfo$PZgu2%f6(Cn%b+vLjqsmpX`Rv8or}gU z@F(mJ=JWb@*dd?yOIH0HViF^@*I~CiXgit~wA0;k_#|2#bsg}2G7G_mrdywrsY{(S zO+%ZV@Y2DH&57Q4>!VOgBg1)_`0_O&oDx?yf>RQqY~J{jFg6fCp=$@t4QM0mt?=iH z-85$#Q=2CKh5MPrmtBrT6WtElfpvX*654$M@?AgA7tQ+?;3_rdxH=ZmysHAZs%HVN zzEp+dlM(4Y$?Hj1vV^18)f;JR08_thf&I3H3sL)Kvo-e7O|mLin@R617GWi5ezfpP z1f%ql<%(}3h6`$WCK2)reBl>9vAh_m$XR;l#sH1Y5K5bU!yEXC6@%81uj78GfNf|m z(k z)zVhIq}$53beJ7w*sl++#G|g%PfjpRP5?#1ImkeATH*Uwj}k9Zi6TfW2f5Mj<2>*Q zM4aPO2}_UWZiKL#y_&Cly+$k7RjS+g_Ijm3kG)Jmek3dRZZbj}ku^kR$jo$WhY2oh zeObX09_V%0{Q}nGq{1^q4h$ij=TY!5^7IXP4d)Em6uhE@8qTF&pZ>y^h*J;5VYK8s zI`V6jrh096NrhBii)Dv%>fu9(AhcH7bw>DlxHCFJ9E^W5YoxLu`gPg>FFI|oYq=Tv z@}V)PEV0jjioSey)V`ekgZlFJA7$QnXbj5A)ByaItOxjOsv3wsYm^4FF|H{V_YzyG zsVix$RrA^;&29CX7OV@j+u?&f>;X`6j@Ywg%!|G8W?){795`=+;ojoVT}y8*8M0~# z7+~ChtT<1)H(Yh$5+V*6xwm#B+VX+C!_`D_iLG0zZBginW zb?8@?jl9N2eg;|~G+Om-PI?t6gtR-*NYn)CA0*(b^sdd#VfN)Wdx z600*$ug7?@{gIt})(J8yX1+{XUnU{wh`xQohPXu~P><+cHnVfWDYE9o*$O|5N=c7` zC{iF8J^3Vr3`L&fe!)1RWBO3dKXXl4*Bw$lK zMTEA9K=OH@$GkoLn}T;p&n?t~TPVO%Ak%K4BF~~*V81<&ubt@~mj*?nuWHOEq z@Hj2C`Msu!<~~cFwWYjHCBVAFoB8lsItZn}x}jt$2yC&#lRwtldP}gGkILbM^y~g& z-VC5R$dEW=fT~>Tr|Q>DOuybYmi@Z;e5+2pzg9eB0W+ZgxnT0rw1wSA*f= zdK?%Z@!d?kniZ->rcJ?i#BYLXauGCztD>COz|VrQ*j$DBVHoGdU3XWUzC%%4+tXUv z+Fa5{S2(b8m5O{Ud9K?bj`wDU33$UY?j|Ox{L+b_nm{SsXs4L5NQP z9O^U$F=rEUUm#*&yZ=R^_C-P;2AhZaM1Kxdkg_oehk#MpRj3} zMrD!lJ4MbKv))}I!v0MriK4)jNW#o5J@pBO`UKeNr++=+V%(w=g!fgYI>8UvFob2= z0A{D^1OcCJ*m>;)!Pr@yK-|_kZ{1rfFUVIL&3S5DX}%dG8c)d9;s$jBrydr@Ja1Cg zHz^hklapacc2g!CRwjVVs-dcO8Lom{&+$a*{TehA- zTvH&rm)6x-%}uV38i+P%>1}pn+W?VAY&DG+UN8fj^2`Qb%UNriXDxKnjT|U~zGgUjC>Gkd_2E#yGXns+V>ncsjajOp+t zwl-f?FRa(~mRFZK)O4Q#n<(25WstmKc1URB$%3@Pc;#2{!t?~0^#mH8ez^|U$9o

zy8Y1e9(;|wbBr4h*544KmG8K6-`V#N^quq5>{_t>@97nE3u_coV_iWz){KhL zqccl&AV&K!Hv<)|G z!+l#t;6sU;{c`2AmH}U3L&pGtQv?7YoQGN9VdOcE$RTEb8<9iak={389crml$xBsg ztD&o|u>$)744Ko3o2)#Q*+#p2XgAr@dQzS_B zO|yv|uw4XYJG?paTzZQ1K@)NdMs}U&*?rZ`4OWv)Bz9D_xqF1zA7ojPaT}MjW(22* z@G%y7KP&{Gph@Q&K)M4OE-0n2K^E;Pp(4+-C6sS+fs&*^&=l;@R~}fJ%4m-Q=^8qb zBVVd&Rdn>V>M9x>M(k)fD25ASgB>~=9sQV~s1tn)D28mh``f4n)R=$YRrly@Poe}x ztjra_AKd3&e4TIAaxQv-*4JW7r@@al2%^CwX<$@~xgKo0&mgHH(jWqq<`*2a3TcU)8OKC34r5K7n`3#NOKrQf9ib6*IzL+RB84aq+#(HsyrH{^U z$9~4dY((w{ZqD$#gl9s5Xo3O}yo*7TB;Jb8hsHQ4;$Y^9IqrLX13UfmHUDP0pLxlZ zKIgd`FS;8gWeoZGpFQ}wow#u)qyW9<-sxk1ZkPT&G?4-x4?rk|SCH-trKtFft#wp( z8cPi2Ho4iLY~f*oPl5p? zZ950!i%~+};CVp`Vd>C3f(W3MI0T@7%IAhk3h zt(2NpVFT6|lIkb05`h3R^y6aCdG?2p>=QZt*L(Joi}sSNxs;xxP(;^c_U!`$J7C!b z3nrtY5tdW~YwxnuO}D&`ibjvWXw)k@3e074zFsAhmUULQVfTjh%cIlm|Jr^zM11aN z!o6+l$SMx%AGr4c6K;GM z=Albq$_P;tJoriXpxN~HVF{703gl) zLtIoP`>%KtTc!1C`sFiu97TVfkRf#$jA_=xWVlgMI+ehS$l}4F@nU#8w>R3kP zUH&KnP4r1#bulN@ju^^1pB?e{1jgt^;{+ZQjZhH!OUB8*l5vi&WL$!#h8mYcuc*x2>wRbd2z5k7#n2G(RbUN_Evp`-laFkh9p)F2XJtK-~<2zz0bH_D9T$>vp~Lb=a5*Jp&Obz+bbSLWPLWlWJ9+5}sRDhpA<0QBr`@ zf&(@0N+*odKtbqVJUclI;zB(V<)C4kq-8VyN?YzUV8Bl*Kv};Pk39OVzODDIsEgc+ zM3{?-Hf2FWzP_`rOVHseZC41u`tAm3VZ&ETxA{exReDbrVa;Mza)7VTBJ?C`Urhvfx!$+EIGUm; zBok;9vL#05rmKobjOnY-vD@qA1wDitv#>2 zwYjHJDg|%$m1rq1neZt%hwO*$R9=FjHJP}a4BhB{sJ4=c$C8P~yS*-&VgG({CHn7I zlIJVM6{;qCWu2zfB+S=!VRc~e6Ok(B*+w4TMzY$yD}RAX*fWtBo=A9h09J&b*LILz zph!k_RWbn$@8@jr4DOUR^|sp^%e%_W*d{RTj0m7uxN-)Va=5*PlJvZ15}}<$u#_Mg z0D`1t5;0*ok)_M3N%YL4isn&h+cK9*b0y~9NW}$)r%;_oITJl|sj&0V+>lko zH5Q@2zlSZ?`U|Qa< z*!C`6du_f|RBDh^)Y{#c1`))O9%frZRFLS~3pCZvwLahiJF`F$h1B1Ib$Ii`pyCm) z$0wl@f35&_jaj@UgZQiPtDU>W7dUZ;^nD;ILeIb;p5ogS*9@YXY7oKNWwx=Pw6s>% zP+X#S=!R0$M`VFpnI;*hO@z^(-|311fZSybO_$7S0= z?6?ak+dTLL;Dd#xn!)1_<`N9LF7O$?0d;$kEvIW0!isX0v%#e{)aPS%@1sZ6}L#Mc@CAqXsMR+u-jx$kr8B8Us??{vishETVXFAkZ}WIu&65uf~UPE zZ=N)wDh(>#+B7r`h&+7|QHR(o!~G<@!dw?p#{CMR@O%Yf%4<@~E1J{-b+t>V?!ywf|dDL{a?!0NRl_61K&f+{8f!e+yE(9zGa)`fgg5mi}Df6 zNQWZ*lIOFT zwV8wpJcaqZ3%Lnm7*eH*P&~-gSGCJ&MpxzstLzJx}^a@>mMVq0g%P9iG`AV!; zzX86;;dM9l`$RDDR9ai9vk5cMYM-~i_1s9C0yX`*N%oD8j3>O^G)`ECPM96~?MyHgH0EnY8lFV^}KpBzqO*Q470+TPxvAy9d|Z8NdH_%n64urwd33}{KT3Vogwp;co=BF zR~V$!)KYTb5Q$c3rV)`xJdH3qTc)8!6-Li}j;*dJZD^@h6&owHby-xLr3Amk$$=>@iHl24vECAtx04hOyvb}ZrB@lO^7|K`kN@b6b6@h^eF zzwhh!gN)9{9{1P6+`b%W%C8{~0wpV$-Q5N5o`xn3zr&(e=`bf& zv@+sH8g{c+%6-l@Wwcf2t2($BE7O(ppg`M(FWd&p#G-ueQJ;8Q1sJnY&q4I+b1)c^ zZee~8JW_4KE8ocl97Oqnc}unfE(&rWSpk%Q5&R~M^L(0a|8nsqc2{*zsYz|9;`L}X zjdmN>^CJ8vRFNTDUK1?0>}7dTR6D>x?yfC3@DNJ|U@8ic6p?kHeJ){fXyzhSG%SI8 z*v`^Aad&>Rt42^?W|XvJhEv(O50l}<(#fyS&V^DHTw~hd%h8>2GM8h}>m4xcv~I`Y zD>1x1NXDN$CE)w5$xb>vFOWqqkZ7TL7d(tS$6xU40khHPv>nyXZhc;{$n2=FRCih( zUDFjCC@rv8uCvnT|H zxnp!#v|dYD_=m`{@c#!`EcrRqg}+35)jn91cpZCM!L=Q-i@~!83*h3n4J(1HAyNhi zi^3(SFe*E`+j<&08f$czgkBHR%8mH^h!=F{Mpgy)#ybcc;K-57xOE$L?(EzR{w0*!5tU1t#L1cAE(-tBhuSVirqOmBr#{^|S@c zz#Q&V-c@q?-}|=+28p+x^qj_vPU9d2jEhrzh`;h)?sfv6sy&T+jla-_!MuMS`@pk} z2t5PaV5Er#9t%D~h44ps*{5u6OMWq3A{18Bf`%r65SIErikzrk-a0axL+bHdz_k|` zUHZb73uvUeEs5FOogj)6fcsh>v7nE@wktN^irERk3xPkKCo3WJyqA^W9j`)MF7)i{ z@UoSJ%cT}{ntGedrOIAqjS`!Wd`%R_8j&bpDru1m`MkO|Dk<@7Z`xzjl$-=sohK(@ zQBDH#GVd9H2%zx^6IQ`%0A+ZA+CPOEqxOm-!*t;p!CpMgLuy_^PHcNa!1&|2odvHW zF#a#U6PvYM!7orWl(dz$8S_M?eb^KP#=j5g$HTq+f(5D9THY5CsmJDWAbH$|g+`C- zucaf8!Vc~BvP0)@it55PTH0BdeSHR&66Rm8%|ib5Gljv#GiKtkEQE0K2IO9h|1A`_ zGs!VhRmQ#ze-IQbeKk!blX!+@$F5KD2bI5+17GVvm{06g6_xStF;M<-Om{o~Yp;zCVv95&E3xT|sWAEf&2!)AKcM z`Wh8a40eBwuwo#ntkfzWw`}nO^loTm#cNTODFKIZpRjT@PN&g>pdk|U`-PQ8>6;*3 z4?U2y?OXal9<&Hc{>iSXu6HyQ3;As_ozvY?i9H5b5+V1#yljTr)&r>ruz6x1dgIV8 z<>!cF?bOXH$l`c|Ls*cN@>uhpgMCE4jGUdJuT(6 z2~@ z0dm5h$=LNU#f?0tGJLYm4D?A1;$_Q-rV4{bRNn^1b9|M(Sc6@bWkfD)x(EGy6|;wf zieAsdr2SzMkwd%jNnXK?;vrH$9e^1-^Ey(ZpZ1r)R$aYH;cTgvc1qNFE_n;q8jiZ*qnaS< z`eIIfvjA*DG*;g5J#lx>wX*VjBs>Riww+_c$_qwhK}MedWPjTPpwpkl8+8Kkzl@dl zjX;N#eo`L%gARH9gQO)v!(ZuVfkKzrhW@q<#n0HCoo2PcSZT8qTTE)58+(IZ0zkPm zB2*A2pi5!-gPZHy{lH$VyiPd_n*V-$VLxnti1^&cL4)pfq*(>(ZgBj43>s1K01ATS z^J;yKe+*v)GN4+J19kG(M~yf0#yxE0jAK zx@-ry$##QA(KLww(d96#8~e9}7SHbIf(*x=MkJx#AVDoCJ)?~s`=$}TH6ULuHQ^ z&|+L!0VN6ZeWa(QJxY$$5rFaVPG$n*4|Po&WduPkU0i35vv9su=UMMHsUZ#l*@hO zHRMvmtdgKv=Ky$!LnI*g6NvWmntT^RP9ifO+=hoGD0<(dx0QX&Zd2PE@>rv41v{Sc{<0f|Qwv^V)P6=|L~8oeq@B z;B=zm0^20zw^o)_Sj~D>UrUbz>%jCYvhO7$cqPajA0cfSdIL&dtv_=dNgZ3`py=~! zE~lYf8yTeA0KpP*VC~R1)J6D;tSCH?MMU%KOH3w@jk}!F|!ZkB| z>Hq+FPa)+hq|k_S6|T9Cm~w#3q7yG|!lz88GK(l^-_sT+<`zQ9$K&w|_mheuKs-U3O7G2+2tq#GE5o|*IZnSVz} z7>Ld3EVl65$}N@#i`3d#MXRtDK*DQ_%>fOo%ZG#i7n`GluSBp#zIqAxf3Z2yBEhBC z9-G4m(?4WaTh#?NZDWI3-Q6J&S7A%AB1p{%R}s6H`_0KetV~vN{gvNtmS`^bL8$!D zwzKCBeAgW~_XGGf@*Kaz@AG{J`pLfoFZ+yLM;FU@F005UbK0!E#aN?$$zVJ&a(L(M zViA80eh#qSGWvOTA^~X9R#UHOlPC=KGJUVBNrY`>jK{*91TRl4tFwTc|GZY(Y}7(W z&7@zSd>;T*n?V%b&l(1SywBUOXa+H12CNDiGXEU!d4Mc>0C{^qK&E{jpL>Kvn$U;H z+J{KdM(R>{rq{szz~-QhrUi3Qg9}2Rf3huL_fub6)6&@`)s%G_um+@$Z_o;;N#(SI zw$dIUWff9|yHNEC$z;d51dM>GX$jEaMxNvFq?np64&9^KUGmM#NYQx3U!`?v`LeFg z)<$DHPg<^NehsGx))#<^@2KyOD0Z9v~xiA}}+qmPtWi@(f62r=1b7Mz0(+MQWDxy)<60fB3 zZzH+tDGXO_^Dod~7e|*g9te^$EW@0M-kDx6%=E@SOZMm(%=G32MUA_mTx+iy9!1m` zf2~3tDAwYqyiEvO`8@`8i=wsESmM-R8=3W)aAwiH)t`{MyfR6d0Vp+ygI%B)U@Dt? zL_8Rhm1@j1k2Hz(S;+d+Qd7gG&9Sq9;z09e#wnK0Lr$?Xu;tq^gnXK>ad)ccOI-XV z%-asazeJwPxaKkr38`PwMV^az=oz?(r}%g%%|*b%br%t7bAhd^FUaqrRW`m&ns2MC z!bJLuxoe0>x1i5bihZ5#YQnl2#c|QLeNx3|XjZw($0VKFU%1wrNqcNP^yp$}%~9V= zf2~+bcxRO-um9{0G(EhXh&)$r_c;QgB5l_ie7@b@*HTtssqeFvnY-i#82=!+J;-P` z1WGxe$g?t0v~-uZ-fMv%3YfI<;v>sH?=v5)LEA=Ovh5nHf!A&65Zaw4ySc6!8#qiQ z$Rlx?dON{0HDSTjgdzZD&|F<_34f+M_kzI$C0YwcjbZ2bVKP{?4c`B% z<%JRQ9Xl_lm=TG0BD=Sh ztSatHK0%x}@X*_~T30bfi&Etyp#Qcn2YMEMjXZBG_jhc_p=NM7UiKx(hWcDOnH|za zgx#fvI;>l^JVG_JSag<(R%Bt*58Z8K0Wzl%SJI%;g3N{!o4{RL#%hPIRWKcLT7glS zPP}4(@C8&}afw~xj4D-6Q2VmtQGskGd^ zWF(0)H5gelp&enA7SIc%+|Zda?o`xJJa~6qPuQ;~q6!4x1A!pJN+XXNM4g;rcf0eu zY!a)mvQ1g3k{hrKunc~a%HCULk@L&7jXGsPwbkWb#i`TNy`J5qbvIdf7i;*AfYAQr zeXyXu3cNVHvq_5Zf6{cNz^(b`gx z=aTi%c|E0yJ_(i$_;!AA2peo@)@XD#T1D5j7)tDJ$Y}AGesZUywLN3D85VEmjJZt? z7QR1tpO>k)H!4BQXHvOBa#NrWA(PtTq0 zGtjvsV4$;MR6%2)N{q5)&5h~Nb88sJcQ?$%ANZagIzGO4^^d~$j)ju@CO_Xh2TUOz zg6i;BRgVURjBf>b40={zly^-+#xrbJx3;*?-dDq?>s2DU37d%(JrvC26Ja46+`4P;#9uK1cydHA{aUhziJ9rkgpH5s zSls2zkeS!%DPa+@!^6N#GuSqa>e69kjQAN_4GSLX@~#SHNtYq70xOfvCc?wZsI&2D z?~yqbMuQ%7L3;Q^T`=41+lHf*)(~y{$!7$2;*om8z%xjAD34}4ltH&qaqOYvLHidx6wMkGviTm!BMgZpnY8cX{l5W3@-=P zqMboG70La=GkwoNJ{RJDZyBGKMTvEY|6Lz~v(Fs=Lp@_$yWEen-F19cN!!u<3oU1-MWcbO*GdD2?!(AnUlzX4 z6B}-iimg?)d2*Cv#2{*R2tVQ{&R|C;aUax|4~+pe3{E@WrM}DvL>kPj&bZd8U_sP% z?H?AV?FK|0d&7zmu4J>lu4KrR?z`BMWe2LuJpiZ1s=X*!=6ICqlAaJmRLCQNq(_iO z84bqK(zMUA_12DZa~arrSG3#uYIWGF`aQWrK#mB?%7nHuNtLv^#97&-b`K?0(DpVx z7|AZb3)NAg8@Z2)??OnrmSKYUd+V{XvP)Df};Bn+R zzQ+eHk0zx3h7=z~3(0E{%tDy0s!gWXH0aI79#eNU1bTt{tV&<%Y$$M5RJwWQHoAZk zC8W)#7}4gG6`Zsq9OWlaNas`8`4r0mLk>_whDwTYfwN}P*iFW|~^BbC;Z zn9D;n2+xy8)#gzl(#svxqC}WGhMoZ-bv8!hGgA-Nm~S;IH(o$J^ymKRqQg{2tD6LU zdOPG^v~`qWpP?EvbOUho@uJM;>z|`rFMfv&!0)mGGsUHN~bFm`Wu?v$~DBJ_{87}mL+c!9D`V6hj21bm#ano+x z=SyMT9l)ZZU4Bj!0t^Q6A`ra@LHQEc0o>wURSEmIU;wOngkn)%PA0h4!1!$dpKs$y z`qX@fsv^(mbPDq@iEJP;=X&`T>~Aon0pL<@Y@H`KH7(6)=Gg5X6*apDyZl3`uE_su>CXgx$`9U`Gb&exQ7 zmMhw&y5&k~JyYbq` zN!4uF!CqAf5rMp%7pth5>%D$RQ*NTD?TMahD)bD%n{$Z^bAwn{dFxE~iwNt!@ME1* zF6c2gRF#P98hX`I3lIBcIM#)0f`WzKzXt0@Dd@bBfny7HN#6o?h)Lm#us_CrU#ycb zShsv6)`b%(-xcc+kuvsJH?~BI--~Q?E+yu>6?Y%A%RA~77QVE@XxH_~s|?t~kc}eXgJM-HI>V>bIQrH=igm(BccCo(yy?%*1>cH`CdVdhBRp#f8g#ou+T9 zSaF7J>7pGy>dv}avBBO}X2Nnnk8&k75`vdcLfLfC3Nr?>0CbQ|7ivAd4A(5f+V1V$meWVep$WKBsJM=s-}ikc|O*5ip))j3?0xWOrJr8 zg}|)FO{;MT14JrEznG2sEJ1K5=@;T`N%ZU_i*}OmsxymA9JB+oeS5r1kdfBUo8;xAp8*(69`hZOv4Bxa3O_G5Pbki;SqJeh^z0ay zL-zOJ(DD71fh|Gg3-7md9Fcpa*QB$OVEX2$OyqK8?#x0(fP!hRv1u#n8=LGk-4>@= zfst6zJCUXY?st4J>UjsZzk^hJNHimU2Q|rCy=ljb^{k#{RzHe90IUQUoH0y@A53AR zlV`EmJM(BPU$!i= ze4Kjrwv@Vdr`_10m!3JaP5CJlbTn~=W;KiVu;>n!`{ZMbz#7PB@ejO9660Tr-2eQs%^W^++ z@2||v^CYXj>bvR8Or7(e~#Xo|BtjXlU};kuAEW* ze9dm_Y$|CMD>V5Q39r`x%f&@Yqcr79%R<~3kV6F{x88(9cB&YRDa71ozz4?1>(I|D zp9>}nvH?-RT$VMD`xJmj^>U$NuJaJtecC&sfWEh06 z{|+s_FfFhYvKBXi_st&Uob6ZX{H!pOII-L3uXgN$Cx=kwAkw>b9`TA3jCTQ0k@hUW zkAyxr#rKJH?nD*kod~|pu=7NDrB-W`NTzCNZRjY)vJMIeuVx&=5A0b4s|Q|vz@MTe zi-45X(T?B=@@(w6OyX1~y<)zu+-%l1xXKzkRRt!I5L+$d5;uh_W3nJ6p^~PTA8So} zi8Cb?C2`HCvgT7UJv#4PGN7hRM-};k6)31|0^#{N6?qo@oZ>L5NeUqw6=H{b$h7|n z#)0P!e^uI}*Ou0Gx{ABp2BWI4J0IJQs?wqm?xiP8`Wb|_NJ|sHBTsDpO|binR-ug+ z$WzMfc6Vc4*TTMp+mXfA!1o_hn93vTQfz7n&;^2|GvhU=rW^{|PrQHtcr=k?YN*CB zdj88)A>+0J@5FD)6IM_ziGLt=?NvO&fi3XIzsPTbEM(elvDwu|y}i|FZHwI!|1MKa zE*=SW$zD4$zr>MyaCE2(wIlmi1!7&ZYok9Di<|l_p;+SsP5Eeg9)B^(q^Nq>y?Oc4 zycWK+Oe$Vfvk^^2myivS(7-ANA@vPf{z~&=%xnAF{?CLOfL1+za=3{@< zZ_AZ{S@=kbh)%X_PpUJvc9<|cHik2bU3v3%a zj6BCdCFA9cmceHN9XH6x8(OptI%~eLLs+aUEpTBs%BDw9C*Y8?EDnZn9*VG11egR4 zF9{U0@Bt@ekUkU+Z0R8uCm~+37EikvpL>`DNJ1T#779to@)~&_n(Xt-L2HXp-zAl#ODE3b*2E=M%C^smQdP!&{-N2NvHj3%RFl4XF%WvGqGY zL?g{h{>reoix!sVmuYBTrIqj0_F$&~Ki?05&(SNxk>TQiE~rLKiAG$TuLU}z_(tr% zHs}n^S3ou57#ZGv2?I@G5Hu%UeUJJ38Q#u~YIqyZKRFG2H?9~~n8B>ax}MQQ7K4A;Dt#>MFh2s#EW9&Rl5NB*-^xXXvm!dfS2aT3Su}Tt z6yNf-2KhUzTjv!!yPKM7Z4L5fak;TLUuAG$tI%RfxPbj~hEQsC80Wz%NC!i44E+Z9 zp#=jtq>UT|8#6)CG(wLO@3jN?F4S;~=qF>>Xm218#}P^G?4RKuJNk-Oz-=&c>?$dd zxbx+Po;st$q{P-7+=6>aWe&1uM5}$fS?~akfpNIt)88nLkX6?cEZ*{s_^TW6eN#D% zY0sc%77==eXCXheSx6WOerlhyd#z3NE=z%(t}3l*DzC-Vu-lxgpdu1&E@y#9!?1#4 zxzVBz2!{Of6RJKzaFm3U>CsMMDdk((z5!K>10iT zZkS6(s2igL-4C>E%wcN8zL7QJ|MZpRr@Sl6EQ4y)rRA@KRU*m(zKSk~;i=EC%~DH^ zNNjD>mm6An1vJ)%6@g+U++f7LI;e6ksjQr=oEZl%WngXPT<_E9_@GV}zXA3`?EL^G zI_}>inG$&BI3i0Ro`eTo8~k9ez{{2s?p|quyuCV4>=0GU*U0n6Y;b8{hF?PnVM87Ld;gPn=d(xd zm1Q2Ve?C5C+P|mgtbD)k@O|u;u{|rZ*`1tQC$`LdcAhY+{j+t$F|W(k-&uC#`O`Bd zv-KKz!)-sG^47ljoBP>V^8SOIzh~UbK00OmF2}MtNl%`9P?5@xnJ|r3mvXw;^recy zU3V7bCEc_-rjmV|f;g^o-Zq7Oa@YWiMvSEyOU?=kQ@Cn7`7?Zxq?jE$Zr#Cy^wN#&c@6#Zt50CB zOEzM=|IGf4nY)*NJOAz(bsWLR?D#pqPEAhy;(7M_s`qb|#ZD|^KNs8f>pjn_S58ZP zs^~1c?LR(x*+?Hxu8L2ZXJaoOUh-jF_wE_&jprY|n3#0iyn{Kse`d1hz7R9xxudDa z*=hD;PfyI0AJ> zIlp9U56;KFXqIB^x~=o&C9CHdhaMF37qhwJZo5d_&U%V1_;cIp0?t80!i*j7|CN1P zx47r-){^}X?VXXfgnfdiYJ5@nXdIjS6luz=A~%`Vy=6Ge9>|Gh&tP$uvXNvy4XzNb z6s`(x6I>du4Q?;o<#56BkF^u-ez=doJr4KZ;JyX-1GwkmUWQ9xELIZS>2PPk6~Qfr zTLHHLF4zIFy5RP~T?uz1+}&^w!F>$w3vge7`wrZ{!Tkg-YaELe5BEB_8E_L=e><`a z#wxJ}qZ!QIbImACRj19BIpJ-iRc5x?EDGj73DzHreLWW50}H(ymhH^RmM@ZSVok)k z2Af$2xz1cgKK4yKHi`9c9BX3CM5 zCCMo%8+%TWtmN3lw_*x3$tg+iEXH;vq^8D5Wyz^Yo;BFl@$iO>pPb71W)Rz$ULI3i zo}8MpWeD4wz`8zJS5d-uIvR`?S6_XrmhY->#^A33!#GFp#}=p0XO)O_oaZ0I_NAxB zlvX4+C!Ku`J0G9gEH7;bC;Qg?>PBg|twdj4jLnO0=6vun_Imn5F-mLle9klfft`W> zsay`9#i94Gw@CP(%3b=t4vSLfYPJ?z4NX1R73@d`i?#YRB+0;^?X8#!#bhbx!YA0@ z(jShg6ehQD-oAppmYd3AIpNcPaOJqS;XPK>!s88_#`UMCvZ@<4CGFZd?zd#>qBylw zketW);GS_i((_m~4U0I79~w7!^XsfyCz*8D(Q!xO3to?@YfdhY`_qf#q>|*n#?;rr zJ39Htap-H(&inCiTNgdmfRBI z)Hr7f=iKg?l{afx)`nX-Umc9OkbXPMw#C4?@Mz4Z>CJLmgeOIObJFSG#w;V<2jra* zJKXWJIG?^0v-M^H%ii!a&iX&cY)PLlw?}LR#n0y)csJ%9_%7^jDC6}1Bj&I0+qxa$ z!p}LgI2SI&e4ai(#wp>qan61f^AGrnxhAJ_-dYy>1$_629^$;QKKAjWmGYj5;cWav zaRYb8=3b16>1|22bI#ly`*iw4a(6@_9zQ?h{s&@D$Ft&NGm|ArJD!X^Phit7PQ>7w zla&Xz67B-HF1YL9A`pBQ?i+B=!DR!wTn{%Nt{Scp?h?3n!aWWbf!Rg4Qvtk$a4X?D z;I4yv58UVAz6JLaxE!3tnhCcEZX?`IxczV;(uegl+z;S>1$S}`m{Y+mg?k&^6>#^! zeG=|#a6g6{1JIWaR}8lrt_$u?xR1g81Kdk+)8QpR4EL9CU2u28eGKj&;C={qJi%f? p@xiKwTLOPpOt|d#@0@-yR#NG^SvKEpU!9B*^Xx=t)%s> zcGtVBlXb=e!{mi_Lem!)k`Sl3F@dDE!MMS+1jtKqAb}($kU)5uw0UV~8WIu)LOSV8 zpWQv(tz_N$apRtSzJ~#GxBHX!r{AtV{{EiV2d)s(BFlV?S?2%a{g1ikI?Yup&UM*B zS-ElZ(2zUXS1puH?jx7)j~7k7pxW_Fyf{8KRxp)*B|A~vY}d{Bnz*4@T*gIyo;sHov9MM!)~nr@6b9uI1#*QJhMMuP@TN3S*`|`%*5AQ8~B)0Hr<$|+A%Ta zR&B#szs}kKCsq}!x*jVi6{V!cs#eT3V?0+cII+%{trn_zwcs5Rx};dqwBgjh-*Qkm z^E^LuUf}*XR#)tTv)X%mZ%V4`!fH4$3tOEs^{PLmH8aaG8mx`27$vn()NEC;EAXPS z;&j0;c{e+$>3Tdp+` zEHADV6W)Cbp6NdCiEsB^nH|yeQf@5|C-U$-xoTll^S+n7oD>8pElUYWO2KNG1+A!s zPbLK}#U+y*oYWP^9hw=i3GR8k+;0yKm>c)>c30H|UmA!XIPlf){%ZI8S?1#ya-1S^ z5IMZB+TtV!e2rUp0)N2(TX-KBvykDr0|y8)XNL@*NT-uH$UJ?;bibBH-hkU790u;2*IrW}DxIVgLvAPX{blVy#aT5*tNK80b?Ys4aA5wR%nT?z07 z3+&GzlLV4UNLQA~bEz~=CjIC`KlOUPAyJ3b#9)q5RC|0l?93!5>p8o z39YaE?Dg#+v<_pSMM8@lZA-z?M$EbZagJg-B|yk1CODw5`>`92vdrIOnDs#tS|qd< zr_lP1{C2^v?+hDy2yOFk4ryO02 z6j`Y34_T6h`LaKfu#-bZ7CiFjKkof7%N)TV=KF-0_9cUXUN zKg)au1E<@X3`n#ao6W{2skAhuQY)O`_jb{m6kjkKUl2tt86wA#>HU{o`L6Fj#xnO} zsC6e%izF3Esz$L9J{+(a6^9TWM}eK;8YPhs6Vn1R-eCB^wu6td%zYS$-9Zo|h!Moj z8Db%YMhrtUOp;SzhR4JothoK{^z$t9Sq#ID6T^sM#IWC(VZko5C5oK_73KmJBK27+ zEg@s8GCQ9<`DKRrT$pXwUKiAubgrwZeR^tgqg$D(3{MR>*^j?tf1{XWAJmQnH~MTf z%B0;RZ5bVsO_P&y+oq~>feU_R!$K@@xI1t>Z|Wu#unfxcc{Kq2s)BI^P6c%(TQ3VI znyX2|f!W%Di@X@1ETj`&>BP3h0Mlt+L<;TFqgOw&l4brOd?OoWM2GvQ1~zX>CXK9G zNNYXPTfY^`plY+&GZ81**_x66Uj;;4C+6K(zy46$Sd;ncgm%uvk%Wqc@?AXFQZ2OY zsGy{1RLM|ySPM19hM6s3#E4Mfy)vLwFq8_0dIdwFj254mhY@L>ld!OVV#m>mUY0qE zVZ`CEla?3}BStg`c##zqZtQ+3<^x-_FB&HaE{WV1kG#8U)pnLShQY}R!iitS98;y7 zB!^ej8w@!YqDDCyCyjxANeGZ@R61*>bXFu@1TLLI`af?ecK)TsGRHA^d5Z8tcv%cB z5E|4tt6FIcoW%dd&Vll z5DG&nPDWzr@$Zcv`54PQfWgqu2}6V-!jOldKqZmi5WEL%drw7f&Y)nQjNF|4e($cY zUCS~j+Tm$zbR;!Cv?-+w42n{X+xm;JyJ^elWMz9&>`w@};VETr0w%g(?xxm>!L`rT z-BfAoMrw98wI4I*YN~im_S&_lD^{T`p4X6#Turdmq26>}Prinqe1Wo)ejvNVh=k!VT7J_cv&y=}wz>(CMEA2DcY>Ig+Dg;a{) zO?|Pdlrzv07*1LW$nohkF$cpOiGwyQIOa^<^%rj~Uv}B&8_eNO{P4Lv%Pw2CjA_K{ zw%RG4AXP)EMz!;PoIL#17MO=FZS+w8r`cSONSln5kVRzw%OCvmzWZ-tnTHzWi9*iv zgd9T7l0!~N6_HoF5=y0wMo>B>A;r&;4;u|Jb*qLNUeMrCZ=ZiU8Th08Lgg95v@41p9GOyVO@XTA zx>iy=@4M6XY+kXNPt;VcRCY57j_cG_7yS7husYrbt?_cxw#tg(WQ0yv-RE{_MnN^) zjJFj2?=BQacZx6%7;mVZuqbBD8(f1$oP8^AbVp6iO=@n3|0>6|%}I4;3B9wmvgWG( zc(rlioRXg`*=E%!bj&T6kbw0P65iU1!s=iO1r>bCimRDM2i%SPq@g-aMl&>5gSGK5 z7a9>P+<{?Bu}H zkH-_snSaJerQ5F}Q&G?yj-(PvC6Y>KG)N?=L{h1!*{WiDo`bUDbiprqH#@26dOTB9 zbVv1EK(oij6ukrbp*Wy^q1t^t8N^Cj8e5& zghd8p-;Q0Ox}#>zfGobUW(Bn>i%L~@{oB$vF+Mp|8m*POws2$HdQ0()2ye33lQ|-# zQ%b-_KbBU$`rAXxnMW|v=`$pq$jU@swplOT`S)@(=PlO@4rDja`Z?BH%K1V1l@>I z(7ZPR^#*!xNtW!OMsbZsadMQV5;z`Pi=$$$`t`2m%oi}4>LJopq^U?#k*0#^If|US z6eH)zb9d=@?izNhhAD5Ryje?@uE2qu3=CW_kP=s#5?3NMmXP9+(NWz`f9dM#a^_Kt z#`*?nEYet{u}EW)#=1na6G&r`#-duYpf$y{+*%$io$YJQMrtp~?`ejKOuu&Y+2ihV z<}r-+dWN(YX)n@Vq`gRck@lj@Jg^5@_JU{THLOwR9&QD%Y}e$d@rJYJtzew!hhD)8 z6vHc&P3^(wN=8LVFEI%v6L3j^>ZVt=y@zEUZzsKsfo?wCy>)Y`r=*F=p6NHkW&UfG z$!(L>@h$ayrLr-r^ngZOu%Za96N77?YnlHb6vo=H-r8{1wDdDaow+@Z)zPG0GcWa5_;$r{Fb}P6;AEZ{D!X^Bl7AeC)ZQ_w}&M7cq#qJ6u(c5E0o_nh>!F zn!r+O-Arm-G))poEKP3z=@0AMSmsL@nmj->LAO04nk)jEgtj?U??3FtkEV+(LD4W& zjg!^yy)SOE%$G5Ad6MWtbg_q*o}-I24Mx+XI8K7?6UKk_<{iUFZf2RUV5su~QHQ9r z6sZ%^J`}--);=jQnS$U?4251$l0UhVW&Q<2q1TB*L?NOO^^^7-ZjmuQkvp?gQcNJ5 zJf0GN`QS>Hd7>SigyhgPrzvA&Tz#rr7&PAsJDU2{p6b^0)ZkE^(@RR)3r1QnM^o#> zE<#6>WrBCqGRf0)A^hOvX$m||2`LE%nsz;%rcQUN$_c;S>~~kokzE`%vUiuIYBrie2xlzJpZ@)x1hHA{z1J zbvnD(DQb_#CuD3@pI?7#-+TU$Wxn2yQUjv0Wuo8NBUsYL($w_Ex5HkiZmHKSrQO^O zePw>S#K{Zkb!wg1Md)>!((Q1U$G&5ETOP#3$>+&{HYwR9~Hj=AQ;>ORY~FHEb|R1{DW zTv|W|yWHIK>`N0Y^9%+kCkZI%T@e9gaR4P`eIegdll3JMFbN@*z{UE$oE2xAKT;z#PX)?+*j53iZ zNeS3kyuW_!)xQChe49`bbIlmv)voLH|D}j8q2wY*3AGw-v>HxDpaj|nideJCO^1qm zM_J}M3`&lXDnXl72qhOgNw@oY$MSkLNqSUAoB9gt6tGr=6MWSo*=XkT2wo) z8KrmzcH4ouCtJZQ#RdF)r&q}4Doempe3-up3&u(Hb#hzk-#Nn2^l7H&$jf{ zH?hojFvxkHkVD8>a>xmxiTu=f)g$u~GEefE>sQ=+kY&D$LC|Z2AVLr!C{Rb_p$2u^ z-a{R^Axq0x5B1F-IC0wwmU*Ean)c=rdA?R0p6Jf^Xq&5JZ-hP6+2QKo_FP4tG^Ynk za@mH7E?7y<)`@vrfV$(V6~9%W>f~+Bay8R{O#<|GTUD&;daR&Sl#&{&TE2Oh^LoF< z)~`F$B7FYr#sW->T-4;EzA!H8G$*D(p0usUDG0E~LT;Zn3?A;^%rY-x0P(4?b|FC6 zXYo-JAgCDUqDYC1WQoY3_d)A!{N(R#Wts0`SaO_Lg0B=)s}V~sZkB{>EaX`V+gPI6 zB1kC#=UGbMd%IL&nU^qZIZbRKwouPE*fm3u1>d)3)(q8l%9<7Ipo>aX4^H$=j86`g zMr)<6E!^0)Uhu?;P=bQI)eDRcch-QwM#u`ud8vJJuu*}OC=6r{k zL(Exv%n9ip@-5+Yk0fx&1_uwk`&ZTI5 Kl#;Oe=zjrw2Gj%q literal 0 HcmV?d00001 diff --git a/packs-system/weapons/CURRENT b/packs-system/weapons/CURRENT new file mode 100644 index 0000000..d95f027 --- /dev/null +++ b/packs-system/weapons/CURRENT @@ -0,0 +1 @@ +MANIFEST-000031 diff --git a/packs-system/weapons/LOCK b/packs-system/weapons/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs-system/weapons/LOG b/packs-system/weapons/LOG new file mode 100644 index 0000000..af4b43d --- /dev/null +++ b/packs-system/weapons/LOG @@ -0,0 +1,3 @@ +2025/07/14-21:08:15.933872 7f3fa6ffd6c0 Recovering log #29 +2025/07/14-21:08:15.943722 7f3fa6ffd6c0 Delete type=3 #27 +2025/07/14-21:08:15.943845 7f3fa6ffd6c0 Delete type=0 #29 diff --git a/packs-system/weapons/LOG.old b/packs-system/weapons/LOG.old new file mode 100644 index 0000000..1fdda04 --- /dev/null +++ b/packs-system/weapons/LOG.old @@ -0,0 +1,8 @@ +2025/07/14-10:18:19.404246 7f3fa5ffb6c0 Recovering log #25 +2025/07/14-10:18:19.435628 7f3fa5ffb6c0 Delete type=3 #23 +2025/07/14-10:18:19.435765 7f3fa5ffb6c0 Delete type=0 #25 +2025/07/14-20:48:52.908846 7f3fa57fa6c0 Level-0 table #30: started +2025/07/14-20:48:52.908888 7f3fa57fa6c0 Level-0 table #30: 0 bytes OK +2025/07/14-20:48:52.915004 7f3fa57fa6c0 Delete type=0 #28 +2025/07/14-20:48:52.915133 7f3fa57fa6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) +2025/07/14-20:48:52.928670 7f3fa57fa6c0 Manual compaction at level-1 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end) diff --git a/packs-system/weapons/MANIFEST-000031 b/packs-system/weapons/MANIFEST-000031 new file mode 100644 index 0000000000000000000000000000000000000000..51b9aba1f998216bc635a20f5061bcca02f61dea GIT binary patch literal 157 zcmWHr^gGzbz{n_-lUkOVlai$8R9TW*o>`pgoS$2eSd>_jU&P8Nub5eqnp><`RaxO^ z>5}1ZY*u3G@8nX(XwCoz>`Z)9FR>~rrse0Pq!tw`8n}2GhZtp*r5fiI=N6|$F)oCt YBV^7U&2RHL85o%qI2o7~S*9}s0EBZZ7ytkO literal 0 HcmV?d00001 diff --git a/styles/global.less b/styles/global.less index c21a984..3dcd0d8 100644 --- a/styles/global.less +++ b/styles/global.less @@ -98,6 +98,23 @@ i.fvtt-cthulhu-eternal { color: var(--color-critical-failure); font-family: var(--font-title); } + .san-type-buttons { + display: flex; + justify-content: center; + align-items: center; + margin: 10px 0; + button { + margin: 0 2px; + font-family: var(--font-primary); + font-size: calc(var(--font-size-standard) * 0.9); + border: none; + padding: 2px 2px; + cursor: pointer; + transition: background-color 0.3s; + min-width: 6.0rem; + max-width: 6.0rem; + } + } .san-loose-buttons { display: flex; justify-content: center; diff --git a/styles/protagonist.less b/styles/protagonist.less index 2b162f3..55cbc4d 100644 --- a/styles/protagonist.less +++ b/styles/protagonist.less @@ -478,7 +478,7 @@ } .weapons { display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(1, 1fr); gap: 4px; .weapon { display: flex; @@ -496,10 +496,24 @@ min-width: 1.8rem; max-width: 1.8rem; } - .damage { + .range { min-width: 6rem; max-width: 6rem; } + .ammo { + min-width: 4rem; + max-width: 4rem; + } + .lethality { + display: flex; + min-width: 3.2rem; + max-width: 3.2rem; + } + .damage { + display: flex; + min-width: 12rem; + max-width: 12rem; + } .name { min-width: 10rem; max-width: 10rem; diff --git a/styles/weapon.less b/styles/weapon.less index 06d9f8d..205ccc5 100644 --- a/styles/weapon.less +++ b/styles/weapon.less @@ -14,6 +14,24 @@ fieldset { margin-top: 8px; background-color: var(--color-light-1); + input { + max-width: 5rem; + min-width: 5rem; + } + select { + max-width: 14rem; + min-width: 14rem; + } + input[type="checkbox"] { + max-width: 1.5rem; + min-width: 1.5rem; + } + .flexrow > *:not(:first-child) { + margin-left: 1rem; + } + .damage-distance { + margin-left: 2rem; + } } label { diff --git a/system.json b/system.json index 431185c..481aeb8 100644 --- a/system.json +++ b/system.json @@ -152,6 +152,18 @@ }, "flags": {} }, + { + "name": "weapons", + "label": "Weapons", + "system": "fvtt-cthulhu-eternal", + "path": "packs-system/weapons", + "type": "Item", + "ownership": { + "PLAYER": "OBSERVER", + "ASSISTANT": "OWNER" + }, + "flags": {} + }, { "name": "rituals", "label": "Rituals", diff --git a/templates/chat-lethal-damage.hbs b/templates/chat-lethal-damage.hbs index 51620c9..9309545 100644 --- a/templates/chat-lethal-damage.hbs +++ b/templates/chat-lethal-damage.hbs @@ -8,11 +8,15 @@ {{#if weapon.system.selectiveFireChoice}}

  • {{weapon.system.selectiveFireChoiceLabel}}
  • {{/if}} - {{#if weapon.system.killRadius}} + {{#if (gt weapon.system.killRadius 0)}}
  • {{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}
  • {{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}
  • {{/if}} + {{#if (gt weapon.system.armorPiercing 0)}} +
  • {{localize "CTHULHUETERNAL.Label.armorPiercing"}} : {{weapon.system.armorPiercing}}
  • + {{/if}} + {{#if ammoUsed}}
  • {{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}
  • {{/if}} diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index 369718f..9f1d595 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -15,7 +15,7 @@ {{/if}} {{#if isNudgedRoll}} -
  • {{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} WP spent
  • +
  • {{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} {{localize "CTHULHUETERNAL.Label.WPSpent"}}
  • {{/if}} {{#if weapon}} @@ -43,26 +43,13 @@ {{#if (eq rollType "resource")}}
  • {{localize "CTHULHUETERNAL.Label.multiplier"}} : {{multiplier}}
  • {{else}} -
  • {{localize "CTHULHUETERNAL.Label.modifier"}} : {{modifier}}%
  • +
  • {{localize "CTHULHUETERNAL.Label.modifier"}} : {{totalModifier}}%
  • {{/if}}
  • {{localize "CTHULHUETERNAL.Label.targetScore"}} : {{targetScore}}%
  • {{#if isSuccess}} {{#if isCritical}}
  • {{localize "CTHULHUETERNAL.Label.criticalSuccess"}} - {{#if (eq rollType "weapon")}} - {{#if (eq weapon.system.weaponType "rangedfirearm")}} - - {{else}} - - {{/if}} - {{/if}} - {{#if (eq rollType "skill") }} - {{#if rollItem.system.isHealing}} - - {{/if}} - {{/if}} -
  • {{else}}
  • @@ -70,38 +57,58 @@ {{#if isNudge}} {{/if}} - {{#if (eq weapon.system.weaponType "rangedfirearm")}} - + +
  • + {{/if}} + {{#if (eq rollType "weapon")}} +
  • + {{#if (eq weapon.system.weaponType "rangedfirearm")}} + {{#if weapon.system.hasDamageDistance}} + {{#each weapon.system.damageDistance as |damageDistance|}} + {{#if (gt damageDistance.distance 0)}} + + + {{damageDistance.distance}}:{{damageDistance.damage}}   + + {{/if}} + {{/each}} {{else}} - + {{/if}} + {{else}} + + {{/if}} +
  • + {{/if}} {{#if (eq rollType "skill") }} {{#if rollItem.system.isHealing}} +
  • +
  • {{/if}} {{/if}} - {{/if}} {{/if}} {{#if isFailure}} - {{#if isCritical}} -
  • {{localize "CTHULHUETERNAL.Label.criticalFailure"}} - {{#if (eq rollType "skill") }} - {{#if rollItem.system.isHealing}} - - {{/if}} - {{/if}} + {{#if isCritical}} +
  • {{localize "CTHULHUETERNAL.Label.criticalFailure"}} +
  • + {{else}} +
  • + {{localize "CTHULHUETERNAL.Label.failure"}}
  • - {{else}} -
  • - {{localize "CTHULHUETERNAL.Label.failure"}} - {{#if isNudge}} - {{/if}} -
  • - {{/if}} + + {{#if isNudge}} +
  • + +
  • + {{/if}} + + {{/if}} diff --git a/templates/chat-regular-damage.hbs b/templates/chat-regular-damage.hbs index 354c17e..7c7cba3 100644 --- a/templates/chat-regular-damage.hbs +++ b/templates/chat-regular-damage.hbs @@ -4,11 +4,15 @@
  • {{weapon.name}} : {{localize "CTHULHUETERNAL.Label.damageRoll"}}
  • {{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{formula}})
  • - {{#if weapon.system.killRadius}} + {{#if (gt weapon.system.killRadius 0)}}
  • {{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}
  • {{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}
  • {{/if}} + {{#if (gt weapon.system.armorPiercing 0)}} +
  • {{localize "CTHULHUETERNAL.Label.armorPiercing"}} : {{weapon.system.armorPiercing}}
  • + {{/if}} + {{#if ammoUsed}}
  • {{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}
  • {{/if}} diff --git a/templates/chat-san-loss-none.hbs b/templates/chat-san-loss-none.hbs new file mode 100644 index 0000000..e86e01c --- /dev/null +++ b/templates/chat-san-loss-none.hbs @@ -0,0 +1,8 @@ +
    +
    +
      +
    • {{localize "CTHULHUETERNAL.Label.SANLossNone"}}
    • +
    + +
    +
    \ No newline at end of file diff --git a/templates/chat-san-loss-unnatural.hbs b/templates/chat-san-loss-unnatural.hbs new file mode 100644 index 0000000..0f1bdb3 --- /dev/null +++ b/templates/chat-san-loss-unnatural.hbs @@ -0,0 +1,8 @@ +
    +
    +
      +
    • {{localize "CTHULHUETERNAL.Label.SANLossUnnatural"}}
    • +
    + +
    +
    \ No newline at end of file diff --git a/templates/chat-san-request.hbs b/templates/chat-san-request.hbs index 872841b..247e6dc 100644 --- a/templates/chat-san-request.hbs +++ b/templates/chat-san-request.hbs @@ -1,7 +1,11 @@
      -
    • {{localize "CTHULHUETERNAL.Label.SANTest"}}
    • + {{#if rollData.isSuccess}} +
    • {{localize "CTHULHUETERNAL.Label.SANTestSuccess"}}
    • + {{else}} +
    • {{localize "CTHULHUETERNAL.Label.SANTestFailure"}}
    • + {{/if}}
    • diff --git a/templates/protagonist-equipment.hbs b/templates/protagonist-equipment.hbs index 046fe9d..fb87e7b 100644 --- a/templates/protagonist-equipment.hbs +++ b/templates/protagonist-equipment.hbs @@ -16,11 +16,64 @@ {{item.name}}
    - - - {{localize "CTHULHUETERNAL.Label.damageShort"}} : - {{item.system.damage}} +
    + {{#if (eq system.lethality 0)}} + + + {{#if item.system.hasDamageDistance}} + {{#each item.system.damageDistance as |damageDistance|}} + {{#if (gt damageDistance.distance 0)}} + + {{damageDistance.distance}}:{{damageDistance.damage}}   + + {{/if}} + {{/each}} + {{else}} + + {{item.system.damage}} + + {{/if}} + {{else}} + N/A + {{/if}} +
    + + {{#if (gt system.baseRange 0)}} + {{item.system.baseRange}} {{item.system.rangeUnit}} + {{else}} + {{localize "CTHULHUETERNAL.Label.melee"}} + {{/if}} + + {{#if (gt system.lethality 0)}} + + + {{item.system.lethality}}% + + {{else}} + - + {{/if}} + + {{#if (gt system.killRadius 0)}} + {{item.system.killRadius}} + {{else}} + - + {{/if}} + + {{#if (gt system.armorPiercing 0)}} + {{item.system.armorPiercing}} + {{else}} + - + {{/if}} + + {{#if (eq system.weaponType "rangedfirearm")}} + {{item.system.ammo.value}}/{{item.system.ammo.max}} + {{else}} + N/A + {{/if}} +
    diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index d356f21..d8fb685 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -12,28 +12,87 @@
    {{rollItem.name}} : {{initialScore}} ({{mul initialScore 5}}%)
    {{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}}
    {{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}}
    -
    {{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}}
    +
    + {{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} + +
    {{else}}
    {{rollItem.name}} : {{initialScore}}%
    {{/if}} {{#if weapon}}
    {{localize "CTHULHUETERNAL.Label.Weapon"}} : {{weapon.name}}
    + + {{#if (eq weapon.system.weaponType "melee")}} +
    + {{localize "CTHULHUETERNAL.Label.targetMove"}} + +
    + {{/if}} + {{#if isRangedWeapon}} +
    + {{localize "CTHULHUETERNAL.Label.rangedRange"}} + +
    +
    + {{localize "CTHULHUETERNAL.Label.targetMove"}} + +
    + +
    + {{localize "CTHULHUETERNAL.Label.aimingLastRound"}} + +
    + {{#if weapon.system.hasSight}} +
    + {{localize "CTHULHUETERNAL.Label.aimingWithSight"}} + +
    + {{/if}} + + {{/if}} + +
    + {{localize "CTHULHUETERNAL.Label.visibility"}} + +
    +
    + {{localize "CTHULHUETERNAL.Label.attackerState"}} + +
    +
    + {{localize "CTHULHUETERNAL.Label.targetSize"}} + +
    + {{#if weapon.system.hasSelectiveFire}}
    Selective Fire :
    {{/if}} + {{/if}} {{#if isZeroWP}}
    {{localize "CTHULHUETERNAL.Label.ZeroWP"}}
    {{else}} - {{#if isLowWP}} -
    {{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%
    - {{/if}} + {{#if isLowWP}} +
    {{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%
    + {{/if}} {{/if}} {{#if isExhausted}} diff --git a/templates/weapon.hbs b/templates/weapon.hbs index 100fc62..82fe4d0 100644 --- a/templates/weapon.hbs +++ b/templates/weapon.hbs @@ -12,32 +12,60 @@ {{/if}} {{formField systemFields.state value=system.state localize=true}} + {{formField systemFields.isStunning value=system.isStunning localize=true}} +
    {{formField systemFields.hasDirectSkill value=system.hasDirectSkill }} {{#if system.hasDirectSkill}} {{formField systemFields.directSkillValue value=system.directSkillValue }} {{/if}} +
    - {{formField systemFields.applyDamageBonus value=system.applyDamageBonus}} - {{formField systemFields.damage value=system.damage}} +
    + {{formField systemFields.hasDamageDistance value=system.hasDamageDistance localize=true}} +
    - {{#if isRanged}} - {{formField systemFields.baseRange value=system.baseRange}} - {{formField systemFields.rangeUnit value=system.rangeUnit localize=true}} + {{#if system.hasDamageDistance}} + {{#each system.damageDistance as |damageDistance idx|}} +
    + + +
    + {{/each}} + {{else}} +
    + {{formField systemFields.damage value=system.damage}} + {{formField systemFields.applyDamageBonus value=system.applyDamageBonus}} +
    + {{#if isRanged}} +
    + {{formField systemFields.baseRange value=system.baseRange}} + {{formField systemFields.rangeUnit value=system.rangeUnit localize=true}} +
    + {{/if}} {{/if}} {{#if isFireArm}} +
    {{formField systemFields.hasSelectiveFire value=system.hasSelectiveFire}} + {{formField systemFields.hasSight value=system.hasSight}} +
    +
    {{formField systemFields.ammo.fields.value value=system.ammo.value}} {{formField systemFields.ammo.fields.max value=system.ammo.max}} +
    {{/if}} - {{formField systemFields.lethality value=system.lethality}} - {{formField systemFields.killRadius value=system.killRadius}} +
    + {{formField systemFields.lethality value=system.lethality}} + {{formField systemFields.killRadius value=system.killRadius}} +
    +
    {{formField systemFields.armorPiercing value=system.armorPiercing}} - {{formField systemFields.resourceLevel value=system.resourceLevel}} +
    +