4 Commits

Author SHA1 Message Date
554220a812 Sync with wfrp 4, v8.4.0
All checks were successful
Release Creation / build (release) Successful in 51s
2025-02-01 21:10:28 +01:00
e7ea8138c9 Enhance fonts/sizing/colors 2025-01-28 14:22:11 +01:00
6a18f7fa29 Additionnal cleanup 2025-01-28 07:20:29 +01:00
7070d4c1da Sync bol for module releas 2025-01-25 22:28:16 +01:00
25 changed files with 255 additions and 145 deletions

View File

@ -27,7 +27,7 @@ jobs:
env: env:
version: ${{steps.get_version.outputs.version-without-v}} version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}} url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-cthulhu-eternal.zip download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-cthulhu-eternal.zip
# Create a zip file with all files required by the module to add to the release # Create a zip file with all files required by the module to add to the release

Binary file not shown.

BIN
assets/fonts/FeFCrm2.ttf Normal file

Binary file not shown.

BIN
assets/fonts/FeGPrm2.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -34,9 +34,17 @@
font-family: "Volkhov"; font-family: "Volkhov";
src: url("../assets/fonts/Volkhov-Regular.ttf") format("truetype"); src: url("../assets/fonts/Volkhov-Regular.ttf") format("truetype");
} }
@font-face {
font-family: "ChantelliAntiqua";
src: url("../assets/fonts/Chantelli_Antiqua.ttf") format("truetype");
}
@font-face { @font-face {
font-family: "IMFell"; font-family: "IMFell";
src: url("../assets/fonts/IMFell.ttf") format("truetype"); src: url("../assets/fonts/IMFeDPrm28P.ttf") format("truetype");
}
@font-face {
font-family: "SailRegular";
src: url("../assets/fonts/Sail-Regular.ttf") format("truetype");
} }
@font-face { @font-face {
font-family: "Dominican"; font-family: "Dominican";
@ -104,13 +112,13 @@
} }
:root { :root {
--font-size-standard: 0.9rem; --font-size-standard: 0.9rem;
--font-size-result: 1.4rem;
--background-image-base: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url("../assets/ui/jazz_background_main.webp"); --background-image-base: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url("../assets/ui/jazz_background_main.webp");
/*--background-image-base: url("../assets/ui/jazzage_background_main.webp");*/
--font-primary: "RozhaOne"; --font-primary: "RozhaOne";
--font-secondary: "RozhaOne"; --font-secondary: "RozhaOne";
--font-title: "Broadway"; --font-title: "Broadway";
--logo-standard: url("../assets/logos/reanimated-ce-logo.webp"); --logo-standard: url("../assets/logos/reanimated-ce-logo.webp");
--color-success: #12e912; --color-success: #0f7a0f;
--color-failure: darkred; --color-failure: darkred;
--color-warning: darkorange; --color-warning: darkorange;
--color-critical-success: #1527cc; --color-critical-success: #1527cc;
@ -305,7 +313,7 @@ i.fvtt-cthulhu-eternal {
} }
.fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-right .protagonist-name input { .fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-right .protagonist-name input {
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.4); font-size: var(--font-size-title);
width: 400px; width: 400px;
} }
.fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-right .san { .fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-right .san {
@ -1915,7 +1923,7 @@ i.fvtt-cthulhu-eternal {
border: none; border: none;
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1);
color: var(--color-dark-2); color: var(--color-dark-2);
width: 60px; width: 4rem;
text-align: center; text-align: center;
} }
.red-warning { .red-warning {
@ -1975,25 +1983,30 @@ i.fvtt-cthulhu-eternal {
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1); 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: 4rem;
display: none;
}
.dice-roll .intro-chat .intro-right ul .result-success { .dice-roll .intro-chat .intro-right ul .result-success {
color: var(--color-success); color: var(--color-success);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.dice-roll .intro-chat .intro-right ul .result-critical-success { .dice-roll .intro-chat .intro-right ul .result-critical-success {
color: var(--color-critical-success); color: var(--color-critical-success);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.dice-roll .intro-chat .intro-right ul .result-failure { .dice-roll .intro-chat .intro-right ul .result-failure {
color: var(--color-failure); color: var(--color-failure);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.dice-roll .intro-chat .intro-right ul .result-critical-failure { .dice-roll .intro-chat .intro-right ul .result-critical-failure {
color: var(--color-critical-failure); color: var(--color-critical-failure);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.dice-roll .intro-chat .intro-right .introText { .dice-roll .intro-chat .intro-right .introText {
font-family: var(--font-secondary); font-family: var(--font-secondary);

View File

@ -114,25 +114,14 @@ Hooks.once("ready", function () {
}) })
Hooks.on("renderChatMessage", (message, html, data) => { Hooks.on("renderChatMessage", (message, html, data) => {
const typeMessage = data.message.flags.CthulhuEternal?.typeMessage // Affichage des boutons de jet de dés uniquement pour les joueurs
// Message de demande de jet de dés if (message.author.id === game.user.id) {
if (typeMessage === "askRoll") { html.find(".nudge-roll").each((i, btn) => {
// Affichage des boutons de jet de dés uniquement pour les joueurs btn.style.display = "inline"
if (game.user.isGM) { })
html.find(".ask-roll-dice").each((i, btn) => { html.find(".nudge-roll").click((event) => {
btn.style.display = "none" CthulhuEternalUtils.nudgeRoll(message)
}) })
} else {
html.find(".ask-roll-dice").click((event) => {
const btn = $(event.currentTarget)
const type = btn.data("type")
const value = btn.data("value")
const avantage = btn.data("avantage") ?? "="
const character = game.user.character
if (type === SYSTEM.ROLL_TYPE.RESOURCE) character.rollResource(value)
else if (type === SYSTEM.ROLL_TYPE.SAVE) character.rollSave(value, avantage)
})
}
} }
}) })

View File

@ -325,6 +325,9 @@
"veryHarsh": "Very Harsh" "veryHarsh": "Very Harsh"
}, },
"Label": { "Label": {
"nudgedRoll": "Nudged Roll",
"selectNewValue": "Select the new value",
"wpCost": "WP Cost",
"Hand": "Hand", "Hand": "Hand",
"Stowed": "Stowed", "Stowed": "Stowed",
"Storage": "Storage", "Storage": "Storage",
@ -437,7 +440,9 @@
}, },
"Roll": { "Roll": {
"skill": "Skill", "skill": "Skill",
"roll": "Roll" "roll": "Roll",
"applyNudge": "Apply",
"cancel": "Cancel"
}, },
"Tooltip": { "Tooltip": {
"sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP.", "sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP.",
@ -445,10 +450,11 @@
}, },
"Chat": { "Chat": {
}, },
"Notitications": { "Notifications": {
"NoWeaponSkill": "No weapon skill found for this weapon. Check Weapon definition or available skills/era", "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", "NoWeaponType": "No weapon type found for this weapon subtype. Check Weapon definition or available skills/era",
"skillAlreadyExists": "Skill already exists" "skillAlreadyExists": "Skill already exists",
"WrongEra": "The era of the item does not match the ear of the system"
} }
} }
} }

View File

@ -42,18 +42,18 @@ export const INSANITY = {
} }
export const ERA_CSS = { export const ERA_CSS = {
jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%)" }, jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", baseFontSize: "1.0rem", 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", imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" }, 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: "Megrim", secondaryFont: "Megrim", titleFont: "Seabreed", imgFilter: "brightness(0) saturate(100%) invert(83%) sepia(30%) saturate(588%) hue-rotate(168deg) brightness(105%) contrast(103%)" }, 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", imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" }, 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: "BebasNeue", secondaryFont: "BebasNeue", titleFont: "TopSecret", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)"}, 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", imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" }, 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: "UncialAntiqua", secondaryFont: "UncialAntiqua", titleFont: "Luminari", imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"}, medieval: { primaryFont: "UncialAntiqua", 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", imgFilter: "brightness(0) saturate(100%) invert(95%) sepia(9%) saturate(1471%) hue-rotate(342deg) brightness(103%) contrast(107%)"}, 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", imgFilter: "brightness(0) saturate(100%) invert(90%) sepia(38%) saturate(341%) hue-rotate(21deg) brightness(105%) contrast(105%)"}, 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: "Tangerine", secondaryFont: "Tangerine", titleFont: "P22Operina", imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" }, 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: "SpectralSC", secondaryFont: "SpectralSC", titleFont: "TrajanPro", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" }, 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", imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" } postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.25rem",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 = { export const RESOURCE_RATING = {
@ -140,6 +140,13 @@ export const WEAPON_SKILL_MAPPING = {
"rangedfirearm": "CTHULHUETERNAL.Skill.Firearms", "rangedfirearm": "CTHULHUETERNAL.Skill.Firearms",
"unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat" "unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat"
}, },
postapo: {
"melee": "CTHULHUETERNAL.Skill.Melee",
"rangedprimitive": "CTHULHUETERNAL.Skill.Firearms",
"rangedthrown": "CTHULHUETERNAL.Skill.Athletics",
"rangedfirearm": "CTHULHUETERNAL.Skill.Firearms",
"unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat"
},
jazz: { jazz: {
"melee": "CTHULHUETERNAL.Skill.Melee", "melee": "CTHULHUETERNAL.Skill.Melee",
"rangedprimitive": "CTHULHUETERNAL.Skill.Firearms", "rangedprimitive": "CTHULHUETERNAL.Skill.Firearms",
@ -211,9 +218,9 @@ export const WEAPON_SKILL_MAPPING = {
} }
export const MODIFIER_CHOICES = { export const MODIFIER_CHOICES = {
"-10": "-10",
"-20": "-20",
"-40": "-40", "-40": "-40",
"-20": "-20",
"-10": "-10",
"+0": "+0", "+0": "+0",
"+10": "+10", "+10": "+10",
"+20": "+20", "+20": "+20",

View File

@ -79,6 +79,14 @@ export default class CthulhuEternalRoll extends Roll {
return this.options.isExhausted return this.options.isExhausted
} }
get isNudgedRoll() {
return this.options.isNudgedRoll
}
get wpCost() {
return this.options.wpCost
}
static updateResourceDialog(options) { static updateResourceDialog(options) {
let rating = 0 let rating = 0
if (options.rollItem.enableHand) { if (options.rollItem.enableHand) {
@ -114,6 +122,7 @@ export default class CthulhuEternalRoll extends Roll {
let formula = "1d100" let formula = "1d100"
let hasModifier = true let hasModifier = true
let hasMultiplier = false let hasMultiplier = false
options.isNudge = true
switch (options.rollType) { switch (options.rollType) {
case "skill": case "skill":
@ -123,6 +132,7 @@ export default class CthulhuEternalRoll extends Roll {
case "san": case "san":
case "char": case "char":
options.initialScore = options.rollItem.targetScore options.initialScore = options.rollItem.targetScore
options.isNudge = (options.rollType !== "san")
break break
case "resource": case "resource":
hasModifier = false hasModifier = false
@ -133,6 +143,7 @@ export default class CthulhuEternalRoll extends Roll {
options.rollItem.enableHand = true options.rollItem.enableHand = true
options.rollItem.enableStowed = true options.rollItem.enableStowed = true
options.rollItem.enableStorage = true options.rollItem.enableStorage = true
options.isNudge = false
break break
case "damage": case "damage":
let formula = options.rollItem.system.damage let formula = options.rollItem.system.damage
@ -142,6 +153,7 @@ export default class CthulhuEternalRoll extends Roll {
flavor: `${options.rollItem.name} - Damage Roll` flavor: `${options.rollItem.name} - Damage Roll`
}); });
let isLethal = false let isLethal = false
options.isNudge = false
if (options.rollItem.system.lethality > 0) { if (options.rollItem.system.lethality > 0) {
let lethalityRoll = new Roll("1d100") let lethalityRoll = new Roll("1d100")
await lethalityRoll.evaluate() await lethalityRoll.evaluate()
@ -153,8 +165,14 @@ export default class CthulhuEternalRoll extends Roll {
return return
case "weapon": case "weapon":
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era") let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
if (era !== options.rollItem.system.settings) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.WrongEra"))
console.log("WP Wrong Era", era, options.rollItem.system.weaponType)
return
}
if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) { if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType")) ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType"))
console.log("WP Not found", era, options.rollItem.system.weaponType)
return return
} }
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
@ -259,8 +277,8 @@ export default class CthulhuEternalRoll extends Roll {
rollData.rollMode = rollContext.visibility rollData.rollMode = rollContext.visibility
// Update target score // Update target score
console.log(rollData) console.log("Rolldata", rollData, options)
if (options.rollType === "resource" ) { if (options.rollType === "resource") {
rollData.targetScore = options.initialScore * Number(rollContext.multiplier) rollData.targetScore = options.initialScore * Number(rollContext.multiplier)
} else { } else {
rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100) rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100)
@ -273,22 +291,28 @@ export default class CthulhuEternalRoll extends Roll {
rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100) rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100)
} }
/**
* A hook event that fires before the roll is made.
*/
if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return
const roll = new this(formula, options.data, rollData) const roll = new this(formula, options.data, rollData)
await roll.evaluate() await roll.evaluate()
roll.displayRollResult(roll, options, rollData)
if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return
return roll
}
displayRollResult(formula, options, rollData) {
// Compute the result quality // Compute the result quality
let resultType = "failure" let resultType = "failure"
let dec = Math.floor(roll.total / 10) let dec = Math.floor(this.total / 10)
let unit = roll.total - (dec * 10) let unit = this.total - (dec * 10)
if (roll.total <= rollData.targetScore) { if (this.total <= rollData.targetScore) {
resultType = "success" resultType = "success"
// Detect if decimal == unit in the dire total result // Detect if decimal == unit in the dire total result
if (dec === unit || roll.total === 1) { if (dec === unit || this.total === 1) {
resultType = "successCritical" resultType = "successCritical"
} }
} else { } else {
@ -298,20 +322,20 @@ export default class CthulhuEternalRoll extends Roll {
} }
} }
roll.options.resultType = resultType this.options.resultType = resultType
roll.options.isSuccess = resultType === "success" || resultType === "successCritical" if (this.options.isNudgedRoll) {
roll.options.isFailure = resultType === "failure" || resultType === "failureCritical" this.options.isSuccess = resultType === "success" || resultType === "successCritical"
roll.options.isCritical = resultType === "successCritical" || resultType === "failureCritical" this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
roll.options.isLowWP = rollData.isLowWP this.options.isCritical = false
roll.options.isZeroWP = rollData.isZeroWP } else {
roll.options.isExhausted = rollData.isExhausted this.options.isSuccess = resultType === "success" || resultType === "successCritical"
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
/** this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
* A hook event that fires after the roll has been made. }
*/ this.options.isLowWP = rollData.isLowWP
if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return this.options.isZeroWP = rollData.isZeroWP
this.options.isExhausted = rollData.isExhausted
return roll this.options.rollData = foundry.utils.duplicate(rollData)
} }
/** /**
@ -387,9 +411,8 @@ export default class CthulhuEternalRoll extends Roll {
cardData.isLowWP = this.isLowWP cardData.isLowWP = this.isLowWP
cardData.isZeroWP = this.isZeroWP cardData.isZeroWP = this.isZeroWP
cardData.isExhausted = this.isExhausted cardData.isExhausted = this.isExhausted
cardData.isNudgedRoll = this.isNudgedRoll
cardData.wpCost = this.wpCost
console.log(cardData)
cardData.cssClass = cardData.css.join(" ") cardData.cssClass = cardData.css.join(" ")
cardData.tooltip = isPrivate ? "" : await this.getTooltip() cardData.tooltip = isPrivate ? "" : await this.getTooltip()

View File

@ -178,6 +178,17 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
return this.wp.exhausted return this.wp.exhausted
} }
modifyWP(value) {
let updates = {}
let wp = Math.max(Math.min(this.wp.value + value, this.wp.max), 0)
if ( this.wp.value !== wp) {
updates[`system.wp.value`] = wp
}
if (Object.keys(updates).length > 0) {
this.parent.update(updates)
}
}
setBP() { setBP() {
let updates = {} let updates = {}
let bp = Math.max(this.san.value - this.characteristics.pow.value, 0) let bp = Math.max(this.san.value - this.characteristics.pow.value, 0)

View File

@ -1,4 +1,6 @@
import CthulhuEternalRoll from "./documents/roll.mjs"
export default class CthulhuEternalUtils { export default class CthulhuEternalUtils {
static registerSettings() { static registerSettings() {
@ -177,12 +179,82 @@ export default class CthulhuEternalUtils {
} }
static async nudgeRoll(rollMessage) {
let dialogContext = rollMessage.rolls[0]?.options
let actor = game.actors.get(dialogContext.actorId)
dialogContext.wpValue = actor.system.wp.value
dialogContext.rollResultIndex = rollMessage.rolls[0].total - 1
dialogContext.minValue = Math.max(rollMessage.rolls[0].total - (dialogContext.wpValue * 5), 1)
dialogContext.maxValue = Math.min(rollMessage.rolls[0].total + (dialogContext.wpValue * 5), 100)
dialogContext.wpCost = 0
// Build options table for the select operator between minValue and maxValue
dialogContext.nudgeOptions = Array.from({ length: dialogContext.maxValue - dialogContext.minValue + 1 }, (_, i) => dialogContext.minValue + i)
console.log(dialogContext)
const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/nudge-dialog.hbs", dialogContext)
const title = game.i18n.localize("CTHULHUETERNAL.Roll.nudgeRoll")
const rollContext = await foundry.applications.api.DialogV2.wait({
window: { title: title },
classes: ["fvtt-cthulhu-eternal"],
content,
buttons: [
{
action: "apply",
label: game.i18n.localize("CTHULHUETERNAL.Roll.applyNudge"),
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
{
action: "cancel",
label: game.i18n.localize("CTHULHUETERNAL.Roll.cancel"),
callback: (event, button, dialog) => { }
}
],
actions: {
},
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)
$("#nudged-wp-cost").val(dialogContext.wpCost)
})
}
})
// If the user cancels the dialog, exit
if (rollContext === null || dialogContext.wpCost === 0) {
return
}
const roll = new CthulhuEternalRoll(String(dialogContext.nudgedValue))
await roll.evaluate()
roll.options = dialogContext
roll.options.isNudgedRoll = true
roll.options.isNudge = false
roll.displayRollResult(roll, dialogContext, dialogContext.rollData)
roll.toMessage()
actor.system.modifyWP(-dialogContext.wpCost)
}
static setupCSSRootVariables() { static setupCSSRootVariables() {
const era = game.settings.get("fvtt-cthulhu-eternal", "settings-era") const era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
let eraCSS = SYSTEM.ERA_CSS[era]; let eraCSS = SYSTEM.ERA_CSS[era];
if (!eraCSS) eraCSS = SYSTEM.ERA_CSS["jazz"]; if (!eraCSS) eraCSS = SYSTEM.ERA_CSS["jazz"];
document.documentElement.style.setProperty('--font-size-standard', eraCSS.baseFontSize);
document.documentElement.style.setProperty('--font-size-title', eraCSS.titleFontSize);
document.documentElement.style.setProperty('--font-size-result', eraCSS.titleFontSize);
document.documentElement.style.setProperty('--font-primary', eraCSS.primaryFont); document.documentElement.style.setProperty('--font-primary', eraCSS.primaryFont);
document.documentElement.style.setProperty('--font-secondary', eraCSS.secondaryFont); document.documentElement.style.setProperty('--font-secondary', eraCSS.secondaryFont);
document.documentElement.style.setProperty('--font-title', eraCSS.titleFont); document.documentElement.style.setProperty('--font-title', eraCSS.titleFont);

View File

@ -1 +1 @@
MANIFEST-000076 MANIFEST-000096

View File

@ -1,8 +1,8 @@
2025/01/25-20:17:02.992814 7f697a7fc6c0 Recovering log #74 2025/02/01-13:04:37.403980 7fd1c9ffb6c0 Recovering log #94
2025/01/25-20:17:03.002900 7f697a7fc6c0 Delete type=3 #72 2025/02/01-13:04:37.414560 7fd1c9ffb6c0 Delete type=3 #92
2025/01/25-20:17:03.002968 7f697a7fc6c0 Delete type=0 #74 2025/02/01-13:04:37.414616 7fd1c9ffb6c0 Delete type=0 #94
2025/01/25-20:19:31.386247 7f6978bff6c0 Level-0 table #79: started 2025/02/01-21:09:42.547683 7fd1c93ff6c0 Level-0 table #99: started
2025/01/25-20:19:31.386288 7f6978bff6c0 Level-0 table #79: 0 bytes OK 2025/02/01-21:09:42.547729 7fd1c93ff6c0 Level-0 table #99: 0 bytes OK
2025/01/25-20:19:31.417028 7f6978bff6c0 Delete type=0 #77 2025/02/01-21:09:42.554673 7fd1c93ff6c0 Delete type=0 #97
2025/01/25-20:19:31.593890 7f6978bff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) 2025/02/01-21:09:42.570630 7fd1c93ff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/01/25-20:19:31.593942 7f6978bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) 2025/02/01-21:09:42.570661 7fd1c93ff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)

View File

@ -1,8 +1,8 @@
2025/01/25-20:09:49.585129 7f697a7fc6c0 Recovering log #70 2025/01/28-13:40:46.388286 7fc73affd6c0 Recovering log #90
2025/01/25-20:09:49.662901 7f697a7fc6c0 Delete type=3 #68 2025/01/28-13:40:46.486338 7fc73affd6c0 Delete type=3 #88
2025/01/25-20:09:49.662960 7f697a7fc6c0 Delete type=0 #70 2025/01/28-13:40:46.486413 7fc73affd6c0 Delete type=0 #90
2025/01/25-20:11:19.050068 7f6978bff6c0 Level-0 table #75: started 2025/01/28-14:21:23.579080 7fc738ff96c0 Level-0 table #95: started
2025/01/25-20:11:19.050103 7f6978bff6c0 Level-0 table #75: 0 bytes OK 2025/01/28-14:21:23.579113 7fc738ff96c0 Level-0 table #95: 0 bytes OK
2025/01/25-20:11:19.078755 7f6978bff6c0 Delete type=0 #73 2025/01/28-14:21:23.585685 7fc738ff96c0 Delete type=0 #93
2025/01/25-20:11:19.078917 7f6978bff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) 2025/01/28-14:21:23.595091 7fc738ff96c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/01/25-20:11:19.078946 7f6978bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end) 2025/01/28-14:21:23.607394 7fc738ff96c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)

View File

@ -44,9 +44,19 @@
src: url("../assets/fonts/Volkhov-Regular.ttf") format("truetype"); src: url("../assets/fonts/Volkhov-Regular.ttf") format("truetype");
} }
@font-face {
font-family: "ChantelliAntiqua";
src: url("../assets/fonts/Chantelli_Antiqua.ttf") format("truetype");
}
@font-face { @font-face {
font-family: "IMFell"; font-family: "IMFell";
src: url("../assets/fonts/IMFell.ttf") format("truetype"); src: url("../assets/fonts/IMFeDPrm28P.ttf") format("truetype");
}
@font-face {
font-family: "SailRegular";
src: url("../assets/fonts/Sail-Regular.ttf") format("truetype");
} }
@font-face { @font-face {

View File

@ -1,13 +1,13 @@
:root { :root {
--font-size-standard: 0.9rem; --font-size-standard: 0.9rem;
--font-size-result: 1.4rem;
--background-image-base: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), --background-image-base: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)),
url("../assets/ui/jazz_background_main.webp"); url("../assets/ui/jazz_background_main.webp");
/*--background-image-base: url("../assets/ui/jazzage_background_main.webp");*/
--font-primary: "RozhaOne"; --font-primary: "RozhaOne";
--font-secondary: "RozhaOne"; --font-secondary: "RozhaOne";
--font-title: "Broadway"; --font-title: "Broadway";
--logo-standard: url("../assets/logos/reanimated-ce-logo.webp"); --logo-standard: url("../assets/logos/reanimated-ce-logo.webp");
--color-success: rgb(18, 233, 18); --color-success: rgb(15, 122, 15);
--color-failure: darkred; --color-failure: darkred;
--color-warning: darkorange; --color-warning: darkorange;
--color-critical-success: rgb(21, 39, 204); --color-critical-success: rgb(21, 39, 204);

View File

@ -62,7 +62,7 @@
display: flex; display: flex;
input { input {
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.4); font-size: var(--font-size-title);
width: 400px; width: 400px;
} }
} }

View File

@ -31,7 +31,7 @@
border: none; border: none;
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1);
color: var(--color-dark-2); color: var(--color-dark-2);
width: 60px; width: 4rem;
text-align: center; text-align: center;
} }
} }
@ -93,25 +93,30 @@
font-family: var(--font-primary); font-family: var(--font-primary);
font-size: calc(var(--font-size-standard) * 1.0); font-size: calc(var(--font-size-standard) * 1.0);
} }
.nudge-roll {
font-size: calc(var(--font-size-standard) * 1.0);
margin-left: 4rem;
display: none;
}
.result-success { .result-success {
color: var(--color-success); color: var(--color-success);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.result-critical-success { .result-critical-success {
color: var(--color-critical-success); color: var(--color-critical-success);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.result-failure { .result-failure {
color: var(--color-failure); color: var(--color-failure);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
.result-critical-failure { .result-critical-failure {
color: var(--color-critical-failure); color: var(--color-critical-failure);
font-family: var(--font-title); font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.2); font-size: var(--font-size-result);
} }
} }
.introText { .introText {

View File

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

View File

@ -14,6 +14,10 @@
<li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li> <li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li>
{{/if}} {{/if}}
{{#if isNudgedRoll}}
<li><strong>{{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} WP spent</strong></li>
{{/if}}
{{#if weapon}} {{#if weapon}}
<li><strong>Weapon : {{weapon.name}}</strong></li> <li><strong>Weapon : {{weapon.name}}</strong></li>
{{/if}} {{/if}}
@ -47,14 +51,24 @@
{{#if isCritical}} {{#if isCritical}}
<li class="result-critical-success">{{localize "CTHULHUETERNAL.Label.criticalSuccess"}}</li> <li class="result-critical-success">{{localize "CTHULHUETERNAL.Label.criticalSuccess"}}</li>
{{else}} {{else}}
<li class="result-success">{{localize "CTHULHUETERNAL.Label.success"}}</li> <li class="result-success">
{{localize "CTHULHUETERNAL.Label.success"}}
{{#if isNudge}}
<a class="nudge-roll"><i class="fa-solid fa-circle-sort-down"></i></a>
{{/if}}
</li>
{{/if}} {{/if}}
{{/if}} {{/if}}
{{#if isFailure}} {{#if isFailure}}
{{#if isCritical}} {{#if isCritical}}
<li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}</li> <li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}</li>
{{else}} {{else}}
<li class="result-failure">{{localize "CTHULHUETERNAL.Label.failure"}}</li> <li class="result-failure">
{{localize "CTHULHUETERNAL.Label.failure"}}
{{#if isNudge}}
<a class="nudge-roll"><i class="fa-solid fa-circle-sort-down"></i></a>
{{/if}}
</li>
{{/if}} {{/if}}
{{/if}} {{/if}}
</ul> </ul>

View File

@ -1,39 +0,0 @@
<table class="tenebris-table">
<thead>
<tr>
<th>{{localize "TENEBRIS.Manager.player"}}</th>
<th>{{localize "TENEBRIS.Manager.character"}}</th>
<th>{{localize "TENEBRIS.Manager.pv"}}</th>
<td data-action="saveAll" data-save="rob">{{localize "TENEBRIS.Manager.rob"}}</td>
<td data-action="saveAll" data-save="dex">{{localize "TENEBRIS.Manager.dex"}}</td>
<td data-action="saveAll" data-save="int">{{localize "TENEBRIS.Manager.int"}}</td>
<td data-action="saveAll" data-save="per">{{localize "TENEBRIS.Manager.per"}}</td>
<td data-action="saveAll" data-save="vol">{{localize "TENEBRIS.Manager.vol"}}</td>
<td data-action="resourceAll" data-resource="san">{{localize "TENEBRIS.Manager.san"}}</td>
<td data-action="resourceAll" data-resource="oeil">{{localize "TENEBRIS.Manager.oeil"}}</td>
<td data-action="resourceAll" data-resource="verbe">{{localize "TENEBRIS.Manager.verbe"}}</td>
<td data-action="resourceAll" data-resource="bourse">{{localize "TENEBRIS.Manager.bourse"}}</td>
<td data-action="resourceAll" data-resource="magie">{{localize "TENEBRIS.Manager.magie"}}</td>
</tr>
</thead>
<tbody>
{{#each players as |player|}}
{{!log "player" this}}
<tr class="player" data-user-id="{{player.id}}" data-character-name="{{player.character.name}}" data-character-id="{{player.character.id}}">
<td>{{player.name}}</td>
<td data-action="openSheet" data-character-id="{{player.character.id}}">{{player.character.name}}</td>
<td>{{player.character.system.pv.value}}</td>
<td data-action="saveOne" data-save="rob">{{player.character.system.caracteristiques.rob.valeur}}</td>
<td data-action="saveOne" data-save="dex">{{player.character.system.caracteristiques.dex.valeur}}</td>
<td data-action="saveOne" data-save="int">{{player.character.system.caracteristiques.int.valeur}}</td>
<td data-action="saveOne" data-save="per">{{player.character.system.caracteristiques.per.valeur}}</td>
<td data-action="saveOne" data-save="vol">{{player.character.system.caracteristiques.vol.valeur}}</td>
<td data-action="resourceOne" data-resource="san">{{player.character.system.ressources.san.valeur}}</td>
<td data-action="resourceOne" data-resource="oeil">{{player.character.system.ressources.oeil.valeur}}</td>
<td data-action="resourceOne" data-resource="verbe">{{player.character.system.ressources.verbe.valeur}}</td>
<td data-action="resourceOne" data-resource="bourse">{{player.character.system.ressources.bourse.valeur}}</td>
<td data-action="resourceOne" data-resource="magie">{{player.character.system.ressources.magie.valeur}}</td>
</tr>
{{/each}}
</tbody>
</table>

View File

@ -1,4 +1,3 @@
{{log "roll-dialog" this}}
<div class="fvtt-cthulhu-eternal-roll-dialog"> <div class="fvtt-cthulhu-eternal-roll-dialog">
<fieldSet> <fieldSet>
{{#if (eq rollType "skill")}} {{#if (eq rollType "skill")}}