6 Commits

Author SHA1 Message Date
68a0d03740 Update fight options
All checks were successful
Release Creation / build (release) Successful in 53s
2025-11-11 19:56:33 +01:00
8d9cc1045c Fix licence 2025-10-01 15:14:58 +02:00
4af277d8a2 Fight helper ! 2025-10-01 11:24:41 +02:00
bc9f397755 Fix initiative 2025-09-30 17:44:39 +02:00
264a5c7a4c Fix HP and other derivated values not computed anymore
All checks were successful
Release Creation / build (release) Successful in 2m57s
2025-08-10 19:33:28 +02:00
4edbc9b618 Translate weapons + skills in columns
All checks were successful
Release Creation / build (release) Successful in 3m43s
2025-07-29 18:29:02 +02:00
46 changed files with 1114 additions and 263 deletions

View File

@@ -0,0 +1,6 @@
Code license :
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
This license requires that reusers give credit to the creator. It allows reusers to distribute, remix, adapt, and build upon the material in any medium or format, for noncommercial purposes only. If others modify or adapt the material, they must license the modified material under identical terms.

View File

@@ -0,0 +1,389 @@
{
"label": "Armes",
"folders": {
"Automatic and Heavy Weapons": "Automatiques et armes lourdes",
"Firearms": "Armes à feu",
"Melee Weapons": "Armes de mêlée",
"Ranged Weapons": "Armes à distance",
"Ranged weapons": "Armes à distance",
"Thermal Weapons": "Armes thermiques",
"Weapons - Age Of Revolutions": "Armes - Âge des Révolutions",
"Weapons - Age Of Sails": "Armes - Âge de la Voile",
"Weapons - Classical Era": "Armes - Époque Classique",
"Weapons - Cold War": "Armes - Guerre Froide",
"Weapons - Future": "Armes - Futur",
"Weapons - Jazz": "Armes - Jazz/Années folles",
"Weapons - Medieval": "Armes - Médiévales",
"Weapons - Modern": "Armes - Modernes",
"Weapons - Post Apocalyptic": "Armes - Post-apocalyptiques",
"Weapons - Victorian": "Armes - Victoriennes",
"Weapons - World War I": "Armes - Première Guerre mondiale",
"Weapons - World War II": "Armes - Seconde Guerre mondiale"
},
"mapping": {
"rangeUnit": {
"path": "system.rangeUnit",
"converter": "translateRangeUnit"
},
"baseRange": {
"path": "system.baseRange",
"converter": "translateRange"
}
},
"entries": {
"Anti-tank rifle": {
"name": "Arme antichar"
},
"Assault rifle": {
"name": "Fusil d'assaut"
},
"Axe": {
"name": "Hache"
},
"Bare hands and feet": {
"name": "Mains et pieds nus"
},
"Baseball Bat": {
"name": "Batte de baseball"
},
"Baseball bat": {
"name": "Batte de baseball"
},
"Battle laser": {
"name": "Laser de combat"
},
"Battle rifle": {
"name": "Fusil de combat"
},
"Bayonet": {
"name": "Baïonnette"
},
"Blackjack": {
"name": "Blackjack"
},
"Blunderbuss Pistol": {
"name": "Pistolet tromblon"
},
"Bow": {
"name": "Arc"
},
"Brass knuckles": {
"name": "Poings américains"
},
"Broad sword": {
"name": "Épée large"
},
"Buffalo Rifle": {
"name": "Fusil Buffalo"
},
"Cane Gun": {
"name": "Pistolet canne"
},
"Cannon Barrel Pistol": {
"name": "Pistolet canon"
},
"Carbine": {
"name": "Carabine"
},
"Cavalry lance": {
"name": "Lance de cavalerie"
},
"Cavalry sabre": {
"name": "Sabre de cavalerie"
},
"Ceramic Grenade": {
"name": "Grenade en céramique"
},
"Chainsaw": {
"name": "Tronçonneuse"
},
"Claymore": {
"name": "Claymore"
},
"Club": {
"name": "Gourdin"
},
"Combat knife": {
"name": "Couteau de combat"
},
"Cosh": {
"name": "Matraque"
},
"Cricket bat": {
"name": "Batte de cricket"
},
"Crossbow": {
"name": "Arbalète"
},
"Cutlass": {
"name": "Coutelas"
},
"Dagger": {
"name": "Dague"
},
"Derringer": {
"name": "Derringer"
},
"Dueling Pistol": {
"name": "Pistolet de duel"
},
"Dutch (long) Pistol": {
"name": "Pistolet néerlandais (long)"
},
"Elephant Gun": {
"name": "Fusil à éléphant"
},
"Flintlock Pistol": {
"name": "Pistolet à silex"
},
"Fowling Piece": {
"name": "Fusil de chasse"
},
"Garotte": {
"name": "Garrot"
},
"Gatling Gun": {
"name": "Gatling Gun"
},
"Guntō": {
"name": "Guntō"
},
"Hand Grenade": {
"name": "Grenade à main"
},
"Hand grenade": {
"name": "Grenade à main"
},
"Hatchet": {
"name": "Hachette"
},
"Heavy Pistol": {
"name": "Pistolet lourd"
},
"Heavy Spear": {
"name": "Lance lourde"
},
"Heavy axe": {
"name": "Hache lourde"
},
"Heavy hammer": {
"name": "Marteau lourd"
},
"Heavy pistol": {
"name": "Pistolet gros calibre"
},
"Heavy spear": {
"name": "Lance lourde"
},
"Incendiary Grenade": {
"name": "Grenade incendiaire"
},
"Javelin": {
"name": "Javelot"
},
"Katana": {
"name": "Katana"
},
"Knife": {
"name": "Couteau"
},
"Large Caliber Pistol": {
"name": "Pistolet gros calibre"
},
"Large sword": {
"name": "Grande épée"
},
"Laser carbine": {
"name": "Carabine laser"
},
"Life preserver": {
"name": "Gilet de sauvetage"
},
"Light Spear": {
"name": "Lance légère"
},
"Light axe": {
"name": "Hache légère"
},
"Light spear": {
"name": "Lance légère"
},
"Long spear": {
"name": "Lance longue"
},
"Long sword": {
"name": "Epée longue"
},
"Longrifle": {
"name": "Fusil long"
},
"Mace": {
"name": "Masse"
},
"Machete": {
"name": "Machette"
},
"Maxim": {
"name": "Maxime"
},
"Medium Pistol": {
"name": "Pistolet moyen"
},
"Musket": {
"name": "Mousquet"
},
"Nightstick": {
"name": "Matraque"
},
"Oil": {
"name": "Huile"
},
"Ordinary knife": {
"name": "Couteau ordinaire"
},
"Plasma rifle": {
"name": "Fusil à plasma"
},
"Polearm": {
"name": "Arme d'hast"
},
"Power sword": {
"name": "Epée énergétique"
},
"Rapier": {
"name": "Rapière"
},
"Rifle": {
"name": "Fusil"
},
"Sabre": {
"name": "Sabre"
},
"Scimitar": {
"name": "Cimeterre"
},
"Seax": {
"name": "Seax"
},
"Shield bash": {
"name": "Coup de bouclier"
},
"Shiv": {
"name": "Shiv"
},
"Short spear": {
"name": "Lance courte"
},
"Short sword": {
"name": "Epée courte"
},
"Shotgun": {
"name": "Shotgun"
},
"Shuriken": {
"name": "Shuriken"
},
"Sickle": {
"name": "Faucille"
},
"Sling": {
"name": "Fronde"
},
"Small-caliber pistol": {
"name": "Pistolet de petit calibre"
},
"Smallcaliber pistol": {
"name": "Pistolet de petit calibre"
},
"Staff": {
"name": "Bâton"
},
"Steel-toe boot": {
"name": "Botte à embout en acier"
},
"Steeltoe boot": {
"name": "Botte à embout en acier"
},
"Submachine gun": {
"name": "Pistolet-mitrailleur"
},
"Sulphur soaked cloth": {
"name": "Tissu imbibé de soufre"
},
"Switchblade": {
"name": "Couteau à cran d'arrêt"
},
"Sword cane": {
"name": "Canne épée"
},
"Taser": {
"name": "Taser"
},
"Thompson": {
"name": "Thompson"
},
"Thrown Axe": {
"name": "Hache de lancer"
},
"Thrown Hand Grenade": {
"name": "Grenade à main de lancer"
},
"Thrown Heavy Spear": {
"name": "Lance lourde lancée"
},
"Thrown Knife": {
"name": "Couteau de lancer"
},
"Thrown Light Spear": {
"name": "Lance légère lancée"
},
"Thrown Long Spear": {
"name": "Lance longue lancée"
},
"Thrown Net": {
"name": "Filet"
},
"Thrown Rock": {
"name": "Pierre lancée"
},
"Thrown Short Spear": {
"name": "Lance courte lancée"
},
"Thrown Spear": {
"name": "Lance lancée"
},
"Thrown Spear, Heavy": {
"name": "Lance lancée, lourde"
},
"Thrown Spear, Light": {
"name": "Lance lancée, légère"
},
"Tomahawk": {
"name": "Tomahawk"
},
"Trident": {
"name": "Trident"
},
"Two-Handed sword": {
"name": "Epée à deux mains"
},
"Two-handed sword": {
"name": "Epée à deux mains"
},
"Very heavy sniper laser": {
"name": "Laser lourd de sniper"
},
"Very heavy sniper rifle": {
"name": "Fusil lourd de sniper"
},
"Very large pistol": {
"name": "Pistolet très gros calibre"
},
"WW1 Machinegun": {
"name": "Mitrailleuse de la Première Guerre mondiale"
},
"War club": {
"name": "Massue de guerre"
}
}
}

View File

@@ -3041,6 +3041,9 @@ i.fvtt-cthulhu-eternal {
font-size: calc(var(--font-size-standard) * 2);
color: var(--color-dark-1);
}
.li-apply-wounds {
display: none;
}
.dice-roll {
flex-direction: column;
}

View File

@@ -29,6 +29,12 @@ Hooks.once("init", function () {
models,
documents,
}
// Set an initiative formula for the system
CONFIG.Combat.initiative = {
formula: "@characteristics.dex.value",
decimals: 1
};
CONFIG.Actor.documentClass = documents.CthulhuEternalActor
CONFIG.Actor.dataModels = {
@@ -93,13 +99,14 @@ Hooks.once("init", function () {
CthulhuEternalUtils.registerSettings()
CthulhuEternalUtils.registerHandlebarsHelpers()
CthulhuEternalUtils.setupCSSRootVariables()
CONFIG.debug.hooks = false;
console.info("CTHULHU ETERNAL | System Initialized")
})
Hooks.once('babele.init', (babele) => {
babele.setSystemTranslationsDir("compendiums");
babele.setSystemTranslationsDir("compendiums");
CthulhuEternalUtils.registerBabeleTranslations(babele);
});
/**
@@ -164,6 +171,15 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
CthulhuEternalUtils.applySANType(message, event)
})
}
if (game.user.isGM) {
$(html).find(".li-apply-wounds").each((i, btn) => {
btn.style.display = "inline"
})
$(html).find(".li-apply-wounds-select").click((event) => {
CthulhuEternalUtils.applyWounds(message, event)
})
}
})
/**

View File

@@ -205,6 +205,7 @@
"Struggle": "Struggle"
},
"Skill": {
"DodgeName": "Dodge",
"Unnatural": "Unnatural",
"Melee": "Melee Weapons",
"Firearms": "Firearms",
@@ -552,6 +553,10 @@
}
},
"Label": {
"noTarget": "No target selected",
"noDefenseRoll": "No defense roll available",
"opposedRoll": "Opposed Roll",
"Target": "Target",
"sanLoss5": "You suffered a SAN loss of 5+ ({value}) : you suffer a temporary insanity (Flee, Submit, Struggle or understanding the Unnatural).",
"sanViolenceReset": "The violence SAN loss count has been reset.",
"sanHelplessnessReset": "The helplessness SAN loss count has been reset.",
@@ -730,7 +735,8 @@
"visibility": "Visibility",
"rangedRange": "Range",
"aimingLastRound": "Aiming Last Round (+20)",
"aimingWithSight": "Aiming with Sight (+20)"
"aimingWithSight": "Aiming with Sight (+20)",
"applyWounds": "Apply To"
},
"ChatMessage": {
"exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points."
@@ -755,8 +761,12 @@
"rollDamage": "Roll Damage"
},
"Chat": {
"noArmor": "No armor absorbed damage.",
"armorAbsorbed": "Armor absorbed {armor} damage.",
"woundsApplied": "Wounds applied to {name}: {effectiveWounds} (armor absorbed : {armorText})"
},
"Notifications": {
"AttackNoTarget": "No target selected for the attack, please select one target to get automations.",
"NoWeaponSkill": "No weapon skill found for this weapon. Check Weapon definition or available skills/era",
"NoWeaponType": "No weapon type found for this weapon subtype. Check Weapon definition or available skills/era",
"skillAlreadyExists": "Skill already exists",

View File

@@ -217,6 +217,7 @@
"Struggle": "Lutter"
},
"Skill": {
"DodgeName": "Esquive",
"Unnatural": "Inconcevable",
"Melee": "Armes de mêlée",
"Firearms": "Armes à feu",
@@ -564,6 +565,17 @@
}
},
"Label": {
"noTarget": "Aucune cible sélectionnée",
"noDefenseRoll": "Aucun jet de défense existant",
"opposedRoll": "Jet opposé",
"Target": "Cible",
"feet": "pieds (ie 30cm)",
"feets": "pieds (ie 30cm)",
"yard": "mètres",
"Yard": "mètres",
"yards": "mètres",
"Feet": "Pieds",
"Yards": "Mètres",
"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é.",
@@ -744,7 +756,8 @@
"visibility": "Visibilité",
"rangedRange": "Portée",
"aimingLastRound": "Visée lors du dernier round (+20)",
"aimingWithSight": "Visée avec lunette (+20)"
"aimingWithSight": "Visée avec lunette (+20)",
"applyWounds": "Appliquer à"
},
"ChatMessage": {
"exhausted": "Votre protagoniste est épuisé. Il perd [[/r 1d6]] Points de Volonté."
@@ -769,8 +782,12 @@
"rollDamage": "Lancer les dégâts"
},
"Chat": {
"armorAbsorbed": "L'armure a absorbé {armor} points de dégâts.",
"noArmor": "Pas d'armure.",
"woundsApplied": "Blessures appliquées à {name} : {effectiveWounds} (armure absorbée : {armorText})"
},
"Notifications": {
"AttackNoTarget": "Aucune cible n'a été sélectionnée pour cette attaque, veuillez sélectionner une cible pour bénéficier des automatisations.",
"NoWeaponSkill": "Aucune compétence associée n'a été trouvé pour cette arme. Vérifier la définition de l'arme ainsi que l'époque configurée.",
"NoWeaponType": "Aucun type d'arme trouvé pour ce sous-type. Vérifier la définition de l'arme ainsi que l'époque configurée.",
"skillAlreadyExists": "La compétence existe déja",

View File

@@ -98,10 +98,20 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
switch (partId) {
case "main":
break
case "skills":
case "skills": {
context.tab = context.tabs.skills
context.skills = doc.itemTypes.skill
context.skills.sort((a, b) => a.name.localeCompare(b.name))
let tmpSkills = doc.itemTypes.skill
tmpSkills.sort((a, b) => a.name.localeCompare(b.name))
const nbCols = 3;
const nbRows = Math.ceil(tmpSkills.length / nbCols);
let skillsColumns = Array.from({ length: nbRows }, (_, rowIdx) =>
Array.from({ length: nbCols }, (_, colIdx) => tmpSkills[rowIdx + colIdx * nbRows]).filter(Boolean)
);
// Merge skillsColumns in a single flat array
skillsColumns = skillsColumns.flat().filter(Boolean);
//DEBUG : console.log("Skills columns:", skillsColumns);
context.skills = skillsColumns
}
break
case "equipment":
context.tab = context.tabs.equipment

View File

@@ -77,6 +77,96 @@ export const RESOURCE_RATING = {
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern"}
},
future: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorModern"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageModern"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageModern"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffModern"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 20000, assets: "CTHULHUETERNAL.Resource.RichModern"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichModern"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichModern"}
},
coldwar: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
ww1: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
ww2: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
medieval: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
revolution: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
ageofsail: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
classical: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
postapo: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 20000, assets: "CTHULHUETERNAL.Resource.PoorColdWar"},
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 50000, assets: "CTHULHUETERNAL.Resource.AverageColdWar"},
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 100000, assets: "CTHULHUETERNAL.Resource.AboveAverageColdWar"},
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 150000, assets: "CTHULHUETERNAL.Resource.WellOffColdWar"},
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 200000, assets: "CTHULHUETERNAL.Resource.RichColdWar"},
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 500000, assets: "CTHULHUETERNAL.Resource.VeryRichColdWar"},
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 1000000, assets: "CTHULHUETERNAL.Resource.SuperRichColdWar"}
},
victorian: {
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 30, assets: "CTHULHUETERNAL.Resource.PoorVictorian"},

View File

@@ -23,8 +23,10 @@ export default class CthulhuEternalActor extends Actor {
data.items.push(skill.toObject())
}
}
data.items.push({ type:"weapon", img: "systems/fvtt-cthulhu-eternal/assets/icons/icon_fist.svg",
name: game.i18n.localize("CTHULHUETERNAL.Label.Unarmed"), system: { damage: "1d4-1", weaponType: "unarmed" } })
data.items.push({
type: "weapon", img: "systems/fvtt-cthulhu-eternal/assets/icons/icon_fist.svg",
name: game.i18n.localize("CTHULHUETERNAL.Label.Unarmed"), system: { damage: "1d4-1", weaponType: "unarmed", applyDamageBonus: true }
})
}
return super.create(data, options);
@@ -43,6 +45,43 @@ export default class CthulhuEternalActor extends Actor {
return super._onUpdate(changed, options, userId)
}
setLastDefenseRoll(rollData) {
this.setFlag("fvtt-cthulhu-eternal", "last-defense-roll", rollData)
}
getLastDefenseRoll() {
return this.getFlag("fvtt-cthulhu-eternal", "last-defense-roll")
}
applyWounds(woundData) {
// Get available armor
let armors = this.items.filter(i => i.type === "armor" && i.system.equipped)
let totalArmor = 0
for (let armor of armors) {
totalArmor += armor.system.protection
}
let effectiveWounds = Math.max(woundData.rollResult - totalArmor, 0)
if (woundData.isLethal) {
effectiveWounds = this.system.hp.value // Killed!
}
// Apply armor reduction
let hp = Math.max(this.system.hp.value - effectiveWounds, 0)
if (this.system.hp.value !== hp) {
this.update({ "system.hp.value": hp })
}
// Chat message for GM only
if (game.user.isGM) {
let armorText = totalArmor > 0 ? game.i18n.format("CTHULHUETERNAL.Chat.armorAbsorbed", { armor: totalArmor }) : game.i18n.localize("CTHULHUETERNAL.Chat.noArmor")
ChatMessage.create({
user: game.user.id,
speaker: { alias: this.name },
rollMode: "gmroll",
content: game.i18n.format("CTHULHUETERNAL.Chat.woundsApplied", { name: this.name, effectiveWounds, armorText }),
})
}
}
async createEmbeddedDocuments(embeddedName, data, operation) {
let newData = []
if (embeddedName === "Item") {
@@ -71,18 +110,18 @@ export default class CthulhuEternalActor extends Actor {
}
async _preCreate(data, options, user) {
await super._preCreate(data, options, user)
await super._preCreate(data, options, user)
// Configure prototype token settings
const prototypeToken = {}
if (this.type === "protagonist") {
Object.assign(prototypeToken, {
sight: { enabled: true },
actorLink: true,
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
})
this.updateSource({ prototypeToken })
// Configure prototype token settings
const prototypeToken = {}
if (this.type === "protagonist") {
Object.assign(prototypeToken, {
sight: { enabled: true },
actorLink: true,
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
})
this.updateSource({ prototypeToken })
}
}
}
}

View File

@@ -1,5 +1,6 @@
import { SYSTEM } from "../config/system.mjs"
import CthulhuEternalUtils from "../utils.mjs"
export default class CthulhuEternalRoll extends Roll {
/**
@@ -128,51 +129,48 @@ export default class CthulhuEternalRoll extends Roll {
static async processWeaponDamage(actor, options) {
let isLethal = false
let weapon = options.rollItem
let ammoUsed = weapon.system.weaponType.includes("ranged") ? 1 : 0 // Default ammo used for melee weapons is 0
options.isNudge = false
// Selective fire management
if (weapon.system.hasSelectiveFire && weapon.selectiveFireChoice) {
let choice = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES[weapon.selectiveFireChoice]
if (choice.ammoUsed > weapon.system.ammo.value) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo"))
return
}
weapon.system.selectiveFireChoiceLabel = choice.label // Store the choice in the weapon
weapon.system.lethality = choice.lethality // Override lethality
weapon.system.killRadius = choice.killRadius // Override kill radius
ammoUsed = choice.ammoUsed // Override ammo used
}
ammoUsed = Number(ammoUsed)
let combatants = []
if (game?.combat?.combatants) {
for (let c of game.combat.combatants) {
if (c.actor.id !== actor.id) {
combatants.push({ id: c.id, name: c.name })
}
}
}
if (weapon.system.lethality > 0) {
let lethalityRoll = new Roll("1d100")
await lethalityRoll.evaluate()
let lethalScore = (options?.previousResultType === "successCritical") ? weapon.system.lethality * 2 : weapon.system.lethality
isLethal = (lethalityRoll.total <= lethalScore)
if (ammoUsed > 0) {
await actor.updateEmbeddedDocuments("Item", [{
_id: weapon._id,
"system.ammo.value": Math.max(0, weapon.system.ammo.value - ammoUsed)
}])
}
let wounds = Math.floor(lethalityRoll.total / 10) + (lethalityRoll.total % 10)
let msgData = {
actorId: actor.id,
weapon,
wounds,
lethalScore,
isLethal,
ammoUsed,
ammoUsed: weapon?.ammoUsed || 0,
rollResult: lethalityRoll.total,
combatants: combatants
}
let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-lethal-damage.hbs", msgData)
ChatMessage.create({
let msg = await ChatMessage.create({
user: game.user.id,
content: flavor,
speaker: ChatMessage.getSpeaker({ actor: actor }),
}, { rollMode: options.rollMode, create: true })
await msg.setFlag("fvtt-cthulhu-eternal", "woundData", msgData)
return
}
@@ -184,27 +182,24 @@ export default class CthulhuEternalRoll extends Roll {
if (options?.previousResultType === "successCritical") {
formula = `( ${formula} ) * 2`
}
if (ammoUsed > 0) {
await actor.updateEmbeddedDocuments("Item", [{
_id: weapon._id,
"system.ammo.value": Math.max(0, weapon.system.ammo.value - ammoUsed)
}])
}
console.log("Weapon damage formula", formula, weapon, ammoUsed)
let damageRoll = new Roll(formula)
await damageRoll.evaluate()
let msgData = {
weapon,
formula,
ammoUsed,
rollResult: damageRoll.total,
}
let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-regular-damage.hbs", msgData)
ChatMessage.create({
user: game.user.id,
content: flavor,
speaker: ChatMessage.getSpeaker({ actor: actor }),
}, { rollMode: options.rollMode, create: true })
actorId: actor.id,
weapon,
formula,
ammoUsed: weapon?.ammoUsed || 0,
rollResult: damageRoll.total,
combatants: combatants
}
let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-regular-damage.hbs", msgData)
let msg = await ChatMessage.create({
user: game.user.id,
content: flavor,
speaker: ChatMessage.getSpeaker({ actor: actor }),
}, { rollMode: options.rollMode, create: true })
await msg.setFlag("fvtt-cthulhu-eternal", "woundData", msgData)
}
@@ -220,6 +215,27 @@ export default class CthulhuEternalRoll extends Roll {
return modifier
}
static async processAmmoUsed(actor, weapon) {
let ammoUsed = weapon.system.weaponType.includes("ranged") ? 1 : 0 // Default ammo used for melee weapons is 0
// Selective fire management
if (weapon.system.hasSelectiveFire && weapon.selectiveFireChoice) {
let choice = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES[weapon.selectiveFireChoice]
if (choice.ammoUsed > weapon.system.ammo.value) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo"))
return
}
ammoUsed = choice.ammoUsed // Override ammo used
}
ammoUsed = Number(ammoUsed)
if (ammoUsed > 0) {
await actor.updateEmbeddedDocuments("Item", [{
_id: weapon._id,
"system.ammo.value": Math.max(0, weapon.system.ammo.value - ammoUsed)
}])
}
weapon.ammoUsed = ammoUsed
}
/**
* Prompt the user with a dialog to configure and execute a roll.
*
@@ -241,9 +257,10 @@ export default class CthulhuEternalRoll extends Roll {
options.isNudge = true
let actor = game.actors.get(options.actorId)
let target = CthulhuEternalUtils.getTarget()
switch (options.rollType) {
case "skill":
console.log(options.rollItem)
options.initialScore = options.rollItem.system.computeScore()
break
case "luck":
@@ -281,12 +298,16 @@ export default class CthulhuEternalRoll extends Roll {
console.log("WP Not found", era, options.rollItem.system.weaponType)
return
}
if (!target) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.AttackNoTarget"))
}
// Check if the weapon has enouth ammo in case of a firearm
if (options.rollItem.system.isFireArm() && options.rollItem.system.ammo.value <= 0) {
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo"))
return
}
options.weapon = options.rollItem
if (options.rollItem.system.hasDirectSkill) {
let skillName = options.rollItem.name
options.rollItem = { type: "skill", name: skillName, system: { base: 0, bonus: options.weapon.system.directSkillValue } }
@@ -357,6 +378,7 @@ export default class CthulhuEternalRoll extends Roll {
aimingWithSight: false,
modifier,
formula,
targetName: target?.name,
hasTarget: options.hasTarget,
hasModifier,
hasMultiplier,
@@ -409,10 +431,14 @@ export default class CthulhuEternalRoll extends Roll {
if (rollContext === null) return
let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext)
// If we have a target, get its data
rollData.targetId = target?.id
rollData.targetName = target?.name
rollData.rollMode = rollContext.visibility
// Update target score
console.log("Rolldata", rollData, options)
console.log("Rolldata", rollData)
if (options.rollType === "resource") {
rollData.targetScore = options.initialScore * Number(rollContext.multiplier)
} else {
@@ -432,6 +458,10 @@ export default class CthulhuEternalRoll extends Roll {
rollData.modifier = "0"
}
if (options.rollType === "weapon") {
await this.processAmmoUsed(actor, rollData.weapon)
}
if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return
const roll = new this(formula, options.data, rollData)
@@ -492,7 +522,64 @@ export default class CthulhuEternalRoll extends Roll {
this.options.isLowWP = rollData.isLowWP
this.options.isZeroWP = rollData.isZeroWP
this.options.isExhausted = rollData.isExhausted
rollData.isSuccess = this.options.isSuccess
rollData.isFailure = this.options.isFailure
rollData.isCritical = this.options.isCritical
rollData.resultType = resultType
this.options.rollData = foundry.utils.duplicate(rollData)
// Keep track of the last defense roll for the actor
if (game.combat && (rollData?.weapon?.system.type === "melee" || (rollData?.rollItem.type === "skill" && rollData?.rollItem.name?.toLowerCase().includes(game.i18n.localize("CTHULHUETERNAL.Skill.dodgeName").toLowerCase())))) {
let actor = game.actors.get(options.actorId)
rollData.round = game.combat.round
actor.setLastDefenseRoll(foundry.utils.duplicate(rollData))
}
if (game.combat && rollData?.weapon) { // An attack roll
rollData.isAttackRoll = true
}
// Now check if we have a target for the current roll, and if the target has done its defense roll this round
if (rollData.targetId) {
let token = game.scenes.current.tokens.get(rollData.targetId)
let defender = token.actor
let lastDefenseRoll = defender?.getLastDefenseRoll()
// Now compare opposition
this.compareRolls(rollData, lastDefenseRoll)
rollData.defenseRoll = lastDefenseRoll
}
}
compareRolls(attackRoll, defenseRoll) {
if (!defenseRoll || defenseRoll.round !== game?.combat?.round) {
ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.NoDefenseRoll"))
return
}
if (attackRoll.isFailure) {
attackRoll.attackSucess = false
}
if (attackRoll.isSuccess && defenseRoll.isFailure) {
attackRoll.attackSucess = true
}
if (attackRoll.isSuccess && defenseRoll.isSuccess) {
if (attackRoll.isCritical && !defenseRoll.isCritical) {
attackRoll.attackSucess = true
}
else if (!attackRoll.isCritical && defenseRoll.isCritical) {
attackRoll.attackSucess = false
}
else {
// Both are normal success, compare the roll results
if (attackRoll.total >= defenseRoll.total) {
// Attack successful
attackRoll.attackSucess = true
} else {
// Defense successful
attackRoll.attackSucess = false
}
}
}
}
/**

View File

@@ -90,7 +90,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
prepareDerivedData() {
super.prepareDerivedData();
if (!game.user.isGM ) {
if (!game.user.isGM) {
return
}
@@ -140,12 +140,15 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
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: `<p>${game.i18n.format("CTHULHUETERNAL.Label.breakingPointReached", { bp: this.san.breakingPoint, san: this.san.value })}</p>`,
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 ]
})
let w = game.users.find(u => u.character?.name === this.parent?.name)
if (w) {
ChatMessage.create({
content: `<p>${game.i18n.format("CTHULHUETERNAL.Label.breakingPointReached", { bp: this.san.breakingPoint, san: this.san.value })}</p>`,
speaker: ChatMessage.getSpeaker({ actor: this.parent }),
// Get the user id of the actor owner
whisper: [w.id]
})
}
}
// Unconsciousness management
@@ -207,7 +210,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
actorName: this.parent.name,
adaptedToHelplessness: this.biodata.adaptedToHelplessness,
adaptedToViolence: this.biodata.adaptedToViolence,
... rollData
...rollData
}
let updates = {}
let template = ""
@@ -224,7 +227,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
}
template = "systems/fvtt-cthulhu-eternal/templates/chat-san-temp-insanity.hbs"
} else if (rollData.sanLoss === 0) { // Manage if sanLoss is 0
} else if (rollData.sanLoss === 0) { // Manage if sanLoss is 0
rollData.resetMsg = false
if (rollData.sanType === "violence" && !this.biodata.adaptedToViolence) {
updates[`system.san.violence`] = [false, false, false]
@@ -236,7 +239,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
}
template = "systems/fvtt-cthulhu-eternal/templates/chat-san-loss-0.hbs"
} else if (rollData.sanType === "violence" ) {
} else if (rollData.sanType === "violence") {
// Set the first false element of the violence array to true
let violence = this.san.violence.slice()
let index = violence.findIndex(v => !v)
@@ -251,7 +254,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
updates[`system.san.violence`] = [false, false, false]
msgData.adaptedToViolence = true
}
} else if (rollData.sanType === "helplessness" ) {
} else if (rollData.sanType === "helplessness") {
// If sanType is "helplessness" and adapted to helplessness, set the first false element of the helplessness array to true
let helplessness = this.san.helplessness.slice()
let index = helplessness.findIndex(h => !h)
@@ -266,7 +269,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
updates[`system.san.helplessness`] = [false, false, false]
msgData.adaptedToHelplessness = true
}
} else if (rollData.sanType === "unnatural" ) {
} 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"
@@ -354,15 +357,15 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
*/
async roll(rollType, rollItem) {
if (this.hp.dead ) {
if (this.hp.dead) {
// Warn with chat message
ChatMessage.create({
content: `<p>${game.i18n.format("CTHULHUETERNAL.Label.deadWarning", {con: this.characteristics.con.value} )}</p>`,
content: `<p>${game.i18n.format("CTHULHUETERNAL.Label.deadWarning", { con: this.characteristics.con.value })}</p>`,
speaker: ChatMessage.getSpeaker({ actor: this.parent })
})
return null
}
if (this.hp.unconscious ) {
if (this.hp.unconscious) {
// Warn with chat message
ChatMessage.create({
content: `<p>${game.i18n.localize("CTHULHUETERNAL.Label.unconsciousWarning")}</p>`,

View File

@@ -229,7 +229,7 @@ export default class CthulhuEternalUtils {
let healingFormula = rollData.rollItem.system.healingFormula
let healingMsg = "CTHULHUETERNAL.Label.healingRoll"
if (rollData.resultType === "successCritical") {
healingFormula += " * 2"
healingFormula += " * 2"
}
if (rollData.resultType === "failureCritical") {
healingMsg = "CTHULHUETERNAL.Label.healingRollFailure"
@@ -248,9 +248,39 @@ export default class CthulhuEternalUtils {
})
}
static translateRangeUnit(range) {
if (typeof range === 'string') {
return game.i18n.localize(`CTHULHUETERNAL.Label.${range}`)
} else if (typeof range === 'number') {
return range
} else {
console.warn("CTHULHU ETERNAL | translateRange called with an unknown type", range)
return range
}
}
static translateRange(range) {
// If the range is a string, replace STR with FOR
if (typeof range === 'string') {
return range.replace(/STR/g, "FOR").replace(/str/g, "for")
}
return range
}
static async registerBabeleTranslations(babele) {
babele.registerConverters({
'translateRangeUnit': (originalValue) => {
return CthulhuEternalUtils.translateRangeUnit(originalValue)
},
'translateRange': (originalValue) => {
return CthulhuEternalUtils.translateRange(originalValue)
}
})
}
static async damageRoll(rollMessage, formula = null) {
let rollData = rollMessage.rolls[0]?.options?.rollData
let actor = game.actors.get(rollData.actorId)
let actor = game.actors.get(rollData.actorId)
if (!actor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound"))
return
@@ -306,8 +336,8 @@ export default class CthulhuEternalUtils {
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
$(".nudged-score-select").change(event => {
dialogContext.nudgedValue = Number(event.target.value)+1
dialogContext.wpCost = Math.ceil(Math.abs(rollMessage.rolls[0].total - dialogContext.nudgedValue) / 5)
dialogContext.nudgedValue = Number(event.target.value) + 1
dialogContext.wpCost = Math.ceil(Math.abs(rollMessage.rolls[0].total - dialogContext.nudgedValue) / 5)
$("#nudged-wp-cost").val(dialogContext.wpCost)
})
}
@@ -345,4 +375,34 @@ export default class CthulhuEternalUtils {
document.documentElement.style.setProperty('--background-image-base', `linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url("../assets/ui/${era}_background_main.webp")`);
}
static getTarget() {
if (game.user.targets && game.user.targets.size === 1) {
for (let target of game.user.targets) {
return target
}
}
return undefined;
}
static applyWounds(message, event) {
let woundData = message.getFlag("fvtt-cthulhu-eternal", "woundData")
if (!woundData) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noRollDataFound"))
return
}
let actor = game.actors.get(woundData.actorId)
if (!actor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noActorFound"))
return
}
// Get the targetted actorId from the HTML select event
let targetCombatantId = event.target.value
let combatant = game.combat.combatants.get(targetCombatantId)
let targetActor = combatant.token?.actor || game.actors.get(combatant.actorId)
if (!targetActor) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noTargetActorFound") + targetCombatantId)
return
}
targetActor.applyWounds(woundData)
}
}

View File

@@ -1 +1 @@
MANIFEST-000217
MANIFEST-000261

View File

@@ -1,7 +1,7 @@
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
2025/07/14-21:36:01.776546 7f3fa57fa6c0 Level-0 table #220: started
2025/07/14-21:36:01.776599 7f3fa57fa6c0 Level-0 table #220: 0 bytes OK
2025/07/14-21:36:01.836135 7f3fa57fa6c0 Delete type=0 #218
2025/07/14-21:36:02.071353 7f3fa57fa6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)
2025/10/08-22:08:44.664871 7f77151f96c0 Recovering log #259
2025/10/08-22:08:44.675676 7f77151f96c0 Delete type=3 #257
2025/10/08-22:08:44.675773 7f77151f96c0 Delete type=0 #259
2025/10/08-23:43:02.763720 7f770f3ff6c0 Level-0 table #264: started
2025/10/08-23:43:02.763751 7f770f3ff6c0 Level-0 table #264: 0 bytes OK
2025/10/08-23:43:02.770330 7f770f3ff6c0 Delete type=0 #262
2025/10/08-23:43:02.770574 7f770f3ff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
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)
2025/10/01-17:34:00.770173 7fc4987f86c0 Recovering log #255
2025/10/01-17:34:00.786532 7fc4987f86c0 Delete type=3 #253
2025/10/01-17:34:00.786591 7fc4987f86c0 Delete type=0 #255
2025/10/01-20:52:25.677932 7fc497ff76c0 Level-0 table #260: started
2025/10/01-20:52:25.677997 7fc497ff76c0 Level-0 table #260: 0 bytes OK
2025/10/01-20:52:26.027584 7fc497ff76c0 Delete type=0 #258
2025/10/01-20:52:26.508239 7fc497ff76c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

@@ -1 +1 @@
MANIFEST-000386
MANIFEST-000430

View File

@@ -1,7 +1,7 @@
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
2025/07/14-21:36:01.925671 7f3fa57fa6c0 Level-0 table #389: started
2025/07/14-21:36:01.925708 7f3fa57fa6c0 Level-0 table #389: 0 bytes OK
2025/07/14-21:36:01.980506 7f3fa57fa6c0 Delete type=0 #387
2025/07/14-21:36:02.071389 7f3fa57fa6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)
2025/10/08-22:08:44.633139 7f77159fa6c0 Recovering log #428
2025/10/08-22:08:44.643368 7f77159fa6c0 Delete type=3 #426
2025/10/08-22:08:44.643480 7f77159fa6c0 Delete type=0 #428
2025/10/08-23:43:02.756716 7f770f3ff6c0 Level-0 table #433: started
2025/10/08-23:43:02.756789 7f770f3ff6c0 Level-0 table #433: 0 bytes OK
2025/10/08-23:43:02.763557 7f770f3ff6c0 Delete type=0 #431
2025/10/08-23:43:02.770557 7f770f3ff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
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)
2025/10/01-17:34:00.727436 7fc499ffb6c0 Recovering log #424
2025/10/01-17:34:00.744993 7fc499ffb6c0 Delete type=3 #422
2025/10/01-17:34:00.745065 7fc499ffb6c0 Delete type=0 #424
2025/10/01-20:52:26.571766 7fc497ff76c0 Level-0 table #429: started
2025/10/01-20:52:26.571816 7fc497ff76c0 Level-0 table #429: 0 bytes OK
2025/10/01-20:52:26.607301 7fc497ff76c0 Delete type=0 #427
2025/10/01-20:52:26.607477 7fc497ff76c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

View File

View File

@@ -1 +1 @@
MANIFEST-000031
MANIFEST-000076

View File

@@ -1,15 +1,7 @@
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
2025/07/14-21:36:01.980637 7f3fa57fa6c0 Level-0 table #34: started
2025/07/14-21:36:02.012185 7f3fa57fa6c0 Level-0 table #34: 24252 bytes OK
2025/07/14-21:36:02.071125 7f3fa57fa6c0 Delete type=0 #32
2025/07/14-21:36:02.071403 7f3fa57fa6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)
2025/07/14-21:36:02.071441 7f3fa57fa6c0 Manual compaction at level-1 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at '!items!qb4c1wfPZFcGiEuV' @ 472 : 1
2025/07/14-21:36:02.071451 7f3fa57fa6c0 Compacting 1@1 + 1@2 files
2025/07/14-21:36:02.101879 7f3fa57fa6c0 Generated table #35@1: 362 keys, 93592 bytes
2025/07/14-21:36:02.101908 7f3fa57fa6c0 Compacted 1@1 + 1@2 files => 93592 bytes
2025/07/14-21:36:02.154064 7f3fa57fa6c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2025/07/14-21:36:02.154296 7f3fa57fa6c0 Delete type=2 #14
2025/07/14-21:36:02.154743 7f3fa57fa6c0 Delete type=2 #34
2025/07/14-21:36:02.372014 7f3fa57fa6c0 Manual compaction at level-1 from '!items!qb4c1wfPZFcGiEuV' @ 472 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)
2025/10/08-22:08:44.648914 7f770ffff6c0 Recovering log #74
2025/10/08-22:08:44.660220 7f770ffff6c0 Delete type=3 #72
2025/10/08-22:08:44.660388 7f770ffff6c0 Delete type=0 #74
2025/10/08-23:43:02.832863 7f770f3ff6c0 Level-0 table #79: started
2025/10/08-23:43:02.832918 7f770f3ff6c0 Level-0 table #79: 0 bytes OK
2025/10/08-23:43:02.839997 7f770f3ff6c0 Delete type=0 #77
2025/10/08-23:43:02.852551 7f770f3ff6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,7 @@
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)
2025/10/01-17:34:00.750882 7fc4997fa6c0 Recovering log #70
2025/10/01-17:34:00.765634 7fc4997fa6c0 Delete type=3 #68
2025/10/01-17:34:00.765703 7fc4997fa6c0 Delete type=0 #70
2025/10/01-20:52:26.472838 7fc497ff76c0 Level-0 table #75: started
2025/10/01-20:52:26.472892 7fc497ff76c0 Level-0 table #75: 0 bytes OK
2025/10/01-20:52:26.508046 7fc497ff76c0 Delete type=0 #73
2025/10/01-20:52:26.508280 7fc497ff76c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

View File

@@ -11,8 +11,8 @@
@import "weapon.less";
@import "armor.less";
@import "motivation.less";
@import "mentaldisorder.less";
@import "bond.less";
@import "mentaldisorder.less";
@import "bond.less";
@import "chat.less";
@import "gear.less";
@import "arcane.less";
@@ -21,4 +21,4 @@
@import "tome.less";
}
@import "roll.less";
@import "roll.less";

View File

@@ -53,6 +53,10 @@
color: var(--color-dark-1);
}
.li-apply-wounds {
display: none;
}
&.dice-roll {
flex-direction: column;
@@ -70,7 +74,7 @@
border: 0px;
}
.intro-chat {
color:var(--color-dark-1);
color: var(--color-dark-1);
border-radius: 20px;
display: flex;
flex-direction: row;
@@ -91,20 +95,20 @@
li {
margin: 0 10px;
font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1.0);
font-size: calc(var(--font-size-standard) * 1);
}
.nudge-roll {
font-size: calc(var(--font-size-standard) * 1.0);
font-size: calc(var(--font-size-standard) * 1);
margin-left: 2rem;
display: none;
}
.healing-roll {
font-size: calc(var(--font-size-standard) * 1.0);
font-size: calc(var(--font-size-standard) * 1);
margin-left: 2rem;
display: none;
}
.roll-damage {
font-size: calc(var(--font-size-standard) * 1.0);
font-size: calc(var(--font-size-standard) * 1);
margin-left: 2rem;
display: none;
}

View File

@@ -6,7 +6,7 @@
"download": "#{DOWNLOAD}#",
"url": "https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal",
"license": "LICENSE",
"version": "13.0.1",
"version": "13.0.2",
"authors": [
{
"name": "Uberwald",

View File

@@ -2,7 +2,7 @@
<div class="chat-lethal-damage">
<ul>
<li><strong>{{weapon.name}} : {{localize "CTHULHUETERNAL.Label.lethalityRoll"}}</strong></li>
<li>{{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{lethalScore}})</li>
<li>{{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{lethalScore}})</li>
{{#if weapon.system.selectiveFireChoice}}
@@ -21,12 +21,20 @@
<li>{{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}</li>
{{/if}}
<li class="li-apply-wounds">
<button type="button" class="apply-wounds">{{localize "CTHULHUETERNAL.Label.applyWounds"}}</button>
<select name="combatant" class="roll-skill-modifier">
{{selectOptions combatants valueAttr="id" labelAttr="name"}}
</select>
</li>
{{#if isLethal}}
<li class="result-lethal">{{localize "CTHULHUETERNAL.Label.lethalityLethal"}}</li>
<li class="result-lethal">{{localize "CTHULHUETERNAL.Label.lethalityWounded"}}</li>
{{else}}
<li class="result-non-lethal">{{localize "CTHULHUETERNAL.Label.lethalityNotLethal"}}</li>
<li class="result-non-lethal">{{localize "CTHULHUETERNAL.Label.lethalityNotWounded"}}: <strong>{{wounds}}</strong></li>
<li class="result-non-lethal">{{localize "CTHULHUETERNAL.Label.lethalityNotWounded"}}: <strong>{{wounds}}</strong>
</li>
{{/if}}
</ul>

View File

@@ -7,125 +7,218 @@
<div class="intro-right">
<ul>
{{#if (eq rollType "char")}}
<li><strong>{{localize "CTHULHUETERNAL.Label.charRoll"}}</strong></li>
<li><strong>{{localize "CTHULHUETERNAL.Label.charRoll"}}</strong></li>
{{/if}}
{{#if (eq rollType "skill")}}
<li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li>
<li><strong>{{localize
"CTHULHUETERNAL.Label.skillRoll"
}}</strong></li>
{{/if}}
{{#if isNudgedRoll}}
<li><strong>{{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} {{localize "CTHULHUETERNAL.Label.WPSpent"}}</strong></li>
<li><strong>{{localize "CTHULHUETERNAL.Label.nudgedRoll"}}
:
{{wpCost}}
{{localize "CTHULHUETERNAL.Label.WPSpent"}}</strong></li>
{{/if}}
{{#if weapon}}
<li><strong>{{localize "CTHULHUETERNAL.Label.Weapon"}} : {{weapon.name}}</strong></li>
<li><strong>{{localize "CTHULHUETERNAL.Label.Weapon"}}
:
{{weapon.name}}</strong></li>
{{/if}}
{{#if (eq rollType "resource")}}
<li><strong>{{rollItem.name}} : {{initialScore}}</strong></li>
<li><strong>{{rollItem.name}} : {{initialScore}}</strong></li>
{{else}}
<li><strong>{{rollItem.name}} : {{initialScore}}%</strong></li>
<li><strong>{{rollItem.name}} : {{initialScore}}%</strong></li>
{{/if}}
{{#if isZeroWP}}
<li class="red-warning">{{localize "CTHULHUETERNAL.Label.ZeroWP"}}</li>
<li class="red-warning">{{localize
"CTHULHUETERNAL.Label.ZeroWP"
}}</li>
{{else}}
{{#if isLowWP}}
<li class="orange-warning">{{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%</li>
{{/if}}
{{#if isLowWP}}
<li class="orange-warning">{{localize "CTHULHUETERNAL.Label.LowWP"}}
: -20%</li>
{{/if}}
{{/if}}
{{#if isExhausted}}
<li class="orange-warning">{{localize "CTHULHUETERNAL.Label.Exhausted"}} : -20%</li>
<li class="orange-warning">{{localize
"CTHULHUETERNAL.Label.Exhausted"
}}
: -20%</li>
{{/if}}
{{#if (eq rollType "resource")}}
<li>{{localize "CTHULHUETERNAL.Label.multiplier"}} : {{multiplier}}</li>
{{#if (eq rollType "resource")}}
<li>{{localize "CTHULHUETERNAL.Label.multiplier"}}
:
{{multiplier}}</li>
{{else}}
<li>{{localize "CTHULHUETERNAL.Label.modifier"}} : {{totalModifier}}%</li>
<li>{{localize "CTHULHUETERNAL.Label.modifier"}}
:
{{totalModifier}}%</li>
{{/if}}
<li>{{localize "CTHULHUETERNAL.Label.targetScore"}} : {{targetScore}}%</li>
<li>{{localize "CTHULHUETERNAL.Label.targetScore"}}
:
{{targetScore}}%</li>
{{#if isSuccess}}
{{#if isCritical}}
<li class="result-critical-success">{{localize "CTHULHUETERNAL.Label.criticalSuccess"}}
<li class="result-critical-success">{{localize
"CTHULHUETERNAL.Label.criticalSuccess"
}}
</li>
{{else}}
<li class="result-success">
{{localize "CTHULHUETERNAL.Label.success"}}
{{#if isNudge}}
<a class="nudge-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollNudge"}}"><i class="fa-solid fa-circle-sort-down"></i></a>
{{/if}}
<li class="result-success">
{{localize "CTHULHUETERNAL.Label.success"}}
{{#if isNudge}}
<a
class="nudge-roll"
data-tooltip="{{localize ' CTHULHUETERNAL.Label.rollNudge'}}"
><i class="fa-solid fa-circle-sort-down"></i></a>
{{/if}}
</li>
</li>
{{/if}}
{{#if (eq rollType "weapon")}}
<li>
{{#if (eq rollType "weapon")}}
<li>
{{#if (eq weapon.system.weaponType "rangedfirearm")}}
{{#if weapon.system.hasDamageDistance}}
{{#each weapon.system.damageDistance as |damageDistance|}}
{{#if (gt damageDistance.distance 0)}}
<a class="damage-roll" data-item-id="{{weapon.id}}" data-action="roll" data-roll-type="damage"
data-roll-value="{{damageDistance.damage}}" >
<i class="fa-solid fa-gun"></i>
<span class="damage-distance">{{damageDistance.distance}}:{{damageDistance.damage}}&nbsp;&nbsp;</span>
</a>
<a
class="damage-roll"
data-item-id="{{weapon.id}}"
data-action="roll"
data-roll-type="damage"
data-roll-value="{{damageDistance.damage}}"
>
<i class="fa-solid fa-gun"></i>
<span
class="damage-distance"
>{{damageDistance.distance}}:{{damageDistance.damage}}&nbsp;&nbsp;</span>
</a>
{{/if}}
{{/each}}
{{else}}
<a class="damage-roll" data-roll-value="{{weapon.system.damage}}" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-gun"></i></a>
<a
class="damage-roll"
data-roll-value="{{weapon.system.damage}}"
data-tooltip="{{localize
'
CTHULHUETERNAL.Label.rollDamage'
}}"
><i class="fa-solid fa-gun"></i></a>
{{/if}}
{{else}}
<a class="damage-roll" data-roll-value="{{weapon.system.damage}}" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-sword"></i></a>
<a
class="damage-roll"
data-roll-value="{{weapon.system.damage}}"
data-tooltip="{{localize
'
CTHULHUETERNAL.Label.rollDamage'
}}"
><i class="fa-solid fa-sword"></i></a>
{{/if}}
</li>
{{/if}}
{{#if (eq rollType "skill")}}
{{#if rollItem.system.isHealing}}
<li>
<a
class="healing-roll"
data-tooltip="{{localize
' CTHULHUETERNAL.Label.rollHealing'
}}"
><i class="fa-solid fa-heart"></i></a>
</li>
{{/if}}
{{#if (eq rollType "skill") }}
{{#if rollItem.system.isHealing}}
<li>
<a class="healing-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollHealing"}}"><i class="fa-solid fa-heart"></i></a>
</li>
{{/if}}
{{/if}}
</li>
{{/if}}
{{/if}}
{{#if isFailure}}
{{#if isCritical}}
<li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}
<li class="result-critical-failure">{{localize
"CTHULHUETERNAL.Label.criticalFailure"
}}
</li>
{{else}}
<li class="result-failure">
{{localize "CTHULHUETERNAL.Label.failure"}}
</li>
<li class="result-failure">
{{localize "CTHULHUETERNAL.Label.failure"}}
</li>
{{/if}}
{{#if isNudge}}
<li>
<a class="nudge-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollNudge"}}"><i class="fa-solid fa-circle-sort-down"></i></a>
</li>
<li>
<a
class="nudge-roll"
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollNudge'}}"
><i class="fa-solid fa-circle-sort-down"></i></a>
</li>
{{/if}}
{{/if}}
{{#if isAttackRoll}}
{{#if defenseRoll}}
<li>{{localize "CTHULHUETERNAL.Label.defenseRoll"}}</li>
{{#if attackSuccess}}
<li class="result-success">{{localize
"CTHULHUETERNAL.Label.attackSuccess"
}}</li>
{{else}}
<li class="result-failure">{{localize
"CTHULHUETERNAL.Label.attackFailure"
}}</li>
{{/if}}
{{else}}
{{#if targetId}}
<li class="orange-warning">{{localize
"CTHULHUETERNAL.Label.noDefenseRoll"
}}</li>
<a
class="opposed-roll"
data-tooltip="{{localize 'CTHULHUETERNAL.Label.opposedRoll'}}"
>
<i class="fa-duotone fa-light fa-arrows-to-line"></i></a>
{{else}}
<li class="orange-warning">{{localize
"CTHULHUETERNAL.Label.noTarget"
}}</li>
<a
class="opposed-roll"
data-tooltip="{{localize 'CTHULHUETERNAL.Label.opposedRoll'}}"
>
<i class="fa-duotone fa-light fa-arrows-to-line"></i></a>
{{/if}}
{{/if}}
{{/if}}
</ul>
</div>
</div>
{{#if isDamage}}
<div>
{{#if (and isGM hasTarget)}}
{{{localize "CTHULHUETERNAL.Roll.displayArmor" targetName=targetName targetArmor=targetArmor
realDamage=realDamage}}}
{{/if}}
</div>
<div>
{{#if (and isGM hasTarget)}}
{{{localize
"CTHULHUETERNAL.Roll.displayArmor"
targetName=targetName
targetArmor=targetArmor
realDamage=realDamage
}}}
{{/if}}
</div>
{{/if}}
{{#unless isPrivate}}
<div class="dice-result">
<h4 class="dice-total">{{total}}</h4>
<div class="dice-formula">{{formula}}</div>
{{{tooltip}}}
</div>
<div class="dice-result">
<h4 class="dice-total">{{total}}</h4>
<div class="dice-formula">{{formula}}</div>
{{{tooltip}}}
</div>
{{/unless}}
</div>

View File

@@ -2,7 +2,7 @@
<div class="chat-lethal-damage">
<ul>
<li><strong>{{weapon.name}} : {{localize "CTHULHUETERNAL.Label.damageRoll"}}</strong></li>
<li>{{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{formula}})</li>
<li>{{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{formula}})</li>
{{#if (gt weapon.system.killRadius 0)}}
<li>{{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}</li>
@@ -12,11 +12,24 @@
{{#if (gt weapon.system.armorPiercing 0)}}
<li>{{localize "CTHULHUETERNAL.Label.armorPiercing"}} : {{weapon.system.armorPiercing}}</li>
{{/if}}
{{#if (gt weapon.system.penetration 0)}}
<li>{{localize "CTHULHUETERNAL.Label.penetration"}} : {{weapon.system.penetration}}</li>
{{/if}}
{{#if ammoUsed}}
<li>{{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}</li>
{{/if}}
<li class="result-non-lethal">{{localize "CTHULHUETERNAL.Label.damageMessage"}}: <strong>{{rollResult}}</strong></li>
<li class="li-apply-wounds">
{{localize "CTHULHUETERNAL.Label.applyWounds"}}
<select name="combatant" class="li-apply-wounds-select">
<option value="none"></option>
{{selectOptions combatants valueAttr="id" labelAttr="name"}}
</select>
</li>
<li class="result-non-lethal">{{localize "CTHULHUETERNAL.Label.damageMessage"}}: <strong>{{rollResult}}</strong>
</li>
</ul>

View File

@@ -9,9 +9,12 @@
{{#if (eq rollType "resource")}}
<legend>{{localize "CTHULHUETERNAL.Label.resourceRating"}}</legend>
<div class="dialog-skill">{{rollItem.name}} : <span class="resource-score">{{initialScore}} ({{mul initialScore 5}}%)</span></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}} <input type="checkbox" data-action="selectHand" {{checked rollItem.enableHand}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}} <input type="checkbox" data-action="selectStowed" {{checked rollItem.enableStowed}}></div>
<div class="dialog-skill">{{rollItem.name}} : <span class="resource-score">{{initialScore}} ({{mul initialScore
5}}%)</span></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}} <input type="checkbox"
data-action="selectHand" {{checked rollItem.enableHand}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}} <input type="checkbox"
data-action="selectStowed" {{checked rollItem.enableStowed}}></div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}}
<input type="checkbox" data-action="selectStorage" {{checked rollItem.enableStorage}}>
@@ -23,76 +26,85 @@
{{#if weapon}}
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Weapon"}} : {{weapon.name}}</div>
{{#if (eq weapon.system.weaponType "melee")}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetMove"}}
<select name="meleeTargetMoveChoice" class="roll-skill-modifier">
{{selectOptions choiceMeleeTargetMove localize=true selected=meleeTargetMoveChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
{{/if}}
{{#if isRangedWeapon}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.rangedRange"}}
<select name="rangedRangeChoice" class="roll-skill-modifier">
{{selectOptions choiceRangedRange localize=true selected=rangedRangeChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetMove"}}
<select name="rangedTargetMoveChoice" class="roll-skill-modifier">
{{selectOptions choiceRangedTargetMove localize=true selected=rangedTargetMoveChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
{{#if targetName}}
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Target"}} : {{targetName}}</div>
{{/if}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.aimingLastRound"}}
<input type="checkbox" name="aimingLastRound">
</div>
{{#if weapon.system.hasSight}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.aimingWithSight"}}
<input type="checkbox" name="aimingWithSight">
</div>
{{/if}}
{{/if}}
{{#if (eq weapon.system.weaponType "melee")}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetMove"}}
<select name="meleeTargetMoveChoice" class="roll-skill-modifier">
{{selectOptions choiceMeleeTargetMove localize=true selected=meleeTargetMoveChoice valueAttr="id"
labelAttr="label"}}
</select>
</div>
{{/if}}
{{#if isRangedWeapon}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.rangedRange"}}
<select name="rangedRangeChoice" class="roll-skill-modifier">
{{selectOptions choiceRangedRange localize=true selected=rangedRangeChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetMove"}}
<select name="rangedTargetMoveChoice" class="roll-skill-modifier">
{{selectOptions choiceRangedTargetMove localize=true selected=rangedTargetMoveChoice valueAttr="id"
labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.visibility"}}
<select name="visibilityChoice" class="roll-skill-modifier">
{{selectOptions choiceVisibility localize=true selected=visibilityChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.attackerState"}}
<select name="attackerStateChoice" class="roll-skill-modifier">
{{selectOptions choiceAttackerState localize=true selected=attackerStateChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetSize"}}
<select name="targetSizeChoice" class="roll-skill-modifier">
{{selectOptions choiceTargetSize localize=true selected=targetSizeChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.aimingLastRound"}}
<input type="checkbox" name="aimingLastRound">
</div>
{{#if weapon.system.hasSight}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.aimingWithSight"}}
<input type="checkbox" name="aimingWithSight">
</div>
{{/if}}
{{#if weapon.system.hasSelectiveFire}}
<div class="dialog-skill">Selective Fire :
<select name="selectiveFireChoice" class="roll-skill-modifier">
{{selectOptions choiceSelectiveFire localize=true selected=selectiveFireChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
{{/if}}
{{/if}}
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.visibility"}}
<select name="visibilityChoice" class="roll-skill-modifier">
{{selectOptions choiceVisibility localize=true selected=visibilityChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.attackerState"}}
<select name="attackerStateChoice" class="roll-skill-modifier">
{{selectOptions choiceAttackerState localize=true selected=attackerStateChoice valueAttr="id"
labelAttr="label"}}
</select>
</div>
<div class="dialog-skill">
{{localize "CTHULHUETERNAL.Label.targetSize"}}
<select name="targetSizeChoice" class="roll-skill-modifier">
{{selectOptions choiceTargetSize localize=true selected=targetSizeChoice valueAttr="id" labelAttr="label"}}
</select>
</div>
{{#if weapon.system.hasSelectiveFire}}
<div class="dialog-skill">Selective Fire :
<select name="selectiveFireChoice" class="roll-skill-modifier">
{{selectOptions choiceSelectiveFire localize=true selected=selectiveFireChoice valueAttr="id"
labelAttr="label"}}
</select>
</div>
{{/if}}
{{/if}}
{{#if isZeroWP}}
<div class="dialog-skill red-warning">{{localize "CTHULHUETERNAL.Label.ZeroWP"}}</div>
{{else}}
{{#if isLowWP}}
<div class="dialog-skill orange-warning">{{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%</div>
{{/if}}
{{#if isLowWP}}
<div class="dialog-skill orange-warning">{{localize "CTHULHUETERNAL.Label.LowWP"}} : -20%</div>
{{/if}}
{{/if}}
{{#if isExhausted}}