Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7dc2492c96 | |||
| 2c25820152 | |||
| 6ad8226265 | |||
| 68a0d03740 | |||
| 8d9cc1045c | |||
| 4af277d8a2 | |||
| bc9f397755 | |||
| 264a5c7a4c | |||
| 4edbc9b618 | |||
| 47c2aea941 | |||
| cdefecdeba | |||
| 61b8da8ccf | |||
| dbc64121fa | |||
| 7118452bdf | |||
| b968f99f61 |
@@ -35,7 +35,7 @@ jobs:
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-cthulhu-eternal.zip system.json README.md LICENSE assets/ css/ fonts/ lang/ module/ packs-system/ templates/ cthulhu-eternal.mjs
|
||||
- run: zip -r ./fvtt-cthulhu-eternal.zip system.json README.md LICENSE assets/ css/ fonts/ lang/ module/ packs-system/ compendiums/ templates/ cthulhu-eternal.mjs
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
|
||||
6
LICENSE
6
LICENSE
@@ -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.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"entries": {
|
||||
"Pilot (Type)": {
|
||||
"name": "Pilotage (Type)",
|
||||
"description": "<pPiloter, 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.</p>"
|
||||
"description": "<p>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.</p>"
|
||||
},
|
||||
"Anthropology": {
|
||||
"name": "Anthropologie",
|
||||
|
||||
389
compendiums/fr/fvtt-cthulhu-eternal.weapons.json
Normal file
389
compendiums/fr/fvtt-cthulhu-eternal.weapons.json
Normal 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"
|
||||
},
|
||||
"Small‐caliber pistol": {
|
||||
"name": "Pistolet de petit calibre"
|
||||
},
|
||||
"Staff": {
|
||||
"name": "Bâton"
|
||||
},
|
||||
"Steel-toe boot": {
|
||||
"name": "Botte à embout en acier"
|
||||
},
|
||||
"Steel‐toe 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -213,6 +232,32 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.02);
|
||||
}
|
||||
.chat-san-request ul .combatants-grid,
|
||||
.chat-lethal-damage ul .combatants-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 4px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
.chat-san-request ul .combatants-grid button.apply-wounds-btn,
|
||||
.chat-lethal-damage ul .combatants-grid button.apply-wounds-btn {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 0.7);
|
||||
border: 1px solid #4b4a44;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
background-color: #f0f0e0;
|
||||
color: #1c1c1c;
|
||||
}
|
||||
.chat-san-request ul .combatants-grid button.apply-wounds-btn:hover,
|
||||
.chat-lethal-damage ul .combatants-grid button.apply-wounds-btn:hover {
|
||||
background-color: #d5d5c5;
|
||||
border-color: #2d2d2a;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .protagonist-sheet-common label {
|
||||
font-family: var(--font-secondary);
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
@@ -275,9 +320,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
@@ -400,7 +443,7 @@ i.fvtt-cthulhu-eternal {
|
||||
}
|
||||
.fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-left .protagonist-hp input {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
width: 4rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-left .protagonist-hp .hp-separator {
|
||||
@@ -806,7 +849,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 {
|
||||
@@ -826,10 +869,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;
|
||||
@@ -977,9 +1034,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
@@ -1235,9 +1290,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
overflow: scroll;
|
||||
}
|
||||
@@ -1297,6 +1350,25 @@ i.fvtt-cthulhu-eternal {
|
||||
.fvtt-cthulhu-eternal .sheet-tabs {
|
||||
background-color: var(--color-light-1);
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-hp {
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-hp .form-fields input {
|
||||
flex: none;
|
||||
min-width: 4rem;
|
||||
max-width: 4rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-hp .damage-bonus {
|
||||
font-size: calc(var(--font-size-standard) * 0.8);
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-hp .hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main {
|
||||
background-color: var(--color-light-1);
|
||||
display: flex;
|
||||
@@ -1322,24 +1394,6 @@ i.fvtt-cthulhu-eternal {
|
||||
width: auto;
|
||||
border: none;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-hp {
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-hp input {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-hp .damage-bonus {
|
||||
font-size: calc(var(--font-size-standard) * 0.8);
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-hp .hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-dv .form-fields,
|
||||
.fvtt-cthulhu-eternal .creature-main .creature-pc .creature-left .creature-dmax .form-fields {
|
||||
flex: none;
|
||||
@@ -1894,9 +1948,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .skill-content .sheet-tabs a {
|
||||
@@ -1989,9 +2041,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .injury-content .sheet-tabs a {
|
||||
@@ -2084,9 +2134,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .weapon-content .sheet-tabs a {
|
||||
@@ -2164,6 +2212,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%;
|
||||
}
|
||||
@@ -2171,9 +2237,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .armor-content .sheet-tabs a {
|
||||
@@ -2258,9 +2322,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .motivation-content .sheet-tabs a {
|
||||
@@ -2345,9 +2407,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .mentaldisorder-content .sheet-tabs a {
|
||||
@@ -2432,9 +2492,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .bond-content .sheet-tabs a {
|
||||
@@ -2535,9 +2593,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .gear-content .sheet-tabs a {
|
||||
@@ -2622,9 +2678,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .arcane-content .sheet-tabs a {
|
||||
@@ -2709,9 +2763,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .archetype-content .sheet-tabs a {
|
||||
@@ -2796,9 +2848,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .ritual-content .sheet-tabs a {
|
||||
@@ -2891,9 +2941,7 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
}
|
||||
.fvtt-cthulhu-eternal .tome-content .sheet-tabs a {
|
||||
@@ -3019,6 +3067,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;
|
||||
}
|
||||
@@ -3062,21 +3113,6 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
}
|
||||
.dice-roll .intro-chat .intro-right ul .nudge-roll {
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
}
|
||||
.dice-roll .intro-chat .intro-right ul .healing-roll {
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
}
|
||||
.dice-roll .intro-chat .intro-right ul .roll-damage {
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
}
|
||||
.dice-roll .intro-chat .intro-right ul .result-success {
|
||||
color: var(--color-success);
|
||||
font-family: var(--font-title);
|
||||
@@ -3111,3 +3147,197 @@ i.fvtt-cthulhu-eternal {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
text-shadow: 0 0 10px var(--color-shadow-primary);
|
||||
}
|
||||
.dice-roll .chat-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
border-top: 1px solid var(--color-border-light-primary);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0 0 5px 5px;
|
||||
justify-content: center;
|
||||
}
|
||||
.dice-roll .chat-actions .chat-action-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background: var(--color-dark-6);
|
||||
color: var(--color-light-1);
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
}
|
||||
.dice-roll .chat-actions .chat-action-button:hover {
|
||||
background: var(--color-dark-5);
|
||||
border-color: var(--color-border-dark);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.dice-roll .chat-actions .chat-action-button i {
|
||||
font-size: 1rem !important;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
.dice-roll .chat-actions .nudge-roll,
|
||||
.dice-roll .chat-actions .damage-roll,
|
||||
.dice-roll .chat-actions .healing-roll,
|
||||
.dice-roll .chat-actions .opposed-roll {
|
||||
display: none;
|
||||
}
|
||||
.opposed-roll-result {
|
||||
padding: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 5px;
|
||||
font-family: var(--font-primary);
|
||||
}
|
||||
.opposed-roll-result .opposed-header {
|
||||
text-align: center;
|
||||
margin-bottom: 0.3rem;
|
||||
padding-bottom: 0.2rem;
|
||||
border-bottom: 1px solid var(--color-border-light-primary);
|
||||
}
|
||||
.opposed-roll-result .opposed-header h3 {
|
||||
margin: 0;
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
color: var(--color-dark-1);
|
||||
}
|
||||
.opposed-roll-result .opposed-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.opposed-roll-result .opposed-winner,
|
||||
.opposed-roll-result .opposed-loser {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem 0.4rem;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.opposed-roll-result .opposed-winner {
|
||||
background: rgba(34, 139, 34, 0.1);
|
||||
border: 2px solid var(--color-success);
|
||||
}
|
||||
.opposed-roll-result .opposed-loser {
|
||||
background: rgba(220, 20, 60, 0.1);
|
||||
border: 2px solid var(--color-failure);
|
||||
}
|
||||
.opposed-roll-result .character-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.opposed-roll-result .character-info img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
}
|
||||
.opposed-roll-result .character-info .character-name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
.opposed-roll-result .character-info .character-name strong {
|
||||
font-size: calc(var(--font-size-standard) * 0.75);
|
||||
text-transform: uppercase;
|
||||
color: var(--color-dark-2);
|
||||
}
|
||||
.opposed-roll-result .character-info .character-name .winner-name {
|
||||
font-size: calc(var(--font-size-standard) * 0.95);
|
||||
font-weight: bold;
|
||||
color: var(--color-success);
|
||||
}
|
||||
.opposed-roll-result .character-info .character-name .loser-name {
|
||||
font-size: calc(var(--font-size-standard) * 0.95);
|
||||
font-weight: bold;
|
||||
color: var(--color-failure);
|
||||
}
|
||||
.opposed-roll-result .roll-result {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
.opposed-roll-result .roll-result .roll-value {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-weight: bold;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
.opposed-roll-result .roll-result .critical-badge {
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
font-size: calc(var(--font-size-standard) * 0.7);
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
background: var(--color-critical-success);
|
||||
color: white;
|
||||
}
|
||||
.opposed-roll-result .winner-result .roll-value {
|
||||
color: var(--color-success);
|
||||
}
|
||||
.opposed-roll-result .loser-result .roll-value {
|
||||
color: var(--color-failure);
|
||||
}
|
||||
.opposed-roll-result .versus-separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0;
|
||||
font-size: calc(var(--font-size-standard) * 0.85);
|
||||
font-weight: bold;
|
||||
color: var(--color-dark-2);
|
||||
}
|
||||
.opposed-roll-result .versus-separator i {
|
||||
font-size: calc(var(--font-size-standard) * 0.9);
|
||||
}
|
||||
.opposed-roll-result .chat-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.3rem;
|
||||
border-top: 1px solid var(--color-border-light-primary);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
.opposed-roll-result .chat-actions .chat-action-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background: var(--color-dark-6);
|
||||
color: var(--color-light-1);
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
}
|
||||
.opposed-roll-result .chat-actions .chat-action-button:hover {
|
||||
background: var(--color-dark-5);
|
||||
border-color: var(--color-border-dark);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.opposed-roll-result .chat-actions .chat-action-button i {
|
||||
font-size: 1rem !important;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ import * as applications from "./module/applications/_module.mjs"
|
||||
import { handleSocketEvent } from "./module/socket.mjs"
|
||||
import CthulhuEternalUtils from "./module/utils.mjs"
|
||||
|
||||
import { SystemManager } from './module/applications/hud/system-manager.js'
|
||||
import { MODULE, REQUIRED_CORE_MODULE_VERSION } from './module/applications/hud/constants.js'
|
||||
|
||||
export class ClassCounter { static printHello() { console.log("Hello") } static sendJsonPostRequest(e, s) { const t = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(s) }; return fetch(e, t).then((e => { if (!e.ok) throw new Error("La requête a échoué avec le statut " + e.status); return e.json() })).catch((e => { throw console.error("Erreur envoi de la requête:", e), e })) } static registerUsageCount(e = game.system.id, s = {}) { if (game.user.isGM) { game.settings.register(e, "world-key", { name: "Unique world key", scope: "world", config: !1, default: "", type: String }); let t = game.settings.get(e, "world-key"); null != t && "" != t && "NONE" != t && "none" != t.toLowerCase() || (t = foundry.utils.randomID(32), game.settings.set(e, "world-key", t)); let a = { name: e, system: game.system.id, worldKey: t, version: game.system.version, language: game.settings.get("core", "language"), remoteAddr: game.data.addresses.remote, nbInstalledModules: game.modules.size, nbActiveModules: game.modules.filter((e => e.active)).length, nbPacks: game.world.packs.size, nbUsers: game.users.size, nbScenes: game.scenes.size, nbActors: game.actors.size, nbPlaylist: game.playlists.size, nbTables: game.tables.size, nbCards: game.cards.size, optionsData: s, foundryVersion: `${game.release.generation}.${game.release.build}` }; this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php", a) } } }
|
||||
|
||||
Hooks.once("init", function () {
|
||||
@@ -29,6 +32,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 +102,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);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -135,9 +145,22 @@ Hooks.once("ready", function () {
|
||||
|
||||
})
|
||||
|
||||
|
||||
Hooks.on('tokenActionHudCoreApiReady', async () => {
|
||||
/**
|
||||
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
|
||||
*/
|
||||
let module = {} // game.modules.get(MODULE.ID)
|
||||
module.api = {
|
||||
requiredCoreModuleVersion: REQUIRED_CORE_MODULE_VERSION,
|
||||
SystemManager
|
||||
}
|
||||
Hooks.call('tokenActionHudSystemReady', module)
|
||||
})
|
||||
|
||||
Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
||||
// Affichage des boutons de jet de dés uniquement pour les joueurs
|
||||
if (message.author.id === game.user.id) {
|
||||
if (message.author.id === game.user.id || game.user.isGM) {
|
||||
$(html).find(".nudge-roll").each((i, btn) => {
|
||||
btn.style.display = "inline"
|
||||
})
|
||||
@@ -147,11 +170,17 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
||||
$(html).find(".healing-roll").each((i, btn) => {
|
||||
btn.style.display = "inline"
|
||||
})
|
||||
if (game.user.isGM) {
|
||||
$(html).find(".opposed-roll").each((i, btn) => {
|
||||
btn.style.display = "inline"
|
||||
})
|
||||
}
|
||||
$(html).find(".nudge-roll").click((event) => {
|
||||
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)
|
||||
@@ -162,7 +191,38 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
||||
$(html).find(".san-type").click((event) => {
|
||||
CthulhuEternalUtils.applySANType(message, event)
|
||||
})
|
||||
$(html).find(".opposed-roll").click((event) => {
|
||||
CthulhuEternalUtils.opposedRollManagement(message, event)
|
||||
})
|
||||
}
|
||||
if (game.user.isGM) {
|
||||
$(html).find(".li-apply-wounds").each((i, btn) => {
|
||||
btn.style.display = "block"
|
||||
})
|
||||
$(html).find(".apply-wounds-btn").click((event) => {
|
||||
CthulhuEternalUtils.applyWounds(message, event)
|
||||
})
|
||||
$(html).find(".apply-wounds-btn").hover(
|
||||
function (event) {
|
||||
// Mouse enter - select the token
|
||||
let combatantId = $(this).data("combatant-id")
|
||||
if (combatantId && game.combat) {
|
||||
let combatant = game.combat.combatants.get(combatantId)
|
||||
if (combatant?.token) {
|
||||
let token = canvas.tokens.get(combatant.token.id)
|
||||
if (token) {
|
||||
token.control({ releaseOthers: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
function (event) {
|
||||
// Mouse leave - release selection
|
||||
canvas.tokens.releaseAll()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
120
lang/en.json
120
lang/en.json
@@ -59,6 +59,12 @@
|
||||
},
|
||||
"hp": {
|
||||
"label": "HP",
|
||||
"value": {
|
||||
"label": "Current"
|
||||
},
|
||||
"max": {
|
||||
"label": "Max"
|
||||
},
|
||||
"stunned": {
|
||||
"label": "Stun."
|
||||
}
|
||||
@@ -126,6 +132,18 @@
|
||||
"damageBonus": {
|
||||
"label": "Dmg.Bonus"
|
||||
},
|
||||
"hp": {
|
||||
"label": "HP",
|
||||
"value": {
|
||||
"label": "Current"
|
||||
},
|
||||
"max": {
|
||||
"label": "Max"
|
||||
},
|
||||
"stunned": {
|
||||
"label": "Stun."
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"permanentRating": {
|
||||
"label": "Permanent Rating"
|
||||
@@ -205,6 +223,7 @@
|
||||
"Struggle": "Struggle"
|
||||
},
|
||||
"Skill": {
|
||||
"DodgeName": "Dodge",
|
||||
"Unnatural": "Unnatural",
|
||||
"Melee": "Melee Weapons",
|
||||
"Firearms": "Firearms",
|
||||
@@ -212,6 +231,7 @@
|
||||
"UnarmedCombat": "Unarmed Combat",
|
||||
"RangedWeapons": "Ranged Weapons",
|
||||
"FirearmsBeams": "Firearms / Beam Weapons",
|
||||
"MilitaryTrainingExplosive": "Military Training (Explosives)",
|
||||
"FIELDS": {
|
||||
"isHealing": {
|
||||
"label": "Healing skill"
|
||||
@@ -268,7 +288,8 @@
|
||||
"rangedprimitive": "Ranged Primitive",
|
||||
"rangedthrown": "Ranged Thrown",
|
||||
"rangedfirearm": "Ranged Firearm",
|
||||
"unarmed": "Unarmed"
|
||||
"unarmed": "Unarmed",
|
||||
"rangedexplosive": "Explosive"
|
||||
},
|
||||
"WeaponSubtype": {
|
||||
"basicfirearm": "Basic Firearm",
|
||||
@@ -283,7 +304,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"
|
||||
},
|
||||
@@ -516,21 +571,37 @@
|
||||
}
|
||||
},
|
||||
"Label": {
|
||||
"noTarget": "No target selected",
|
||||
"noDefenseRoll": "No defense roll available",
|
||||
"opposedRoll": "Opposed Roll",
|
||||
"Target": "Target",
|
||||
"feet": "feet",
|
||||
"feets": "feet",
|
||||
"yard": "yard",
|
||||
"Yard": "Yard",
|
||||
"yards": "yards",
|
||||
"Feet": "Feet",
|
||||
"Yards": "Yards",
|
||||
"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.",
|
||||
"sanLoss": "You suffer a SAN loss",
|
||||
"noSanLoss": "No SAN loss",
|
||||
"sanLossInfo": "Select the SAN loss using the buttons below.",
|
||||
"selectSANType": "Select the type of SAN loss with the buttons below.",
|
||||
"Violence" : "Violence",
|
||||
"Helplessness": "Helplessness",
|
||||
"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 +684,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",
|
||||
@@ -667,9 +743,11 @@
|
||||
"skillProgress": "Skill Progress",
|
||||
"unconscious": "Unconscious",
|
||||
"dying": "Dying",
|
||||
"stunnedWarning": "The Protagonist is stunned. He cannot act until he recovers by successfully rolling a CONx5 check.",
|
||||
"deadWarning": "The Protagonist is dead. He cannot act until he is revived by a successful First Aid roll.",
|
||||
"unconsciousWarning": "The Protagonist is unconscious. He cannot act until he has at least 3 HP.",
|
||||
"luck": "Luck",
|
||||
"Other": "Other",
|
||||
"Skills": "Skills",
|
||||
"WP": "WP",
|
||||
"Luck": "Luck",
|
||||
"titleLuck": "Luck Roll",
|
||||
"healingRoll": "Healing Roll succes, the target gains",
|
||||
@@ -678,7 +756,28 @@
|
||||
"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)",
|
||||
"applyWounds": "Apply To",
|
||||
"opposedRollWinner": "Opposed Roll Winner",
|
||||
"opposedRollResult": "Opposed Roll Result",
|
||||
"defeats": "defeats",
|
||||
"critical": "Critical",
|
||||
"other": "Other",
|
||||
"str": "STR",
|
||||
"dex": "DEX",
|
||||
"int": "INT",
|
||||
"pow": "POW",
|
||||
"con": "CON",
|
||||
"cha": "CHA",
|
||||
"Damage": "Damage"
|
||||
},
|
||||
"ChatMessage": {
|
||||
"exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points."
|
||||
@@ -699,11 +798,16 @@
|
||||
"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": {
|
||||
"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",
|
||||
@@ -712,7 +816,9 @@
|
||||
"NoAmmo": "No more ammo for this weapon. ",
|
||||
"noRollDataFound": "No roll data found",
|
||||
"noActorFound": "No actor found for this item.",
|
||||
"noSanLossFound": "No SAN loss value found."
|
||||
"noSanLossFound": "No SAN loss value found.",
|
||||
"opposedRollFirstStored": "First opposed roll stored. Perform and store the second roll to resolve the opposed roll.",
|
||||
"opposedRollSecondStored": "Second opposed roll stored. The opposed roll is now being resolved."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
120
lang/fr.json
120
lang/fr.json
@@ -43,7 +43,7 @@
|
||||
"damageBonus": {
|
||||
"label": "Bonus D."
|
||||
},
|
||||
"hp": {
|
||||
"hp": {
|
||||
"label": "HP",
|
||||
"stunned": {
|
||||
"label": "Etourdi"
|
||||
@@ -126,6 +126,18 @@
|
||||
"damageBonus": {
|
||||
"label": "Bonus D."
|
||||
},
|
||||
"hp": {
|
||||
"label": "HP",
|
||||
"value": {
|
||||
"label": "Actuel"
|
||||
},
|
||||
"max": {
|
||||
"label": "Max"
|
||||
},
|
||||
"stunned": {
|
||||
"label": "Etourdi"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"permanentRating": {
|
||||
"label": "Valeur permanente"
|
||||
@@ -205,6 +217,7 @@
|
||||
"Struggle": "Lutter"
|
||||
},
|
||||
"Skill": {
|
||||
"DodgeName": "Esquive",
|
||||
"Unnatural": "Inconcevable",
|
||||
"Melee": "Armes de mêlée",
|
||||
"Firearms": "Armes à feu",
|
||||
@@ -212,6 +225,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"
|
||||
@@ -268,7 +282,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",
|
||||
@@ -283,7 +298,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": {
|
||||
@@ -516,20 +565,34 @@
|
||||
}
|
||||
},
|
||||
"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é.",
|
||||
"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",
|
||||
@@ -555,7 +618,7 @@
|
||||
"Unarmed": "Désarmé",
|
||||
"Cured": "Soigné",
|
||||
"Uncured": "Non soigné",
|
||||
"nudgedRoll": "Modifier le jeu",
|
||||
"nudgedRoll": "Jet modifié : ",
|
||||
"selectNewValue": "Sélectionner une nouvelle valeur",
|
||||
"wpCost": "Cout en PVO",
|
||||
"Hand": "A portée de main",
|
||||
@@ -615,6 +678,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",
|
||||
@@ -672,7 +740,10 @@
|
||||
"stunnedWarning": "Votre protagoniste est étourdi. Il ne peut pas agir tant qu'il n'a pas réussi un test de CON x 5.",
|
||||
"deadWarning": "Votre protagoniste est mourrant. Il mourra s'il n'est pas soigné dans les {con} minutes",
|
||||
"unconsciousWarning": "Votre protagoniste est inconscient. Il ne peut pas agir tant qu'il n'a pas atteint 3 PV.",
|
||||
"Luck": "Chance",
|
||||
"luck": "Chance",
|
||||
"Other": "Autre",
|
||||
"Skills": "Compétences",
|
||||
"WP": "PVO",
|
||||
"titleLuck": "Jet de Chance",
|
||||
"healingRoll": "Jet de soin, PV soignés",
|
||||
"healingRollFailure": "Jet de soin échoué critique, PV perdus",
|
||||
@@ -680,7 +751,29 @@
|
||||
"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)",
|
||||
"applyWounds": "Appliquer à",
|
||||
"opposedRollWinner": "Gagnant du jet opposé",
|
||||
"opposedRollResult": "Résultat du jet opposé",
|
||||
"defeats": "Défait",
|
||||
"critical": "Critique",
|
||||
"other": "Autre",
|
||||
"str": "FOR",
|
||||
"dex": "DEX",
|
||||
"int": "INT",
|
||||
"pow": "POU",
|
||||
"con": "CON",
|
||||
"cha": "CHA",
|
||||
"Luck": "Chance",
|
||||
"Damage": "Dégâts"
|
||||
},
|
||||
"ChatMessage": {
|
||||
"exhausted": "Votre protagoniste est épuisé. Il perd [[/r 1d6]] Points de Volonté."
|
||||
@@ -701,11 +794,16 @@
|
||||
"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": {
|
||||
"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",
|
||||
@@ -714,7 +812,9 @@
|
||||
"NoAmmo": "Aucune munition disponible pour cette arme.",
|
||||
"noRollDataFound": "Aucune donnée de jet trouvée.",
|
||||
"noActorFound": "Aucun protagoniste trouvé.",
|
||||
"noSanLossFound": "Aucune valeur de perte de SAN trouvée."
|
||||
"noSanLossFound": "Aucune valeur de perte de SAN trouvée.",
|
||||
"opposedRollFirstStored": "Premier jet opposé enregistré. Effectuez et enregistrez le deuxième jet pour résoudre le jet opposé.",
|
||||
"opposedRollSecondStored": "Deuxième jet opposé enregistré. Le jet opposé est maintenant en cours de résolution."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
macro_roll.js
Normal file
19
macro_roll.js
Normal file
@@ -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))
|
||||
@@ -1,6 +1,8 @@
|
||||
// System Module Imports
|
||||
import { Utils } from './utils.js'
|
||||
import { SYSTEM } from "../../config/system.mjs"
|
||||
import CthulhuEternalUtils from '../../utils.mjs'
|
||||
|
||||
export let ActionHandler = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
@@ -38,7 +40,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
* @private
|
||||
*/
|
||||
#buildCharacterActions() {
|
||||
this.buildAttributes()
|
||||
this.buildCharacteristics()
|
||||
this.buildOther()
|
||||
this.buildLuck()
|
||||
this.buildSkills()
|
||||
@@ -49,17 +51,17 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
return game.settings.get('token-action-hud-core', 'tooltips') === 'none'
|
||||
}
|
||||
|
||||
async buildAttributes() {
|
||||
async buildCharacteristics() {
|
||||
const actions = []
|
||||
for (const key in this.actor.system.characteristics) {
|
||||
const encodedValue = [coreModule.api.Utils.i18n('attributes'), key].join(this.delimiter)
|
||||
const encodedValue = ['characteristics', key].join(this.delimiter)
|
||||
const tooltip = {
|
||||
content: String(this.actor.system.characteristics[key].value * 5),
|
||||
class: 'tah-system-tooltip',
|
||||
direction: 'LEFT'
|
||||
}
|
||||
actions.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.' + key),
|
||||
name: coreModule.api.Utils.i18n(`CTHULHUETERNAL.Label.${key}`),
|
||||
id: key,
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
tooltip,
|
||||
@@ -67,7 +69,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
})
|
||||
}
|
||||
await this.addActions(actions, {
|
||||
id: 'attributes',
|
||||
id: 'characteristics',
|
||||
type: 'system'
|
||||
})
|
||||
}
|
||||
@@ -80,79 +82,83 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
direction: 'LEFT'
|
||||
}
|
||||
actions.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Luck'),
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.luck'),
|
||||
id: 'luck',
|
||||
info1: this.#showValue() ? { text: '50' } : null,
|
||||
tooltip,
|
||||
encodedValue: ['attributes', 'luck'].join(this.delimiter)
|
||||
encodedValue: ['characteristics', 'luck'].join(this.delimiter)
|
||||
})
|
||||
await this.addActions(actions, { id: 'luck', type: 'system' })
|
||||
}
|
||||
|
||||
async buildOther() {
|
||||
if (typeof this.actor.system.sanity.value !== 'undefined') {
|
||||
if (typeof this.actor.system?.san?.value !== 'undefined') {
|
||||
const actions = []
|
||||
const groupData = {
|
||||
id: 'other_sanity',
|
||||
id: 'other_san',
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
|
||||
type: 'system'
|
||||
}
|
||||
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
|
||||
const tooltip = {
|
||||
content: String(this.actor.system.san.value + '/' + this.actor.system.san.max),
|
||||
content: `${this.actor.system.san.value}/${this.actor.system.san.max}`,
|
||||
class: 'tah-system-tooltip',
|
||||
direction: 'LEFT'
|
||||
}
|
||||
actions.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
|
||||
id: 'sanity',
|
||||
id: 'san',
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
tooltip,
|
||||
encodedValue: ['attributes', 'sanity'].join(this.delimiter)
|
||||
encodedValue: ['characteristics', 'san'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '+',
|
||||
id: 'sanity_add',
|
||||
encodedValue: ['attributes', 'sanity_add'].join(this.delimiter)
|
||||
id: 'san_add',
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'san_add'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '-',
|
||||
id: 'sanity_subtract',
|
||||
encodedValue: ['attributes', 'sanity_subtract'].join(this.delimiter)
|
||||
id: 'san_subtract',
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'san_subtract'].join(this.delimiter)
|
||||
})
|
||||
await this.addActions(actions, { id: 'other_sanity', type: 'system' })
|
||||
await this.addActions(actions, { id: 'other_san', type: 'system' })
|
||||
}
|
||||
if (typeof this.actor.system.hp.value !== 'undefined') {
|
||||
const actions = []
|
||||
const groupData = {
|
||||
id: 'other_health',
|
||||
id: 'other_hp',
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
|
||||
type: 'system'
|
||||
}
|
||||
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
|
||||
const tooltip = {
|
||||
content: String(this.actor.system.hp.value + '/' + this.actor.system.hp.max),
|
||||
content: `${this.actor.system.hp.value}/${this.actor.system.hp.max}`,
|
||||
class: 'tah-system-tooltip',
|
||||
direction: 'LEFT'
|
||||
}
|
||||
actions.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
|
||||
id: 'health',
|
||||
id: 'hp',
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
tooltip,
|
||||
encodedValue: ['attributes', 'health'].join(this.delimiter)
|
||||
encodedValue: ['characteristics', 'hp'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '+',
|
||||
id: 'health_add',
|
||||
encodedValue: ['attributes', 'health_add'].join(this.delimiter)
|
||||
id: 'hp_add',
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'hp_add'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '-',
|
||||
id: 'health_subtract',
|
||||
encodedValue: ['attributes', 'health_subtract'].join(this.delimiter)
|
||||
id: 'hp_subtract',
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'hp_subtract'].join(this.delimiter)
|
||||
})
|
||||
await this.addActions(actions, { id: 'other_health', type: 'system' })
|
||||
await this.addActions(actions, { id: 'other_hp', type: 'system' })
|
||||
}
|
||||
if (typeof this.actor.system.wp.value !== 'undefined') {
|
||||
const actions = []
|
||||
@@ -163,7 +169,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
}
|
||||
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
|
||||
const tooltip = {
|
||||
content: String(this.actor.system.wp.value + '/' + this.actor.system.wp.max),
|
||||
content: `${this.actor.system.wp.value}/${this.actor.system.wp.max}`,
|
||||
class: 'tah-system-tooltip',
|
||||
direction: 'LEFT'
|
||||
}
|
||||
@@ -172,17 +178,19 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
id: 'wp',
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
tooltip,
|
||||
encodedValue: ['attributes', 'wp'].join(this.delimiter)
|
||||
encodedValue: ['characteristics', 'wp'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '+',
|
||||
id: 'wp_add',
|
||||
encodedValue: ['attributes', 'wp_add'].join(this.delimiter)
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'wp_add'].join(this.delimiter)
|
||||
},
|
||||
{
|
||||
name: '-',
|
||||
id: 'wp_subtract',
|
||||
encodedValue: ['attributes', 'wp_subtract'].join(this.delimiter)
|
||||
tooltip,
|
||||
encodedValue: ['characteristics', 'wp_subtract'].join(this.delimiter)
|
||||
})
|
||||
await this.addActions(actions, { id: 'other_wp', type: 'system' })
|
||||
}
|
||||
@@ -190,19 +198,23 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
|
||||
async buildSkills() {
|
||||
const actions = []
|
||||
let actorSkills = this.actor.items.filter(item => item.type === 'skill')
|
||||
for (const skill in actorSkills) {
|
||||
if (skill.system.computeScore() > 0) {
|
||||
// Build alpha sorted skill list
|
||||
let skills = this.actor.items.filter(i => i.type === 'skill')
|
||||
skills = skills.sort((a, b) => a.name.localeCompare(b.name))
|
||||
console.log('Building skills actions for skills:', skills)
|
||||
for (const skill of skills) {
|
||||
console.log('Processing skill item:', skill)
|
||||
if (skill.system.skillTotal > 0) {
|
||||
const tooltip = {
|
||||
content: String(skill.skill.system.computeScore()),
|
||||
content: String(skill.system.skillTotal),
|
||||
direction: 'LEFT'
|
||||
}
|
||||
actions.push({
|
||||
name: skill.name,
|
||||
name: `${skill.name} (${skill.system.skillTotal})`,
|
||||
id: skill.id,
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
tooltip,
|
||||
encodedValue: ['skills', s].join(this.delimiter)
|
||||
encodedValue: ['skills', skill.id].join(this.delimiter)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -210,62 +222,55 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
}
|
||||
|
||||
async buildEquipment() {
|
||||
let weapons = this.actor.items.filter(item => item.type === 'weapon')
|
||||
let skills = this.actor.items.filter(item => item.type === 'skill')
|
||||
for (const item of weapons) {
|
||||
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
|
||||
|
||||
// const rituals = []
|
||||
for (const item of this.actor.items) {
|
||||
// Push the weapon name as a new group
|
||||
const groupData = {
|
||||
id: 'weapons_' + item._id,
|
||||
id: `weapons_${item._id}`,
|
||||
name: item.name,
|
||||
type: 'system'
|
||||
}
|
||||
if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
|
||||
continue
|
||||
}
|
||||
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
|
||||
let skill = skills.find(skill => skill.name.toLowerCase() === skillName.toLowerCase())
|
||||
this.addGroup(groupData, { id: 'weapons', type: 'system' }, true)
|
||||
if (item.type === 'weapon') {
|
||||
const weapons = []
|
||||
let skill = CthulhuEternalUtils.getWeaponSkill(this.actor, item, era)
|
||||
item.skillTotal = skill ? skill.system.skillTotal : 0
|
||||
let weapons = []
|
||||
const tooltip = {
|
||||
content: String(skill.system.computeScore()),
|
||||
content: String(item.skillTotal),
|
||||
direction: 'LEFT'
|
||||
}
|
||||
console.log('Weapon skill total for', item.name, 'is', item.skillTotal, item._id)
|
||||
weapons.push({
|
||||
name: skill.name,
|
||||
id: skill._id,
|
||||
name: `${item.name} (${item.skillTotal})`,
|
||||
id: `weapon_${item._id}`,
|
||||
info1: this.#showValue() ? { text: tooltip.content } : null,
|
||||
encodedValue: ['weapons', item._id].join(this.delimiter),
|
||||
tooltip
|
||||
})
|
||||
let damage = ''
|
||||
if (item.system.lethality > 0) {
|
||||
damage = `L:${item.system.lethality}%`
|
||||
} else {
|
||||
damage = item.system.damage
|
||||
}
|
||||
const damageTooltip = {
|
||||
content: String(item.system.damage),
|
||||
content: String(damage),
|
||||
direction: 'LEFT'
|
||||
}
|
||||
if (item.system.damage !== '') {
|
||||
weapons.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage'),
|
||||
id: item._id,
|
||||
name: `${coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage')} (${damage})`,
|
||||
id: `damage_${item._id}`,
|
||||
info1: this.#showValue() ? { text: damageTooltip.content } : null,
|
||||
encodedValue: ['damage', item._id].join(this.delimiter),
|
||||
tooltip: damageTooltip
|
||||
})
|
||||
}
|
||||
if (item.system.isLethal) {
|
||||
const lethalityTooltip = {
|
||||
content: String(item.system.lethality),
|
||||
direction: 'LEFT'
|
||||
}
|
||||
weapons.push({
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Lethality'),
|
||||
id: item._id,
|
||||
info1: this.#showValue() ? { text: lethalityTooltip.content } : null,
|
||||
encodedValue: ['lethality', item._id].join(this.delimiter),
|
||||
tooltip: lethalityTooltip
|
||||
})
|
||||
}
|
||||
console.log('Adding weapon actions for', item.name, weapons)
|
||||
await this.addActions(weapons, {
|
||||
id: 'weapons_' + item._id,
|
||||
id: `weapons_${item._id}`,
|
||||
type: 'system'
|
||||
})
|
||||
}/* else if (item.type === 'ritual') {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* Module-based constants
|
||||
*/
|
||||
export const SYSTEM = {
|
||||
ID: 'fvtt-cthulhu-eternal'
|
||||
export const MODULE = {
|
||||
ID: 'token-action-hud-cthulhu-eternal'
|
||||
}
|
||||
|
||||
/**
|
||||
* Core module
|
||||
*/
|
||||
export const CORE_MODULE = {
|
||||
ID: 'token-action-hud-core'
|
||||
ID: 'token-action-hud-core'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,18 +21,19 @@ export const REQUIRED_CORE_MODULE_VERSION = '2.0'
|
||||
* Action types
|
||||
*/
|
||||
export const ACTION_TYPE = {
|
||||
attributes: 'CTHULHUETERNAL.Label.Characteristics',
|
||||
skills: 'CTHULHUETERNAL.Label.Skill',
|
||||
equipment: 'CTHULHUETERNAL.Label.Gear'
|
||||
characteristics: 'CTHULHUETERNAL.Label.characteristics',
|
||||
skills: 'CTHULHUETERNAL.Label.Skills',
|
||||
equipment: 'CTHULHUETERNAL.Label.gear'
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups
|
||||
*/
|
||||
export const GROUP = {
|
||||
attributes: { id: 'attributes', name: 'CTHULHUETERNAL.Label.Characteristics', type: 'system' },
|
||||
luck: { id: 'luck', name: 'CTHULHUETERNAL.Label.Luck', type: 'system'},
|
||||
skills: { id: 'skills', name: 'CTHULHUETERNAL.Label.Skills', type: 'system' },
|
||||
weapons: { id: 'weapons', name: 'CTHULHUETERNAL.Label.Weapons', type: 'system' },
|
||||
rituals: { id: 'rituals', name: 'CTHULHUETERNAL.Label.Rituals', type: 'system' }
|
||||
characteristics: { id: 'characteristics', name: 'CTHULHUETERNAL.Label.characteristics', type: 'system' },
|
||||
luck: { id: 'luck', name: 'CTHULHUETERNAL.Label.luck', type: 'system' },
|
||||
other: { id: 'other', name: 'CTHULHUETERNAL.Label.other', type: 'system' },
|
||||
skills: { id: 'skills', name: 'CTHULHUETERNAL.Label.Skills', type: 'system' },
|
||||
weapons: { id: 'weapons', name: 'CTHULHUETERNAL.Label.weapons', type: 'system' },
|
||||
rituals: { id: 'rituals', name: 'CTHULHUETERNAL.Label.rituals', type: 'system' }
|
||||
}
|
||||
|
||||
@@ -6,44 +6,42 @@ import { GROUP } from './constants.js'
|
||||
export let DEFAULTS = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
const groups = GROUP
|
||||
Object.values(groups).forEach(group => {
|
||||
group.name = coreModule.api.Utils.i18n(group.name)
|
||||
group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}`
|
||||
})
|
||||
const groupsArray = Object.values(groups)
|
||||
DEFAULTS = {
|
||||
layout: [
|
||||
{
|
||||
nestId: 'statistics',
|
||||
id: 'statistics',
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Characteristics'),
|
||||
groups: [
|
||||
{ ...groups.attributes, nestId: 'statistics_attributes' },
|
||||
{ ...groups.other, nestId: 'statistics_other' },
|
||||
{ ...groups.luck, nestId: 'statistics_luck' }
|
||||
]
|
||||
},
|
||||
{
|
||||
nestId: 'skills',
|
||||
id: 'skills',
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Skills'),
|
||||
groups: [
|
||||
{ ...groups.skills, nestId: 'skills_skills' },
|
||||
{ ...groups.typedSkills, nestId: 'skills_typed' },
|
||||
{ ...groups.specialTraining, nestId: 'skills_special' }
|
||||
]
|
||||
},
|
||||
{
|
||||
nestId: 'equipment',
|
||||
id: 'equipment',
|
||||
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Gear'),
|
||||
groups: [
|
||||
{ ...groups.weapons, nestId: 'equipment_weapons' },
|
||||
{ ...groups.rituals, nestId: 'equipment_rituals' }
|
||||
]
|
||||
}
|
||||
],
|
||||
groups: groupsArray
|
||||
}
|
||||
const groups = GROUP
|
||||
Object.values(groups).forEach(group => {
|
||||
group.name = coreModule.api.Utils.i18n(group.name)
|
||||
group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}`
|
||||
})
|
||||
const groupsArray = Object.values(groups)
|
||||
DEFAULTS = {
|
||||
layout: [
|
||||
{
|
||||
nestId: 'statistics',
|
||||
id: 'statistics',
|
||||
name: game.i18n.localize('CTHULHUETERNAL.Label.characteristics'),
|
||||
groups: [
|
||||
{ ...groups.characteristics, nestId: 'statistics_characteristics' },
|
||||
{ ...groups.other, nestId: 'statistics_other' },
|
||||
{ ...groups.luck, nestId: 'statistics_luck' }
|
||||
]
|
||||
},
|
||||
{
|
||||
nestId: 'skills',
|
||||
id: 'skills',
|
||||
name: game.i18n.localize('CTHULHUETERNAL.Label.skills'),
|
||||
groups: [
|
||||
{ ...groups.skills, nestId: 'skills_skills' }
|
||||
]
|
||||
},
|
||||
{
|
||||
nestId: 'equipment',
|
||||
id: 'equipment',
|
||||
name: game.i18n.localize('CTHULHUETERNAL.Label.gear'),
|
||||
groups: [
|
||||
{ ...groups.weapons, nestId: 'equipment_weapons' },
|
||||
{ ...groups.rituals, nestId: 'equipment_rituals' }
|
||||
]
|
||||
}
|
||||
],
|
||||
groups: groupsArray
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,304 +1,236 @@
|
||||
|
||||
import { SYSTEM } from "../../config/system.mjs"
|
||||
import CthulhuEternalRoll from '../../documents/roll.mjs'
|
||||
|
||||
export let RollHandler = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
|
||||
*/
|
||||
RollHandler = class RollHandler extends coreModule.api.RollHandler {
|
||||
/**
|
||||
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
|
||||
* Handle action click
|
||||
* Called by Token Action HUD Core when an action is left or right-clicked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
RollHandler = class RollHandler extends coreModule.api.RollHandler {
|
||||
/**
|
||||
* Handle action click
|
||||
* Called by Token Action HUD Core when an action is left or right-clicked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
async handleActionClick (event, encodedValue) {
|
||||
const [actionTypeId, actionId] = encodedValue.split('|')
|
||||
async handleActionClick(event, encodedValue) {
|
||||
const [actionTypeId, actionId] = encodedValue.split('|')
|
||||
|
||||
const knownCharacters = ['character']
|
||||
const knownCharacters = ['protagonist', 'creature']
|
||||
|
||||
// If single actor is selected
|
||||
if (this.actor) {
|
||||
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
|
||||
return
|
||||
}
|
||||
// If single actor is selected
|
||||
if (this.actor) {
|
||||
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
|
||||
return
|
||||
}
|
||||
|
||||
const controlledTokens = canvas.tokens.controlled
|
||||
.filter((token) => knownCharacters.includes(token.actor?.type))
|
||||
const controlledTokens = canvas.tokens.controlled
|
||||
.filter((token) => knownCharacters.includes(token.actor?.type))
|
||||
|
||||
// If multiple actors are selected
|
||||
for (const token of controlledTokens) {
|
||||
const actor = token.actor
|
||||
await this.#handleAction(event, actor, token, actionTypeId, actionId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action hover
|
||||
* Called by Token Action HUD Core when an action is hovered on or off
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
async handleActionHover (event, encodedValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle group click
|
||||
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {object} group The group
|
||||
*/
|
||||
async handleGroupClick (event, group) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {object} token The token
|
||||
* @param {string} actionTypeId The action type id
|
||||
* @param {string} actionId The actionId
|
||||
*/
|
||||
async #handleAction (event, actor, token, actionTypeId, actionId) {
|
||||
switch (actionTypeId) {
|
||||
case 'attributes':
|
||||
await this.#handleAttributesAction(event, actor, actionId)
|
||||
break
|
||||
case 'skills':
|
||||
await this.#handleSkillsAction(event, actor, actionId)
|
||||
break
|
||||
case 'weapons':
|
||||
await this.#handleWeaponsAction(event, actor, actionId)
|
||||
break
|
||||
case 'damage':
|
||||
await this.#handleDamageAction(event, actor, actionId)
|
||||
break
|
||||
case 'lethality':
|
||||
await this.#handleLethalityAction(event, actor, actionId)
|
||||
break
|
||||
case 'specialTraining':
|
||||
await this.#handleSpecialTrainingAction(event, actor, actionId)
|
||||
break
|
||||
case 'typedSkills':
|
||||
await this.#handleCustomTypedAction(event, actor, actionId)
|
||||
break
|
||||
/* case 'rituals':
|
||||
await this.#handleRitualsAction(event, actor, actionId)
|
||||
break */
|
||||
case 'utility':
|
||||
await this.#handleUtilityAction(token, actionId)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Attribute action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleAttributesAction (event, actor, actionId) {
|
||||
let rollType
|
||||
if (actionId === 'wp' || actionId === 'health') return
|
||||
if (actionId.includes('_add') || actionId.includes('_subtract')) {
|
||||
const attr = actionId.split('_')[0]
|
||||
const action = actionId.split('_')[1]
|
||||
const update = {}
|
||||
update.system = {}
|
||||
update.system[attr] = {}
|
||||
update.system[attr].value = action === 'add' ? this.actor.system[attr].value + 1 : this.actor.system[attr].value - 1
|
||||
if (update.system[attr].value > this.actor.system[attr].max || update.system[attr].value < this.actor.system[attr].min) return
|
||||
return await this.actor.update(update)
|
||||
}
|
||||
if (actionId === 'sanity') {
|
||||
rollType = actionId
|
||||
} else if (actionId === 'luck') {
|
||||
rollType = actionId
|
||||
} else {
|
||||
rollType = 'stat'
|
||||
}
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType,
|
||||
key: actionId
|
||||
}
|
||||
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
return await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Skill action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleSkillsAction (event, actor, actionId) {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'skill',
|
||||
key: actionId
|
||||
}
|
||||
|
||||
const skill = this.actor.system.skills[actionId]
|
||||
if (!skill) return ui.notifications.warn('Bad skill name in HUD.')
|
||||
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Typed/Custom skills action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleCustomTypedAction (event, actor, actionId) {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'skill',
|
||||
key: actionId
|
||||
}
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle SoecialTraining action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleSpecialTrainingAction (event, actor, actionId) {
|
||||
const attr = this.actor.system.specialTraining.find(a => a.name === actionId).attribute
|
||||
let target = 0
|
||||
if (DG.statistics.includes(attr)) {
|
||||
target = this.actor.system.statistics[attr].x5
|
||||
} else if (DG.skills.includes(attr)) {
|
||||
target = this.actor.system.skills[attr].proficiency
|
||||
} else {
|
||||
target = this.actor.system.typedSkills[attr].proficiency
|
||||
}
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'special-training',
|
||||
key: attr,
|
||||
specialTrainingName: actionId,
|
||||
target
|
||||
}
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Weapon action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleWeaponsAction (event, actor, actionId) {
|
||||
const item = this.actor.items.get(actionId)
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'weapon',
|
||||
key: item.system.skill,
|
||||
item
|
||||
}
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Damage action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleDamageAction (event, actor, actionId) {
|
||||
const item = this.actor.items.get(actionId)
|
||||
if (item.system.lethality > 0 && event.ctrlKey) {
|
||||
// Toggle on/off lethality
|
||||
const isLethal = !item.system.isLethal
|
||||
await item.update({ 'system.isLethal': isLethal })
|
||||
} else {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'damage',
|
||||
key: item.system.damage,
|
||||
item
|
||||
}
|
||||
const roll = new DGDamageRoll(item.system.damage, {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Lethality action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleLethalityAction (event, actor, actionId) {
|
||||
const item = await this.actor.items.get(actionId)
|
||||
if (item.system.damage !== '' && event.ctrlKey) {
|
||||
const isLethal = !item.system.isLethal
|
||||
await item.update({ 'system.isLethal': isLethal })
|
||||
} else {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'lethality',
|
||||
key: item.system.lethality,
|
||||
item
|
||||
}
|
||||
const roll = new DGLethalityRoll(item.system.damage, {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Ritual action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleRitualsAction (event, actor, actionId) {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'ritual',
|
||||
key: actionId
|
||||
}
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle utility action
|
||||
* @private
|
||||
* @param {object} token The token
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleUtilityAction (token, actionId) {
|
||||
switch (actionId) {
|
||||
case 'endTurn':
|
||||
if (game.combat?.current?.tokenId === token.id) {
|
||||
await game.combat?.nextTurn()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
// If multiple actors are selected
|
||||
for (const token of controlledTokens) {
|
||||
const actor = token.actor
|
||||
await this.#handleAction(event, actor, token, actionTypeId, actionId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action hover
|
||||
* Called by Token Action HUD Core when an action is hovered on or off
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {string} encodedValue The encoded value
|
||||
*/
|
||||
async handleActionHover(event, encodedValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle group click
|
||||
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
|
||||
* @override
|
||||
* @param {object} event The event
|
||||
* @param {object} group The group
|
||||
*/
|
||||
async handleGroupClick(event, group) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {object} token The token
|
||||
* @param {string} actionTypeId The action type id
|
||||
* @param {string} actionId The actionId
|
||||
*/
|
||||
async #handleAction(event, actor, token, actionTypeId, actionId) {
|
||||
console.log('Handling action', actionId, 'of type', actionTypeId, 'for actor', actor.name)
|
||||
switch (actionTypeId) {
|
||||
case 'characteristics':
|
||||
await this.#handleCharacteristicsAction(event, actor, actionId)
|
||||
break
|
||||
case 'skills':
|
||||
await this.#handleSkillsAction(event, actor, actionId)
|
||||
break
|
||||
case 'weapons':
|
||||
await this.#handleWeaponsAction(event, actor, actionId)
|
||||
break
|
||||
case 'damage':
|
||||
await this.#handleDamageAction(event, actor, actionId)
|
||||
break
|
||||
case 'lethality':
|
||||
await this.#handleLethalityAction(event, actor, actionId)
|
||||
break
|
||||
/* case 'rituals':
|
||||
await this.#handleRitualsAction(event, actor, actionId)
|
||||
break */
|
||||
case 'utility':
|
||||
await this.#handleUtilityAction(token, actionId)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Characteristic action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleCharacteristicsAction(event, actor, actionId) {
|
||||
let rollType
|
||||
if (actionId === 'wp' || actionId === 'hp') return
|
||||
|
||||
if (actionId.includes('_add') || actionId.includes('_subtract')) {
|
||||
const attr = actionId.split('_')[0]
|
||||
const action = actionId.split('_')[1]
|
||||
console.log('Updating', attr, 'with action', action)
|
||||
const update = {}
|
||||
update.system = {}
|
||||
update.system[attr] = {}
|
||||
update.system[attr].value = action === 'add' ? this.actor.system[attr].value + 1 : this.actor.system[attr].value - 1
|
||||
if (update.system[attr].value > this.actor.system[attr].max || update.system[attr].value < this.actor.system[attr].min) return
|
||||
return await this.actor.update(update)
|
||||
}
|
||||
if (actionId === 'san') {
|
||||
let item = foundry.utils.duplicate(actor.system.san)
|
||||
item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN")
|
||||
item.targetScore = item.value
|
||||
await actor.system.roll('san', item)
|
||||
} else if (actionId === 'luck') {
|
||||
let item = foundry.utils.duplicate(actor.system.characteristics.int)
|
||||
item.name = game.i18n.localize("CTHULHUETERNAL.Label.Luck")
|
||||
item.value = 10
|
||||
item.targetScore = 50
|
||||
await actor.system.roll('luck', item)
|
||||
} else {
|
||||
let item = foundry.utils.duplicate(actor.system.characteristics[actionId])
|
||||
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.${actionId}Long`)
|
||||
item.targetScore = item.value * 5
|
||||
await actor.system.roll('char', item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Skill action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleSkillsAction(event, actor, actionId) {
|
||||
const skill = actor.items.find(i => i.type === 'skill' && i.id === actionId)
|
||||
if (!skill) return ui.notifications.warn(`Skill not found for action id '${actionId}'`)
|
||||
await actor.system.roll('skill', skill)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle Weapon action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleWeaponsAction(event, actor, actionId) {
|
||||
let weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
|
||||
weapon.damageFormula = weapon.system.damage
|
||||
weapon.damageBonus = actor.system.damageBonus
|
||||
await actor.system.roll('weapon', weapon)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Damage action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleDamageAction(event, actor, actionId) {
|
||||
let weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
|
||||
weapon.damageFormula = weapon.system.damage
|
||||
weapon.damageBonus = actor.system.damageBonus
|
||||
await actor.system.roll('damage', weapon)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Lethality action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleLethalityAction(event, actor, actionId) {
|
||||
const item = await this.actor.items.get(actionId)
|
||||
if (item.system.damage !== '' && event.ctrlKey) {
|
||||
const isLethal = !item.system.isLethal
|
||||
await item.update({ 'system.isLethal': isLethal })
|
||||
} else {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'lethality',
|
||||
key: item.system.lethality,
|
||||
item
|
||||
}
|
||||
/* TOFIX
|
||||
const roll = new DGLethalityRoll(item.system.damage, {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Ritual action
|
||||
* @private
|
||||
* @param {object} event The event
|
||||
* @param {object} actor The actor
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleRitualsAction(event, actor, actionId) {
|
||||
const options = {
|
||||
actor: this.actor,
|
||||
rollType: 'ritual',
|
||||
key: actionId
|
||||
}
|
||||
const roll = new DGPercentileRoll('1D100', {}, options)
|
||||
await this.actor.sheet.processRoll(event, roll)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle utility action
|
||||
* @private
|
||||
* @param {object} token The token
|
||||
* @param {string} actionId The action id
|
||||
*/
|
||||
async #handleUtilityAction(token, actionId) {
|
||||
switch (actionId) {
|
||||
case 'endTurn':
|
||||
if (game.combat?.current?.tokenId === token.id) {
|
||||
await game.combat?.nextTurn()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
9
module/applications/hud/settings.js
Normal file
9
module/applications/hud/settings.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { MODULE } from './constants.js'
|
||||
|
||||
/**
|
||||
* Register module settings
|
||||
* Called by Token Action HUD Core to register Token Action HUD system module settings
|
||||
* @param {function} coreUpdate Token Action HUD Core update function
|
||||
*/
|
||||
export function register (coreUpdate) {
|
||||
}
|
||||
@@ -1,91 +1,92 @@
|
||||
// System Module Imports
|
||||
import { ActionHandler } from './action-handler.js'
|
||||
import { RollHandler as Core } from './roll-handler.js'
|
||||
import { SYSTEM } from './constants.js'
|
||||
import { MODULE } from './constants.js'
|
||||
import { DEFAULTS } from './defaults.js'
|
||||
import * as systemSettings from './settings.js'
|
||||
|
||||
export let SystemManager = null
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Extends Token Action HUD Core's SystemManager class
|
||||
*/
|
||||
SystemManager = class SystemManager extends coreModule.api.SystemManager {
|
||||
/**
|
||||
* Extends Token Action HUD Core's SystemManager class
|
||||
* Returns an instance of the ActionHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {class} The ActionHandler instance
|
||||
*/
|
||||
SystemManager = class SystemManager extends coreModule.api.SystemManager {
|
||||
/**
|
||||
* Returns an instance of the ActionHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {class} The ActionHandler instance
|
||||
*/
|
||||
getActionHandler () {
|
||||
return new ActionHandler()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of roll handlers to Token Action HUD Core
|
||||
* Used to populate the Roll Handler module setting choices
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The available roll handlers
|
||||
*/
|
||||
getAvailableRollHandlers () {
|
||||
const coreTitle = 'Core Template'
|
||||
const choices = { core: coreTitle }
|
||||
return choices
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the RollHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {string} rollHandlerId The roll handler ID
|
||||
* @returns {class} The RollHandler instance
|
||||
*/
|
||||
getRollHandler (rollHandlerId) {
|
||||
let rollHandler
|
||||
switch (rollHandlerId) {
|
||||
case 'core':
|
||||
default:
|
||||
rollHandler = new Core()
|
||||
break
|
||||
}
|
||||
return rollHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default layout and groups to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @returns {object} The default layout and groups
|
||||
*/
|
||||
async registerDefaults () {
|
||||
return DEFAULTS
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Token Action HUD system module settings
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {function} coreUpdate The Token Action HUD Core update function
|
||||
*/
|
||||
registerSettings (coreUpdate) {
|
||||
/*systemSettings.register(coreUpdate)*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns styles to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The TAH system styles
|
||||
*/
|
||||
registerStyles () {
|
||||
return {
|
||||
template: {
|
||||
class: 'tah-style-template-style', // The class to add to first DIV element
|
||||
file: 'tah-template-style', // The file without the css extension
|
||||
moduleId: SYSTEM.ID, // The module ID
|
||||
name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting
|
||||
}
|
||||
}
|
||||
}
|
||||
getActionHandler() {
|
||||
return new ActionHandler()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of roll handlers to Token Action HUD Core
|
||||
* Used to populate the Roll Handler module setting choices
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The available roll handlers
|
||||
*/
|
||||
getAvailableRollHandlers() {
|
||||
const coreTitle = 'Core Template'
|
||||
const choices = { core: coreTitle }
|
||||
return choices
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the RollHandler to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {string} rollHandlerId The roll handler ID
|
||||
* @returns {class} The RollHandler instance
|
||||
*/
|
||||
getRollHandler(rollHandlerId) {
|
||||
let rollHandler
|
||||
switch (rollHandlerId) {
|
||||
case 'core':
|
||||
default:
|
||||
rollHandler = new Core()
|
||||
break
|
||||
}
|
||||
return rollHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default layout and groups to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @returns {object} The default layout and groups
|
||||
*/
|
||||
async registerDefaults() {
|
||||
return DEFAULTS
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Token Action HUD system module settings
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @param {function} coreUpdate The Token Action HUD Core update function
|
||||
*/
|
||||
registerSettings(coreUpdate) {
|
||||
systemSettings.register(coreUpdate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns styles to Token Action HUD Core
|
||||
* Called by Token Action HUD Core
|
||||
* @override
|
||||
* @returns {object} The TAH system styles
|
||||
*/
|
||||
registerStyles() {
|
||||
return {
|
||||
template: {
|
||||
class: 'tah-style-template-style', // The class to add to first DIV element
|
||||
file: 'tah-template-style', // The file without the css extension
|
||||
moduleId: MODULE.ID, // The module ID
|
||||
name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,22 +1,7 @@
|
||||
import { SYSTEM } from './constants.js'
|
||||
import { MODULE } from './constants.js'
|
||||
|
||||
export let Utils = null
|
||||
|
||||
function registerHUD() {
|
||||
Hooks.on('tokenActionHudCoreApiReady', async () => {
|
||||
/**
|
||||
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
|
||||
*/
|
||||
const module = game.system
|
||||
module.api = {
|
||||
requiredCoreModuleVersion: "2.0",
|
||||
SystemManager
|
||||
}
|
||||
Hooks.call('tokenActionHudSystemReady', module)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
/**
|
||||
* Utility functions
|
||||
@@ -31,7 +16,7 @@ Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
|
||||
static getSetting(key, defaultValue = null) {
|
||||
let value = defaultValue ?? null
|
||||
try {
|
||||
value = game.settings.get(SYSTEM.ID, key)
|
||||
value = game.settings.get(MODULE.ID, key)
|
||||
} catch {
|
||||
coreModule.api.Logger.debug(`Setting '${key}' not found`)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin(
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new DragDrop(d)
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -141,14 +141,14 @@ export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin(
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragOver(event) {}
|
||||
_onDragOver(event) { }
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {}
|
||||
async _onDrop(event) { }
|
||||
|
||||
// #endregion
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ export default class CthulhuEternalCreatureSheet extends CthulhuEternalActorShee
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
||||
context.enrichedNotes = await TextEditor.enrichHTML(this.document.system.notes, { async: true })
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.notes, { async: true })
|
||||
|
||||
context.tooltipsCharacteristic = {
|
||||
str: game.i18n.localize("CTHULHUETERNAL.Characteristic.Str"),
|
||||
|
||||
@@ -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
|
||||
@@ -225,6 +235,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":
|
||||
|
||||
@@ -43,77 +43,167 @@ export const INSANITY = {
|
||||
|
||||
export const ERA_CSS = {
|
||||
jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", baseFontSize: "0.95rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%)" },
|
||||
modern: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Georama", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" },
|
||||
future: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Seabreed", baseFontSize: "1.0rem", titleFontSize: "2.0rem",imgFilter: "invert(90%) sepia(6%) saturate(1818%) hue-rotate(152deg) brightness(91%) contrast(91%)" },
|
||||
victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" },
|
||||
coldwar: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "TopSecret", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)"},
|
||||
revolution: { primaryFont: "IMFell", secondaryFont: "IMFell", titleFont: "Dominican", baseFontSize: "1.0rem",titleFontSize: "1.3rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" },
|
||||
medieval: { primaryFont: "Skranji", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"},
|
||||
ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)"},
|
||||
ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)"},
|
||||
ageofsail: { primaryFont: "SailRegular", secondaryFont: "SailRegular", titleFont: "P22Operina", baseFontSize: "1.1rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" },
|
||||
classical: { primaryFont: "ChantelliAntiqua", secondaryFont: "ChantelliAntiqua", titleFont: "TrajanPro", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" },
|
||||
postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.35rem",titleFontSize: "1.5rem",imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
|
||||
modern: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Georama", baseFontSize: "1.0rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" },
|
||||
future: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Seabreed", baseFontSize: "1.0rem", titleFontSize: "2.0rem", imgFilter: "invert(90%) sepia(6%) saturate(1818%) hue-rotate(152deg) brightness(91%) contrast(91%)" },
|
||||
victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", baseFontSize: "1.0rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" },
|
||||
coldwar: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "TopSecret", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)" },
|
||||
revolution: { primaryFont: "IMFell", secondaryFont: "IMFell", titleFont: "Dominican", baseFontSize: "1.0rem", titleFontSize: "1.3rem", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" },
|
||||
medieval: { primaryFont: "Skranji", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)" },
|
||||
ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem", titleFontSize: "1.2rem", imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)" },
|
||||
ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem", titleFontSize: "1.1rem", imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)" },
|
||||
ageofsail: { primaryFont: "SailRegular", secondaryFont: "SailRegular", titleFont: "P22Operina", baseFontSize: "1.1rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" },
|
||||
classical: { primaryFont: "ChantelliAntiqua", secondaryFont: "ChantelliAntiqua", titleFont: "TrajanPro", baseFontSize: "0.9rem", titleFontSize: "1.1rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" },
|
||||
postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.35rem", titleFontSize: "1.5rem", imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
|
||||
}
|
||||
|
||||
export const RESOURCE_RATING = {
|
||||
jazz: {
|
||||
0: {name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets"},
|
||||
4: {name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 700, assets: "CTHULHUETERNAL.Resource.PoorJazz"},
|
||||
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 3000, assets: "CTHULHUETERNAL.Resource.AverageJazz"},
|
||||
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 5000, assets: "CTHULHUETERNAL.Resource.AboveAverageJazz"},
|
||||
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 10000, assets: "CTHULHUETERNAL.Resource.WellOffJazz"},
|
||||
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 15000, assets: "CTHULHUETERNAL.Resource.RichJazz"},
|
||||
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 50000, assets: "CTHULHUETERNAL.Resource.VeryRichJazz"},
|
||||
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 100000, assets: "CTHULHUETERNAL.Resource.SuperRichJazz"}
|
||||
0: { name: "Penury", description: "CTHULHUETERNAL.Resource.Penury", income: 0, assets: "CTHULHUETERNAL.Resource.NoAssets" },
|
||||
4: { name: "Poor", description: "CTHULHUETERNAL.Resource.Poor", income: 700, assets: "CTHULHUETERNAL.Resource.PoorJazz" },
|
||||
8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 3000, assets: "CTHULHUETERNAL.Resource.AverageJazz" },
|
||||
12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 5000, assets: "CTHULHUETERNAL.Resource.AboveAverageJazz" },
|
||||
16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 10000, assets: "CTHULHUETERNAL.Resource.WellOffJazz" },
|
||||
18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 15000, assets: "CTHULHUETERNAL.Resource.RichJazz" },
|
||||
19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 50000, assets: "CTHULHUETERNAL.Resource.VeryRichJazz" },
|
||||
20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 100000, assets: "CTHULHUETERNAL.Resource.SuperRichJazz" }
|
||||
},
|
||||
modern: {
|
||||
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"}
|
||||
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" }
|
||||
},
|
||||
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"},
|
||||
8: {name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 90, assets: "CTHULHUETERNAL.Resource.AverageVictorian"},
|
||||
12: {name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 400, assets: "CTHULHUETERNAL.Resource.AboveAverageVictorian"},
|
||||
16: {name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 1500, assets: "CTHULHUETERNAL.Resource.WellOffVictorian"},
|
||||
18: {name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 5000, assets: "CTHULHUETERNAL.Resource.RichVictorian"},
|
||||
19: {name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 40000, assets: "CTHULHUETERNAL.Resource.VeryRichVictorian"},
|
||||
20: {name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 200000, assets: "CTHULHUETERNAL.Resource.SuperRichVictorian"}
|
||||
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" },
|
||||
8: { name: "Average", description: "CTHULHUETERNAL.Resource.Average", income: 90, assets: "CTHULHUETERNAL.Resource.AverageVictorian" },
|
||||
12: { name: "Above Average", description: "CTHULHUETERNAL.Resource.AboveAverage", income: 400, assets: "CTHULHUETERNAL.Resource.AboveAverageVictorian" },
|
||||
16: { name: "Well Off", description: "CTHULHUETERNAL.Resource.WellOff", income: 1500, assets: "CTHULHUETERNAL.Resource.WellOffVictorian" },
|
||||
18: { name: "Rich", description: "CTHULHUETERNAL.Resource.Rich", income: 5000, assets: "CTHULHUETERNAL.Resource.RichVictorian" },
|
||||
19: { name: "Very Rich", description: "CTHULHUETERNAL.Resource.VeryRich", income: 40000, assets: "CTHULHUETERNAL.Resource.VeryRichVictorian" },
|
||||
20: { name: "Super Rich", description: "CTHULHUETERNAL.Resource.SuperRich", income: 200000, assets: "CTHULHUETERNAL.Resource.SuperRichVictorian" }
|
||||
}
|
||||
}
|
||||
|
||||
export const RESOURCE_BREAKDOWN = [
|
||||
{ value: 0, hand: 0, stowed: 0, storage: 0, checks: 0},
|
||||
{ value: 1, hand: 1, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 2, hand: 2, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 3, hand: 3, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 4, hand: 4, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 5, hand: 5, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 6, hand: 6, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 7, hand: 6, stowed: 1, storage: 0, checks: 2},
|
||||
{ value: 8, hand: 6, stowed: 2, storage: 0, checks: 2},
|
||||
{ value: 9, hand: 6, stowed: 3, storage: 0, checks: 2},
|
||||
{ value: 10, hand: 6, stowed: 4, storage: 0, checks: 2},
|
||||
{ value: 11, hand: 6, stowed: 5, storage: 0, checks: 2},
|
||||
{ value: 12, hand: 6, stowed: 6, storage: 0, checks: 2},
|
||||
{ value: 13, hand: 6, stowed: 6, storage: 1, checks: 3},
|
||||
{ value: 14, hand: 6, stowed: 6, storage: 2, checks: 3},
|
||||
{ value: 15, hand: 6, stowed: 6, storage: 3, checks: 3},
|
||||
{ value: 16, hand: 6, stowed: 6, storage: 4, checks: 3},
|
||||
{ value: 17, hand: 6, stowed: 6, storage: 5, checks: 3},
|
||||
{ value: 18, hand: 6, stowed: 6, storage: 6, checks: 3},
|
||||
{ value: 19, hand: 6, stowed: 6, storage: 7, checks: 3},
|
||||
{ value: 20, hand: 6, stowed: 6, storage: 8, checks: 3}
|
||||
{ value: 0, hand: 0, stowed: 0, storage: 0, checks: 0 },
|
||||
{ value: 1, hand: 1, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 2, hand: 2, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 3, hand: 3, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 4, hand: 4, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 5, hand: 5, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 6, hand: 6, stowed: 0, storage: 0, checks: 1 },
|
||||
{ value: 7, hand: 6, stowed: 1, storage: 0, checks: 2 },
|
||||
{ value: 8, hand: 6, stowed: 2, storage: 0, checks: 2 },
|
||||
{ value: 9, hand: 6, stowed: 3, storage: 0, checks: 2 },
|
||||
{ value: 10, hand: 6, stowed: 4, storage: 0, checks: 2 },
|
||||
{ value: 11, hand: 6, stowed: 5, storage: 0, checks: 2 },
|
||||
{ value: 12, hand: 6, stowed: 6, storage: 0, checks: 2 },
|
||||
{ value: 13, hand: 6, stowed: 6, storage: 1, checks: 3 },
|
||||
{ value: 14, hand: 6, stowed: 6, storage: 2, checks: 3 },
|
||||
{ value: 15, hand: 6, stowed: 6, storage: 3, checks: 3 },
|
||||
{ value: 16, hand: 6, stowed: 6, storage: 4, checks: 3 },
|
||||
{ value: 17, hand: 6, stowed: 6, storage: 5, checks: 3 },
|
||||
{ value: 18, hand: 6, stowed: 6, storage: 6, checks: 3 },
|
||||
{ value: 19, hand: 6, stowed: 6, storage: 7, checks: 3 },
|
||||
{ value: 20, hand: 6, stowed: 6, storage: 8, checks: 3 }
|
||||
]
|
||||
|
||||
export const DAMAGE_BONUS = [ -2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
|
||||
export const DAMAGE_BONUS = [-2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
|
||||
|
||||
export const VEHICLE_SPEED = {
|
||||
"none": "CTHULHUETERNAL.Label.None",
|
||||
@@ -154,7 +244,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",
|
||||
@@ -239,12 +330,51 @@ export const MULTIPLIER_CHOICES = {
|
||||
}
|
||||
|
||||
export const WEAPON_SELECTIVE_FIRE_CHOICES = {
|
||||
"shortburst": { id: "shortburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortburst", ammoUsed: 3, lethality: 10, killRadius: 0},
|
||||
"longburst": { id: "longburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longburst", ammoUsed: 5, lethality: 10, killRadius: 1},
|
||||
"shortspray": { id: "shortspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortspray", ammoUsed: 10, lethality: 10, killRadius: 2},
|
||||
"longspray": { id: "longspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longspray", ammoUsed: 20, lethality: 10, killRadius: 3},
|
||||
"shortburst": { id: "shortburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortburst", ammoUsed: 3, lethality: 10, killRadius: 0 },
|
||||
"longburst": { id: "longburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longburst", ammoUsed: 5, lethality: 10, killRadius: 1 },
|
||||
"shortspray": { id: "shortspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortspray", ammoUsed: 10, lethality: 10, killRadius: 2 },
|
||||
"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 +407,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
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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,44 @@ 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 })
|
||||
}
|
||||
console.log("Applying wounds", { woundData, totalArmor, effectiveWounds })
|
||||
// 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 +111,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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
import CthulhuEternalUtils from "../utils.mjs"
|
||||
|
||||
export default class CthulhuEternalRoll extends Roll {
|
||||
/**
|
||||
@@ -106,7 +107,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
|
||||
@@ -128,20 +129,23 @@ 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
|
||||
}
|
||||
|
||||
let combatants = []
|
||||
if (game?.combat?.combatants) {
|
||||
for (let c of game.combat.combatants) {
|
||||
if (c.actorid !== actor.id) {
|
||||
combatants.push({ id: c.id, name: c.name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (weapon.system.lethality > 0) {
|
||||
@@ -149,59 +153,87 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
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
|
||||
}
|
||||
|
||||
// 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") {
|
||||
formula += ` + ${weapon.damageBonus}`
|
||||
let formula = weapon?.damageFormula || weapon.system.damage || "0"
|
||||
if (weapon.system.applyDamageBonus) {
|
||||
formula += ` + ${actor.system?.damageBonus}`
|
||||
}
|
||||
if (options?.previousResultType === "successCritical") {
|
||||
formula = `( ${formula} ) * 2`
|
||||
}
|
||||
|
||||
let damageRoll = new Roll(formula)
|
||||
await damageRoll.evaluate()
|
||||
let msgData = {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
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.aimingLastRoundFlag) ? 20 : 0
|
||||
modifier += (rollData.aimingWithSightFlag) ? 20 : 0
|
||||
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)
|
||||
}])
|
||||
}
|
||||
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 })
|
||||
weapon.ammoUsed = ammoUsed
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,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":
|
||||
@@ -265,26 +298,19 @@ 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 } }
|
||||
options.initialScore = options.weapon.system.directSkillValue
|
||||
} else {
|
||||
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
|
||||
options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
|
||||
if (!options.rollItem) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill"))
|
||||
return
|
||||
}
|
||||
options.initialScore = options.rollItem.system.computeScore()
|
||||
console.log("WEAPON", skillName, era, options.rollItem)
|
||||
}
|
||||
|
||||
options.rollItem = CthulhuEternalUtils.getWeaponSkill(actor, options.rollItem, era)
|
||||
options.initialScore = options.rollItem.system.skillTotal
|
||||
console.log("WEAPON", era, options.rollItem)
|
||||
}
|
||||
break
|
||||
default:
|
||||
@@ -310,6 +336,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,
|
||||
@@ -323,12 +350,27 @@ 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",
|
||||
aimingLastRoundFlag: false,
|
||||
aimingWithSightFlag: false,
|
||||
modifier,
|
||||
formula,
|
||||
targetName: target?.name,
|
||||
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)
|
||||
@@ -371,6 +413,14 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
options.multiplier = Number(event.target.value)
|
||||
this.updateResourceDialog(options)
|
||||
})
|
||||
$(".aimingLastRound").change(event => {
|
||||
options.aimingLastRoundFlag = event.target.checked
|
||||
this.updateResourceDialog(options)
|
||||
})
|
||||
$(".aimingWithSight").change(event => {
|
||||
options.aimingWithSightFlag = event.target.checked
|
||||
this.updateResourceDialog(options)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -378,14 +428,20 @@ 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 {
|
||||
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
|
||||
}
|
||||
@@ -394,11 +450,15 @@ 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"
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -455,10 +515,70 @@ 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
|
||||
rollData.isSuccess = this.options.isSuccess
|
||||
rollData.isFailure = this.options.isFailure
|
||||
rollData.isCritical = this.options.isCritical
|
||||
rollData.resultType = resultType
|
||||
rollData.rollResult = this.total
|
||||
rollData.total = this.total
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +676,7 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
* @returns {Promise} - A promise that resolves when the message is created.
|
||||
*/
|
||||
async toMessage(messageData = {}, { rollMode, create = true } = {}) {
|
||||
super.toMessage(
|
||||
let rollMsg = await super.toMessage(
|
||||
{
|
||||
isFailure: this.resultType === "failure",
|
||||
actingCharName: this.actorName,
|
||||
@@ -567,10 +687,11 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
},
|
||||
{ rollMode: rollMode },
|
||||
)
|
||||
|
||||
// Manage the skill evolution if the roll is a failure
|
||||
let rollData = this.options.rollData || this.options
|
||||
let rollItem = this.options.rollItem
|
||||
await rollMsg.setFlag("fvtt-cthulhu-eternal", "rollData", rollData)
|
||||
|
||||
// Manage the skill evolution if the roll is a failure
|
||||
if (rollData.resultType.includes("failure") && rollItem.type === "skill") {
|
||||
// Is the skill able to progress
|
||||
if (rollItem.system.diceEvolved && !rollItem.system.rollFailed) {
|
||||
@@ -600,12 +721,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
insanity: new fields.StringField({ required: true, nullable: false, initial: "none", choices: SYSTEM.INSANITY }),
|
||||
})
|
||||
|
||||
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: -2 })
|
||||
|
||||
schema.resources = new fields.SchemaField({
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }), // Unused but kept for compatibility
|
||||
@@ -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
|
||||
@@ -127,7 +131,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
dmgBonus = 0
|
||||
} else if (this.characteristics.str.value <= 16) {
|
||||
dmgBonus = 1
|
||||
} else if (this.characteristics.str.value <= 20) {
|
||||
} else if (this.characteristics.str.value <= 40) {
|
||||
dmgBonus = 2
|
||||
}
|
||||
if (this.damageBonus !== dmgBonus) {
|
||||
@@ -137,10 +141,16 @@ 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
|
||||
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 })
|
||||
})
|
||||
this.san.breakingPointReached = true // Force local update to true
|
||||
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
|
||||
@@ -195,10 +205,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,
|
||||
@@ -206,7 +212,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 = ""
|
||||
@@ -223,7 +229,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]
|
||||
@@ -235,7 +241,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)
|
||||
@@ -250,7 +256,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)
|
||||
@@ -265,14 +271,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 +297,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)
|
||||
@@ -344,15 +359,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>`,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
275
module/utils.mjs
275
module/utils.mjs
@@ -16,6 +16,14 @@ export default class CthulhuEternalUtils {
|
||||
config: true,
|
||||
onChange: _ => window.location.reload()
|
||||
});
|
||||
game.settings.register("fvtt-cthulhu-eternal", "roll-opposed-store", {
|
||||
name: "Roll Opposed Store",
|
||||
hint: "Whether to store opposed roll results for later use",
|
||||
default: { roll1: null, roll2: null },
|
||||
scope: "world",
|
||||
type: Object,
|
||||
config: false
|
||||
});
|
||||
}
|
||||
|
||||
static async loadCompendiumData(compendium) {
|
||||
@@ -180,6 +188,53 @@ export default class CthulhuEternalUtils {
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static removeChatMessageId(messageId) {
|
||||
if (messageId) {
|
||||
game.messages.get(messageId)?.delete();
|
||||
}
|
||||
}
|
||||
|
||||
static findChatMessageId(current) {
|
||||
return HawkmoonUtility.getChatMessageId(HawkmoonUtility.findChatMessage(current));
|
||||
}
|
||||
|
||||
static getChatMessageId(node) {
|
||||
return node?.attributes.getNamedItem('data-message-id')?.value;
|
||||
}
|
||||
|
||||
static findChatMessage(current) {
|
||||
return HawkmoonUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'))
|
||||
}
|
||||
|
||||
static findNodeMatching(current, predicate) {
|
||||
if (current) {
|
||||
if (predicate(current)) {
|
||||
return current;
|
||||
}
|
||||
return HawkmoonUtility.findNodeMatching(current.parentElement, predicate);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWeaponSkill(actor, weapon, era) {
|
||||
let skill
|
||||
if (weapon.system.hasDirectSkill) {
|
||||
let skillName = weapon.name
|
||||
skill = { type: "skill", name: skillName, system: { base: 0, bonus: weapon.system.directSkillValue, skillTotal: weapon.system.directSkillValue } }
|
||||
} else {
|
||||
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][weapon.system.weaponType])
|
||||
skill = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
|
||||
if (!skill) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill"))
|
||||
return
|
||||
}
|
||||
}
|
||||
return skill
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async applySANType(rollMessage, event) {
|
||||
let rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData")
|
||||
if (!rollData) {
|
||||
@@ -196,11 +251,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
|
||||
@@ -234,7 +284,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"
|
||||
@@ -253,16 +303,183 @@ export default class CthulhuEternalUtils {
|
||||
})
|
||||
}
|
||||
|
||||
static async damageRoll(rollMessage) {
|
||||
static async opposedRollManagement(rollMessage, event) {
|
||||
let rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData")
|
||||
if (!rollData) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noRollDataFound"))
|
||||
return
|
||||
}
|
||||
|
||||
// Get the store
|
||||
let store = game.settings.get("fvtt-cthulhu-eternal", "roll-opposed-store")
|
||||
if (!store.roll1) {
|
||||
store.roll1 = {
|
||||
rollData: rollData,
|
||||
messageId: rollMessage.id
|
||||
}
|
||||
await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store)
|
||||
ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollFirstStored"))
|
||||
}
|
||||
else if (!store.roll2) {
|
||||
store.roll2 = {
|
||||
rollData: rollData,
|
||||
messageId: rollMessage.id
|
||||
}
|
||||
await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store)
|
||||
ui.notifications.info(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollSecondStored"))
|
||||
// Now perform the opposed roll resolution
|
||||
await this.resolveOpposedRolls(store.roll1, store.roll2)
|
||||
// Clear the store
|
||||
store.roll1 = null
|
||||
store.roll2 = null
|
||||
await game.settings.set("fvtt-cthulhu-eternal", "roll-opposed-store", store)
|
||||
}
|
||||
else {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.opposedRollStoreFull"))
|
||||
}
|
||||
}
|
||||
|
||||
static async resolveOpposedRolls(roll1, roll2) {
|
||||
// Get actors
|
||||
let actor1 = game.actors.get(roll1.rollData.actorId)
|
||||
let actor2 = game.actors.get(roll2.rollData.actorId)
|
||||
if (!actor1 || !actor2) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.noActorFound"))
|
||||
return
|
||||
}
|
||||
// Determine winner
|
||||
let winner = null
|
||||
let loser = null
|
||||
// If there critical success/failure, apply them first (remark : this d100 results)
|
||||
roll1.rollData.rollCompare = roll1.rollData.rollResult
|
||||
roll2.rollData.rollCompare = roll2.rollData.rollResult
|
||||
if (roll1.rollData.resultType === "successCritical") {
|
||||
roll1.rollData.rollCompare = -roll1.rollData.rollResult
|
||||
}
|
||||
if (roll2.rollData.resultType === "failureCritical") {
|
||||
roll2.rollData.rollCompare = 100 + roll2.rollData.rollResult
|
||||
}
|
||||
if (roll2.rollData.resultType === "successCritical") {
|
||||
roll2.rollData.rollCompare = -roll2.rollData.rollResult
|
||||
}
|
||||
if (roll1.rollData.resultType === "failureCritical") {
|
||||
roll1.rollData.rollCompare = roll1.rollData.rollResult * 2
|
||||
}
|
||||
if (roll1.rollData.isSuccess && roll2.rollData.isFailure) {
|
||||
winner = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId }
|
||||
loser = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId }
|
||||
}
|
||||
else if (roll2.rollData.isSuccess && roll1.rollData.isFailure) {
|
||||
winner = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId }
|
||||
loser = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId }
|
||||
}
|
||||
else if (roll1.rollData.rollCompare < roll2.rollData.rollCompare) {
|
||||
winner = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId }
|
||||
loser = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId }
|
||||
}
|
||||
else {
|
||||
winner = { actor: actor2, rollData: roll2.rollData, messageId: roll2.messageId }
|
||||
loser = { actor: actor1, rollData: roll1.rollData, messageId: roll1.messageId }
|
||||
}
|
||||
|
||||
console.log("Opposed roll result", winner, loser)
|
||||
|
||||
// Check if winner was attacking with a weapon that can apply damage
|
||||
let canApplyDamage = winner && winner.rollData?.weapon && winner.rollData.weapon.system
|
||||
|
||||
// Prepare data for the template
|
||||
let msgData = {
|
||||
winner: {
|
||||
actor: {
|
||||
name: winner.actor.name,
|
||||
img: winner.actor.img
|
||||
},
|
||||
rollData: {
|
||||
rollResult: winner.rollData.rollResult || winner.rollData.total,
|
||||
isCritical: winner.rollData.isCritical,
|
||||
weapon: winner.rollData.weapon
|
||||
}
|
||||
},
|
||||
loser: {
|
||||
actor: {
|
||||
name: loser.actor.name,
|
||||
img: loser.actor.img
|
||||
},
|
||||
rollData: {
|
||||
rollResult: loser.rollData.rollResult || loser.rollData.total,
|
||||
isCritical: loser.rollData.isCritical
|
||||
}
|
||||
},
|
||||
canApplyDamage: canApplyDamage
|
||||
}
|
||||
|
||||
// Render the template
|
||||
let content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-cthulhu-eternal/templates/chat-opposed-result.hbs",
|
||||
msgData
|
||||
)
|
||||
|
||||
// Display the result in chat
|
||||
let chatMsg = await ChatMessage.create({
|
||||
speaker: ChatMessage.getSpeaker({ actor: winner.actor.id }),
|
||||
content: content
|
||||
})
|
||||
|
||||
// Store the winner's roll data for damage roll if applicable
|
||||
if (canApplyDamage) {
|
||||
await chatMsg.setFlag("fvtt-cthulhu-eternal", "rollData", winner.rollData)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (!rollData) {
|
||||
rollData = rollMessage.getFlag("fvtt-cthulhu-eternal", "rollData")
|
||||
}
|
||||
if (!rollData) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noRollDataFound"))
|
||||
return
|
||||
}
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
if (!actor) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound"))
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -310,8 +527,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)
|
||||
})
|
||||
}
|
||||
@@ -331,6 +548,10 @@ export default class CthulhuEternalUtils {
|
||||
roll.toMessage()
|
||||
|
||||
actor.system.modifyWP(-dialogContext.wpCost)
|
||||
|
||||
// Delete the initial roll message
|
||||
await rollMessage.delete()
|
||||
|
||||
}
|
||||
|
||||
static setupCSSRootVariables() {
|
||||
@@ -349,4 +570,38 @@ 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
|
||||
}
|
||||
console.log("Applying wounds", woundData)
|
||||
// Remove the chat message
|
||||
this.removeChatMessageId(message.id)
|
||||
|
||||
// Get the targetted actorId from the button's data attribute
|
||||
let targetCombatantId = event.currentTarget.dataset.combatantId
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
0
packs-system/rituals/000275.log
Normal file
0
packs-system/rituals/000275.log
Normal file
@@ -1 +1 @@
|
||||
MANIFEST-000159
|
||||
MANIFEST-000273
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2025/06/26-23:46:34.515678 7f9f367fc6c0 Recovering log #157
|
||||
2025/06/26-23:46:34.534041 7f9f367fc6c0 Delete type=3 #155
|
||||
2025/06/26-23:46:34.534179 7f9f367fc6c0 Delete type=0 #157
|
||||
2025/06/26-23:49:17.164364 7f9c97bff6c0 Level-0 table #162: started
|
||||
2025/06/26-23:49:17.164425 7f9c97bff6c0 Level-0 table #162: 0 bytes OK
|
||||
2025/06/26-23:49:17.171116 7f9c97bff6c0 Delete type=0 #160
|
||||
2025/06/26-23:49:17.171392 7f9c97bff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)
|
||||
2025/11/21-23:23:35.521610 7f21eeffd6c0 Recovering log #271
|
||||
2025/11/21-23:23:35.612353 7f21eeffd6c0 Delete type=3 #269
|
||||
2025/11/21-23:23:35.612430 7f21eeffd6c0 Delete type=0 #271
|
||||
2025/11/21-23:35:34.796894 7f21ed7fa6c0 Level-0 table #276: started
|
||||
2025/11/21-23:35:34.796917 7f21ed7fa6c0 Level-0 table #276: 0 bytes OK
|
||||
2025/11/21-23:35:34.806397 7f21ed7fa6c0 Delete type=0 #274
|
||||
2025/11/21-23:35:34.806600 7f21ed7fa6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2025/06/26-23:36:47.634558 7f9f367fc6c0 Recovering log #153
|
||||
2025/06/26-23:36:47.653567 7f9f367fc6c0 Delete type=3 #151
|
||||
2025/06/26-23:36:47.653707 7f9f367fc6c0 Delete type=0 #153
|
||||
2025/06/26-23:43:03.865022 7f9c97bff6c0 Level-0 table #158: started
|
||||
2025/06/26-23:43:03.865112 7f9c97bff6c0 Level-0 table #158: 0 bytes OK
|
||||
2025/06/26-23:43:03.875155 7f9c97bff6c0 Delete type=0 #156
|
||||
2025/06/26-23:43:03.911824 7f9c97bff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)
|
||||
2025/11/12-23:48:30.686758 7f4781ffb6c0 Recovering log #267
|
||||
2025/11/12-23:48:30.697449 7f4781ffb6c0 Delete type=3 #265
|
||||
2025/11/12-23:48:30.697507 7f4781ffb6c0 Delete type=0 #267
|
||||
2025/11/13-13:58:42.410831 7f4780bff6c0 Level-0 table #272: started
|
||||
2025/11/13-13:58:42.410865 7f4780bff6c0 Level-0 table #272: 0 bytes OK
|
||||
2025/11/13-13:58:42.417362 7f4780bff6c0 Delete type=0 #270
|
||||
2025/11/13-13:58:42.434870 7f4780bff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs-system/rituals/MANIFEST-000273
Normal file
BIN
packs-system/rituals/MANIFEST-000273
Normal file
Binary file not shown.
0
packs-system/rituals/lost/000223.log
Normal file
0
packs-system/rituals/lost/000223.log
Normal file
0
packs-system/rituals/lost/000240.log
Normal file
0
packs-system/rituals/lost/000240.log
Normal file
0
packs-system/skills/000444.log
Normal file
0
packs-system/skills/000444.log
Normal file
@@ -1 +1 @@
|
||||
MANIFEST-000328
|
||||
MANIFEST-000442
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2025/06/26-23:46:34.489168 7f9f357fa6c0 Recovering log #326
|
||||
2025/06/26-23:46:34.505514 7f9f357fa6c0 Delete type=3 #324
|
||||
2025/06/26-23:46:34.505645 7f9f357fa6c0 Delete type=0 #326
|
||||
2025/06/26-23:49:17.142993 7f9c97bff6c0 Level-0 table #331: started
|
||||
2025/06/26-23:49:17.143080 7f9c97bff6c0 Level-0 table #331: 0 bytes OK
|
||||
2025/06/26-23:49:17.150443 7f9c97bff6c0 Delete type=0 #329
|
||||
2025/06/26-23:49:17.171328 7f9c97bff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)
|
||||
2025/11/21-23:23:35.280848 7f21edffb6c0 Recovering log #440
|
||||
2025/11/21-23:23:35.368467 7f21edffb6c0 Delete type=3 #438
|
||||
2025/11/21-23:23:35.368552 7f21edffb6c0 Delete type=0 #440
|
||||
2025/11/21-23:35:34.777225 7f21ed7fa6c0 Level-0 table #445: started
|
||||
2025/11/21-23:35:34.777275 7f21ed7fa6c0 Level-0 table #445: 0 bytes OK
|
||||
2025/11/21-23:35:34.786357 7f21ed7fa6c0 Delete type=0 #443
|
||||
2025/11/21-23:35:34.806576 7f21ed7fa6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
2025/06/26-23:36:47.604835 7f9f36ffd6c0 Recovering log #322
|
||||
2025/06/26-23:36:47.622645 7f9f36ffd6c0 Delete type=3 #320
|
||||
2025/06/26-23:36:47.622799 7f9f36ffd6c0 Delete type=0 #322
|
||||
2025/06/26-23:43:03.901610 7f9c97bff6c0 Level-0 table #327: started
|
||||
2025/06/26-23:43:03.901678 7f9c97bff6c0 Level-0 table #327: 0 bytes OK
|
||||
2025/06/26-23:43:03.911538 7f9c97bff6c0 Delete type=0 #325
|
||||
2025/06/26-23:43:03.911919 7f9c97bff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)
|
||||
2025/11/12-23:48:30.659183 7f47817fa6c0 Recovering log #436
|
||||
2025/11/12-23:48:30.670042 7f47817fa6c0 Delete type=3 #434
|
||||
2025/11/12-23:48:30.670124 7f47817fa6c0 Delete type=0 #436
|
||||
2025/11/13-13:58:42.417482 7f4780bff6c0 Level-0 table #441: started
|
||||
2025/11/13-13:58:42.417509 7f4780bff6c0 Level-0 table #441: 0 bytes OK
|
||||
2025/11/13-13:58:42.423396 7f4780bff6c0 Delete type=0 #439
|
||||
2025/11/13-13:58:42.434882 7f4780bff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs-system/skills/MANIFEST-000442
Normal file
BIN
packs-system/skills/MANIFEST-000442
Normal file
Binary file not shown.
0
packs-system/skills/lost/000392.log
Normal file
0
packs-system/skills/lost/000392.log
Normal file
0
packs-system/skills/lost/000409.log
Normal file
0
packs-system/skills/lost/000409.log
Normal file
BIN
packs-system/weapons/000063.ldb
Normal file
BIN
packs-system/weapons/000063.ldb
Normal file
Binary file not shown.
0
packs-system/weapons/000090.log
Normal file
0
packs-system/weapons/000090.log
Normal file
1
packs-system/weapons/CURRENT
Normal file
1
packs-system/weapons/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000088
|
||||
0
packs-system/weapons/LOCK
Normal file
0
packs-system/weapons/LOCK
Normal file
7
packs-system/weapons/LOG
Normal file
7
packs-system/weapons/LOG
Normal file
@@ -0,0 +1,7 @@
|
||||
2025/11/21-23:23:35.396467 7f21ef7fe6c0 Recovering log #86
|
||||
2025/11/21-23:23:35.502570 7f21ef7fe6c0 Delete type=3 #84
|
||||
2025/11/21-23:23:35.502631 7f21ef7fe6c0 Delete type=0 #86
|
||||
2025/11/21-23:35:34.786516 7f21ed7fa6c0 Level-0 table #91: started
|
||||
2025/11/21-23:35:34.786543 7f21ed7fa6c0 Level-0 table #91: 0 bytes OK
|
||||
2025/11/21-23:35:34.796797 7f21ed7fa6c0 Delete type=0 #89
|
||||
2025/11/21-23:35:34.806589 7f21ed7fa6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)
|
||||
7
packs-system/weapons/LOG.old
Normal file
7
packs-system/weapons/LOG.old
Normal file
@@ -0,0 +1,7 @@
|
||||
2025/11/12-23:48:30.674156 7f4781ffb6c0 Recovering log #82
|
||||
2025/11/12-23:48:30.683495 7f4781ffb6c0 Delete type=3 #80
|
||||
2025/11/12-23:48:30.683546 7f4781ffb6c0 Delete type=0 #82
|
||||
2025/11/13-13:58:42.404378 7f4780bff6c0 Level-0 table #87: started
|
||||
2025/11/13-13:58:42.404437 7f4780bff6c0 Level-0 table #87: 0 bytes OK
|
||||
2025/11/13-13:58:42.410719 7f4780bff6c0 Delete type=0 #85
|
||||
2025/11/13-13:58:42.434856 7f4780bff6c0 Manual compaction at level-0 from '!folders!0DI3T2jve3nsmsfZ' @ 72057594037927935 : 1 .. '!items!zyxA9DhO36t5OBDv' @ 0 : 0; will stop at (end)
|
||||
BIN
packs-system/weapons/MANIFEST-000088
Normal file
BIN
packs-system/weapons/MANIFEST-000088
Normal file
Binary file not shown.
0
packs-system/weapons/lost/000038.log
Normal file
0
packs-system/weapons/lost/000038.log
Normal file
0
packs-system/weapons/lost/000055.log
Normal file
0
packs-system/weapons/lost/000055.log
Normal file
@@ -8,6 +8,28 @@
|
||||
background-color: var(--color-light-1);
|
||||
}
|
||||
|
||||
.creature-hp {
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
.form-fields {
|
||||
input {
|
||||
flex: none;
|
||||
min-width: 4rem;
|
||||
max-width: 4rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
.damage-bonus {
|
||||
font-size: calc(var(--font-size-standard) * 0.8);
|
||||
}
|
||||
.hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.creature-main {
|
||||
background-color: var(--color-light-1);
|
||||
display: flex;
|
||||
@@ -34,25 +56,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.creature-hp {
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
input {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.damage-bonus {
|
||||
font-size: calc(var(--font-size-standard) * 0.8);
|
||||
}
|
||||
.hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.creature-dv,
|
||||
.creature-dmax {
|
||||
.form-fields {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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: 6rem;
|
||||
max-width: 6rem;
|
||||
}
|
||||
}
|
||||
.san-loose-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -111,8 +128,8 @@ i.fvtt-cthulhu-eternal {
|
||||
padding: 2px 2px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
min-width: 3.0rem;
|
||||
max-width: 3.0rem;
|
||||
min-width: 3rem;
|
||||
max-width: 3rem;
|
||||
}
|
||||
}
|
||||
.result-non-lethal {
|
||||
@@ -124,5 +141,28 @@ i.fvtt-cthulhu-eternal {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.02);
|
||||
}
|
||||
.combatants-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 4px;
|
||||
margin: 8px 0;
|
||||
button.apply-wounds-btn {
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 0.7);
|
||||
border: 1px solid #4b4a44;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
background-color: #f0f0e0;
|
||||
color: #1c1c1c;
|
||||
&:hover {
|
||||
background-color: #d5d5c5;
|
||||
border-color: #2d2d2a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.05);
|
||||
color: var(--color-dark-1);
|
||||
background-image: var(--background-image-base);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background: var(--color-light-1);
|
||||
--input-height: 1.4rem;
|
||||
|
||||
.sheet-tabs {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
align-items: center;
|
||||
input {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
width: 4rem;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.hp-separator {
|
||||
@@ -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;
|
||||
|
||||
246
styles/roll.less
246
styles/roll.less
@@ -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,22 +95,7 @@
|
||||
li {
|
||||
margin: 0 10px;
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
}
|
||||
.nudge-roll {
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
}
|
||||
.healing-roll {
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
}
|
||||
.roll-damage {
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
margin-left: 2rem;
|
||||
display: none;
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
}
|
||||
.result-success {
|
||||
color: var(--color-success);
|
||||
@@ -145,4 +134,227 @@
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
text-shadow: 0 0 10px var(--color-shadow-primary);
|
||||
}
|
||||
|
||||
.chat-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
border-top: 1px solid var(--color-border-light-primary);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0 0 5px 5px;
|
||||
justify-content: center;
|
||||
|
||||
.chat-action-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background: var(--color-dark-6);
|
||||
color: var(--color-light-1);
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-dark-5);
|
||||
border-color: var(--color-border-dark);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 1rem !important;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nudge-roll,
|
||||
.damage-roll,
|
||||
.healing-roll,
|
||||
.opposed-roll {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.opposed-roll-result {
|
||||
padding: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 5px;
|
||||
font-family: var(--font-primary);
|
||||
|
||||
.opposed-header {
|
||||
text-align: center;
|
||||
margin-bottom: 0.3rem;
|
||||
padding-bottom: 0.2rem;
|
||||
border-bottom: 1px solid var(--color-border-light-primary);
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
color: var(--color-dark-1);
|
||||
}
|
||||
}
|
||||
|
||||
.opposed-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.opposed-winner,
|
||||
.opposed-loser {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem 0.4rem;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.opposed-winner {
|
||||
background: rgba(34, 139, 34, 0.1);
|
||||
border: 2px solid var(--color-success);
|
||||
}
|
||||
|
||||
.opposed-loser {
|
||||
background: rgba(220, 20, 60, 0.1);
|
||||
border: 2px solid var(--color-failure);
|
||||
}
|
||||
|
||||
.character-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
}
|
||||
|
||||
.character-name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
|
||||
strong {
|
||||
font-size: calc(var(--font-size-standard) * 0.75);
|
||||
text-transform: uppercase;
|
||||
color: var(--color-dark-2);
|
||||
}
|
||||
|
||||
.winner-name {
|
||||
font-size: calc(var(--font-size-standard) * 0.95);
|
||||
font-weight: bold;
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.loser-name {
|
||||
font-size: calc(var(--font-size-standard) * 0.95);
|
||||
font-weight: bold;
|
||||
color: var(--color-failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.roll-result {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
|
||||
.roll-value {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-weight: bold;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.critical-badge {
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
font-size: calc(var(--font-size-standard) * 0.7);
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
background: var(--color-critical-success);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.winner-result .roll-value {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.loser-result .roll-value {
|
||||
color: var(--color-failure);
|
||||
}
|
||||
|
||||
.versus-separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0;
|
||||
font-size: calc(var(--font-size-standard) * 0.85);
|
||||
font-weight: bold;
|
||||
color: var(--color-dark-2);
|
||||
|
||||
i {
|
||||
font-size: calc(var(--font-size-standard) * 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.chat-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.3rem;
|
||||
border-top: 1px solid var(--color-border-light-primary);
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 0 0 5px 5px;
|
||||
|
||||
.chat-action-button {
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background: var(--color-dark-6);
|
||||
color: var(--color-light-1);
|
||||
border: 1px solid var(--color-border-light-primary);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-dark-5);
|
||||
border-color: var(--color-border-dark);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 1rem !important;
|
||||
line-height: 1;
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
14
system.json
14
system.json
@@ -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",
|
||||
@@ -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",
|
||||
|
||||
@@ -2,27 +2,39 @@
|
||||
<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}}
|
||||
<li>{{weapon.system.selectiveFireChoiceLabel}}</li>
|
||||
{{/if}}
|
||||
{{#if weapon.system.killRadius}}
|
||||
{{#if (gt weapon.system.killRadius 0)}}
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}</li>
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt weapon.system.armorPiercing 0)}}
|
||||
<li>{{localize "CTHULHUETERNAL.Label.armorPiercing"}} : {{weapon.system.armorPiercing}}</li>
|
||||
{{/if}}
|
||||
|
||||
{{#if ammoUsed}}
|
||||
<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>
|
||||
|
||||
@@ -6,119 +6,222 @@
|
||||
</div>
|
||||
<div class="intro-right">
|
||||
<ul>
|
||||
<li><strong>{{actingCharName}}</strong></li>
|
||||
{{#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}} WP spent</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"}} : {{modifier}}%</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"}}
|
||||
{{#if (eq rollType "weapon")}}
|
||||
{{#if (eq weapon.system.weaponType "rangedfirearm")}}
|
||||
<a class="damage-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-gun"></i></a>
|
||||
{{else}}
|
||||
<a class="damage-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-sword"></i></a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (eq rollType "skill") }}
|
||||
{{#if rollItem.system.isHealing}}
|
||||
<a class="healing-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollHealing"}}"><i class="fa-solid fa-heart"></i></a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<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}}
|
||||
{{#if (eq weapon.system.weaponType "rangedfirearm")}}
|
||||
<a class="damage-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-gun"></i></a>
|
||||
{{else}}
|
||||
<a class="damage-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollDamage"}}"><i class="fa-solid fa-sword"></i></a>
|
||||
{{/if}}
|
||||
{{#if (eq rollType "skill") }}
|
||||
{{#if rollItem.system.isHealing}}
|
||||
<a class="healing-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollHealing"}}"><i class="fa-solid fa-heart"></i></a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
<li class="result-success">
|
||||
{{localize "CTHULHUETERNAL.Label.success"}}
|
||||
</li>
|
||||
{{/if}}
|
||||
|
||||
{{/if}}
|
||||
|
||||
{{#if isFailure}}
|
||||
{{#if isCritical}}
|
||||
<li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}
|
||||
{{#if (eq rollType "skill") }}
|
||||
{{#if rollItem.system.isHealing}}
|
||||
<a class="healing-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollHealing"}}"><i class="fa-solid fa-heart"></i></a>
|
||||
{{#if isCritical}}
|
||||
<li class="result-critical-failure">{{localize
|
||||
"CTHULHUETERNAL.Label.criticalFailure"
|
||||
}}
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="result-failure">
|
||||
{{localize "CTHULHUETERNAL.Label.failure"}}
|
||||
</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>
|
||||
{{else}}
|
||||
<li class="orange-warning">{{localize
|
||||
"CTHULHUETERNAL.Label.noTarget"
|
||||
}}</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{else}}
|
||||
<li class="result-failure">
|
||||
{{localize "CTHULHUETERNAL.Label.failure"}}
|
||||
{{#if isNudge}}
|
||||
<a class="nudge-roll" data-tooltip="{{localize "CTHULHUETERNAL.Label.rollNudge"}}"><i class="fa-solid fa-circle-sort-down"></i></a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/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}}
|
||||
|
||||
{{! Zone d'actions regroupées }}
|
||||
<div class="chat-actions">
|
||||
{{#if isSuccess}}
|
||||
{{#if isNudge}}
|
||||
<a
|
||||
class="nudge-roll chat-action-button"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollNudge'}}"
|
||||
>
|
||||
<i class="fa-solid fa-circle-sort-down"></i>
|
||||
</a>
|
||||
{{/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)}}
|
||||
<a
|
||||
class="damage-roll chat-action-button"
|
||||
data-item-id="{{weapon.id}}"
|
||||
data-action="roll"
|
||||
data-roll-type="damage"
|
||||
data-roll-value="{{damageDistance.damage}}"
|
||||
data-tooltip="{{localize
|
||||
'CTHULHUETERNAL.Label.rollDamage'
|
||||
}} ({{damageDistance.distance}}m : {{damageDistance.damage}})"
|
||||
>
|
||||
<i class="fa-solid fa-gun"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<a
|
||||
class="damage-roll chat-action-button"
|
||||
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 chat-action-button"
|
||||
data-roll-value="{{weapon.system.damage}}"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollDamage'}}"
|
||||
>
|
||||
<i class="fa-solid fa-sword"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq rollType "skill")}}
|
||||
{{#if rollItem.system.isHealing}}
|
||||
<a
|
||||
class="healing-roll chat-action-button"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollHealing'}}"
|
||||
>
|
||||
<i class="fa-solid fa-heart"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isFailure}}
|
||||
{{#if isNudge}}
|
||||
<a
|
||||
class="nudge-roll chat-action-button"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollNudge'}}"
|
||||
>
|
||||
<i class="fa-solid fa-circle-sort-down"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<a
|
||||
class="opposed-roll chat-action-button"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.opposedRoll'}}"
|
||||
>
|
||||
<i class="fa-duotone fa-light fa-arrows-to-line"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
64
templates/chat-opposed-result.hbs
Normal file
64
templates/chat-opposed-result.hbs
Normal file
@@ -0,0 +1,64 @@
|
||||
{{! Template for opposed roll result }}
|
||||
<div class="cthulhu-eternal-roll opposed-roll-result">
|
||||
<div class="opposed-header">
|
||||
<h3>{{localize "CTHULHUETERNAL.Label.opposedRollResult"}}</h3>
|
||||
</div>
|
||||
|
||||
<div class="opposed-content">
|
||||
<div class="opposed-winner">
|
||||
<div class="character-info">
|
||||
<img src="{{winner.actor.img}}" alt="{{winner.actor.name}}" />
|
||||
<div class="character-name">
|
||||
<strong>{{localize "CTHULHUETERNAL.Label.opposedRollWinner"}}</strong>
|
||||
<span class="winner-name">{{winner.actor.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="roll-result winner-result">
|
||||
<span class="roll-value">{{winner.rollData.rollResult}}</span>
|
||||
{{#if winner.rollData.isCritical}}
|
||||
<span class="critical-badge">{{localize
|
||||
"CTHULHUETERNAL.Label.critical"
|
||||
}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="versus-separator">
|
||||
<i class="fas fa-swords"></i>
|
||||
<span>{{localize "CTHULHUETERNAL.Label.defeats"}}</span>
|
||||
</div>
|
||||
|
||||
<div class="opposed-loser">
|
||||
<div class="character-info">
|
||||
<img src="{{loser.actor.img}}" alt="{{loser.actor.name}}" />
|
||||
<div class="character-name">
|
||||
<span class="loser-name">{{loser.actor.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="roll-result loser-result">
|
||||
<span class="roll-value">{{loser.rollData.rollResult}}</span>
|
||||
{{#if loser.rollData.isCritical}}
|
||||
<span class="critical-badge">{{localize
|
||||
"CTHULHUETERNAL.Label.critical"
|
||||
}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if canApplyDamage}}
|
||||
<div class="chat-actions">
|
||||
<a
|
||||
class="damage-roll chat-action-button"
|
||||
data-roll-value="{{winner.rollData.weapon.system.damage}}"
|
||||
data-tooltip="{{localize 'CTHULHUETERNAL.Label.rollDamage'}}"
|
||||
>
|
||||
{{#if (eq winner.rollData.weapon.system.weaponType "rangedfirearm")}}
|
||||
<i class="fa-solid fa-gun"></i>
|
||||
{{else}}
|
||||
<i class="fa-solid fa-sword"></i>
|
||||
{{/if}}
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -1,18 +1,59 @@
|
||||
<div class="{{cssClass}}">
|
||||
<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><strong>{{weapon.name}}
|
||||
:
|
||||
{{localize "CTHULHUETERNAL.Label.damageRoll"}}</strong></li>
|
||||
<li>{{localize "CTHULHUETERNAL.Label.result"}}
|
||||
:{{rollResult}}
|
||||
({{formula}})</li>
|
||||
|
||||
{{#if weapon.system.killRadius}}
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}</li>
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}</li>
|
||||
{{#if (gt weapon.system.killRadius 0)}}
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadius"}}
|
||||
:
|
||||
{{weapon.system.killRadius}}
|
||||
{{weapon.system.rangeUnit}}</li>
|
||||
<li>{{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}</li>
|
||||
{{/if}}
|
||||
|
||||
{{#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>
|
||||
<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">
|
||||
<div>{{localize "CTHULHUETERNAL.Label.applyWounds"}}</div>
|
||||
<div class="combatants-grid">
|
||||
{{#each combatants}}
|
||||
<button
|
||||
class="apply-wounds-btn"
|
||||
data-combatant-id="{{this.id}}"
|
||||
title="{{this.name}}"
|
||||
>
|
||||
{{this.name}}
|
||||
</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="result-non-lethal">{{localize
|
||||
"CTHULHUETERNAL.Label.damageMessage"
|
||||
}}:
|
||||
<strong>{{rollResult}}</strong>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
8
templates/chat-san-loss-none.hbs
Normal file
8
templates/chat-san-loss-none.hbs
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="{{cssClass}}">
|
||||
<div class="chat-san-request">
|
||||
<ul>
|
||||
<li><strong>{{localize "CTHULHUETERNAL.Label.SANLossNone"}}</strong></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
8
templates/chat-san-loss-unnatural.hbs
Normal file
8
templates/chat-san-loss-unnatural.hbs
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="{{cssClass}}">
|
||||
<div class="chat-san-request">
|
||||
<ul>
|
||||
<li><strong>{{localize "CTHULHUETERNAL.Label.SANLossUnnatural"}}</strong></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,7 +1,11 @@
|
||||
<div class="{{cssClass}}">
|
||||
<div class="chat-san-request">
|
||||
<ul>
|
||||
<li><strong>{{localize "CTHULHUETERNAL.Label.SANTest"}}</strong></li>
|
||||
{{#if rollData.isSuccess}}
|
||||
<li><strong>{{localize "CTHULHUETERNAL.Label.SANTestSuccess"}}</strong></li>
|
||||
{{else}}
|
||||
<li><strong>{{localize "CTHULHUETERNAL.Label.SANTestFailure"}}</strong></li>
|
||||
{{/if}}
|
||||
|
||||
<li class="san-loose-buttons">
|
||||
<button class="san-loose" data-san-value="0">0</button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
data-name="checks" {{#if check}} checked {{/if}} {{#if (gte @index @root.system.resources.nbValidChecks)}} disabled {{/if}}>
|
||||
{{/each}}
|
||||
</div>
|
||||
<button class="resource-roll rollable" data-roll-type="resource"><img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />Resource roll</button>
|
||||
<button class="resource-roll rollable" data-roll-type="resource"><img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />{{localize "CTHULHUETERNAL.Label.titleResource"}}</button>
|
||||
{{formField systemFields.resources.fields.hand value=system.resources.hand name="system.resources.hand" localize=true disabled=true}}
|
||||
{{formField systemFields.resources.fields.stowed value=system.resources.stowed name="system.resources.stowed" localize=true disabled=true}}
|
||||
{{formField systemFields.resources.fields.storage value=system.resources.storage name="system.resources.storage" localize=true disabled=true}}
|
||||
|
||||
@@ -16,11 +16,64 @@
|
||||
{{item.name}}
|
||||
</div>
|
||||
|
||||
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
|
||||
<a class="damage rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage"
|
||||
data-roll-value="{{item.system.damage}}">
|
||||
{{localize "CTHULHUETERNAL.Label.damageShort"}} :
|
||||
{{item.system.damage}}</a>
|
||||
<div class="damage" data-tooltip="{{localize 'CTHULHUETERNAL.Tooltip.rollDamage'}}">
|
||||
{{#if (eq system.lethality 0)}}
|
||||
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
|
||||
|
||||
{{#if item.system.hasDamageDistance}}
|
||||
{{#each item.system.damageDistance as |damageDistance|}}
|
||||
{{#if (gt damageDistance.distance 0)}}
|
||||
<a class="rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage"
|
||||
data-roll-value="{{damageDistance.damage}}" >
|
||||
<span class="damage-distance">{{damageDistance.distance}}:{{damageDistance.damage}} </span>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<a class="rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage"
|
||||
data-roll-value="{{item.system.damage}}" >
|
||||
{{item.system.damage}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
N/A
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if (gt system.baseRange 0)}}
|
||||
<span class="range" data-tooltip="CTHULHUETERNAL.Label.baseRange">{{item.system.baseRange}} {{item.system.rangeUnit}}</span>
|
||||
{{else}}
|
||||
<span class="range">{{localize "CTHULHUETERNAL.Label.melee"}}</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt system.lethality 0)}}
|
||||
<a class="lethality rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage"
|
||||
data-tooltip="CTHULHUETERNAL.Label.Lethality" >
|
||||
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
|
||||
{{item.system.lethality}}%
|
||||
</a>
|
||||
{{else}}
|
||||
<span class="lethality" data-tooltip="CTHULHUETERNAL.Label.Lethality">-</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt system.killRadius 0)}}
|
||||
<span class="lethality" data-tooltip="CTHULHUETERNAL.Label.killRadius" >{{item.system.killRadius}}</span>
|
||||
{{else}}
|
||||
<span class="lethality" data-tooltip="CTHULHUETERNAL.Label.killRadius">-</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt system.armorPiercing 0)}}
|
||||
<span class="lethality" data-tooltip="CTHULHUETERNAL.Label.armorPiercing" >{{item.system.armorPiercing}}</span>
|
||||
{{else}}
|
||||
<span class="lethality" data-tooltip="CTHULHUETERNAL.Label.armorPiercing">-</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq system.weaponType "rangedfirearm")}}
|
||||
<span class="ammo" data-tooltip="CTHULHUETERNAL.Label.Ammo" >{{item.system.ammo.value}}/{{item.system.ammo.max}}</span>
|
||||
{{else}}
|
||||
<span class="ammo" data-tooltip="CTHULHUETERNAL.Label.Ammo">N/A</span>
|
||||
{{/if}}
|
||||
|
||||
<div class="controls">
|
||||
<a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
||||
|
||||
@@ -1,64 +1,214 @@
|
||||
<div class="fvtt-cthulhu-eternal-roll-dialog">
|
||||
<fieldSet>
|
||||
{{#if (eq rollType "skill")}}
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.skill"}}</legend>
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.skill"}}</legend>
|
||||
{{/if}}
|
||||
{{#if (eq rollType "char")}}
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.characteristic"}}</legend>
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.characteristic"}}</legend>
|
||||
{{/if}}
|
||||
|
||||
{{#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">{{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} <input type="checkbox" data-action="selectStorage" {{checked rollItem.enableStorage}}></div>
|
||||
<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">
|
||||
{{localize "CTHULHUETERNAL.Label.Storage"}}
|
||||
:
|
||||
{{rollItem.storage}}
|
||||
<input
|
||||
type="checkbox"
|
||||
data-action="selectStorage"
|
||||
{{checked rollItem.enableStorage}}
|
||||
/>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="dialog-skill">{{rollItem.name}} : {{initialScore}}%</div>
|
||||
<div class="dialog-skill">{{rollItem.name}} : {{initialScore}}%</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if weapon}}
|
||||
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Weapon"}} : {{weapon.name}}</div>
|
||||
{{#if weapon.system.hasSelectiveFire}}
|
||||
<div class="dialog-skill">Selective Fire :
|
||||
<select name="selectiveFireChoice" class="roll-skill-modifier">
|
||||
{{selectOptions choiceSelectiveFire localize=true selected=selectiveFireChoice nameAttr="id" labelAttr="label"}}
|
||||
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Weapon"}}
|
||||
:
|
||||
{{weapon.name}}</div>
|
||||
|
||||
{{#if targetName}}
|
||||
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Target"}}
|
||||
:
|
||||
{{targetName}}</div>
|
||||
{{/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.aimingLastRound"}}
|
||||
<input
|
||||
type="checkbox"
|
||||
class="aimingLastRound"
|
||||
name="aimingLastRound"
|
||||
/>
|
||||
</div>
|
||||
{{#if weapon.system.hasSight}}
|
||||
<div class="dialog-skill">
|
||||
{{localize "CTHULHUETERNAL.Label.aimingWithSight"}}
|
||||
<input
|
||||
type="checkbox"
|
||||
class="aimingWithSight"
|
||||
name="aimingWithSight"
|
||||
/>
|
||||
</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>
|
||||
<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}}
|
||||
<div class="dialog-skill orange-warning">{{localize "CTHULHUETERNAL.Label.Exhausted"}} : -20%</div>
|
||||
<div class="dialog-skill orange-warning">{{localize
|
||||
"CTHULHUETERNAL.Label.Exhausted"
|
||||
}}
|
||||
: -20%</div>
|
||||
{{/if}}
|
||||
|
||||
</fieldSet>
|
||||
|
||||
|
||||
{{#if hasModifier}}
|
||||
<fieldSet class="dialog-modifier">
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.modifier"}}</legend>
|
||||
<select name="modifier" class="roll-skill-modifier">
|
||||
{{selectOptions choiceModifier selected=modifier}}
|
||||
</select>
|
||||
</fieldSet>
|
||||
<fieldSet class="dialog-modifier">
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.modifier"}}</legend>
|
||||
<select name="modifier" class="roll-skill-modifier">
|
||||
{{selectOptions choiceModifier selected=modifier}}
|
||||
</select>
|
||||
</fieldSet>
|
||||
{{/if}}
|
||||
|
||||
{{#if hasMultiplier}}
|
||||
<fieldSet class="dialog-modifier">
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.multiplier"}}</legend>
|
||||
<select name="multiplier" class="roll-skill-modifier roll-skill-multiplier">
|
||||
{{selectOptions choiceMultiplier selected=multiplier}}
|
||||
</select>
|
||||
</fieldSet>
|
||||
<fieldSet class="dialog-modifier">
|
||||
<legend>{{localize "CTHULHUETERNAL.Label.multiplier"}}</legend>
|
||||
<select
|
||||
name="multiplier"
|
||||
class="roll-skill-modifier roll-skill-multiplier"
|
||||
>
|
||||
{{selectOptions choiceMultiplier selected=multiplier}}
|
||||
</select>
|
||||
</fieldSet>
|
||||
{{/if}}
|
||||
|
||||
<fieldSet>
|
||||
|
||||
@@ -12,32 +12,60 @@
|
||||
{{/if}}
|
||||
|
||||
{{formField systemFields.state value=system.state localize=true}}
|
||||
{{formField systemFields.isStunning value=system.isStunning localize=true}}
|
||||
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.hasDirectSkill value=system.hasDirectSkill }}
|
||||
{{#if system.hasDirectSkill}}
|
||||
{{formField systemFields.directSkillValue value=system.directSkillValue }}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{formField systemFields.applyDamageBonus value=system.applyDamageBonus}}
|
||||
{{formField systemFields.damage value=system.damage}}
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.hasDamageDistance value=system.hasDamageDistance localize=true}}
|
||||
</div>
|
||||
|
||||
{{#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|}}
|
||||
<div class="flexrow">
|
||||
<label class="damage-distance">Distance</label><input type="number" name="system.damageDistance.{{idx}}.distance" value="{{damageDistance.distance}}" min="0" />
|
||||
<label>Damage</label><input type="text" name="system.damageDistance.{{idx}}.damage" value="{{damageDistance.damage}}" />
|
||||
</div>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.damage value=system.damage}}
|
||||
{{formField systemFields.applyDamageBonus value=system.applyDamageBonus}}
|
||||
</div>
|
||||
{{#if isRanged}}
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.baseRange value=system.baseRange}}
|
||||
{{formField systemFields.rangeUnit value=system.rangeUnit localize=true}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isFireArm}}
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.hasSelectiveFire value=system.hasSelectiveFire}}
|
||||
{{formField systemFields.hasSight value=system.hasSight}}
|
||||
</div>
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.ammo.fields.value value=system.ammo.value}}
|
||||
{{formField systemFields.ammo.fields.max value=system.ammo.max}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{formField systemFields.lethality value=system.lethality}}
|
||||
{{formField systemFields.killRadius value=system.killRadius}}
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.lethality value=system.lethality}}
|
||||
{{formField systemFields.killRadius value=system.killRadius}}
|
||||
</div>
|
||||
|
||||
<div class="flexrow">
|
||||
{{formField systemFields.armorPiercing value=system.armorPiercing}}
|
||||
|
||||
{{formField systemFields.resourceLevel value=system.resourceLevel}}
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
|
||||
Reference in New Issue
Block a user