Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

70 changed files with 449 additions and 3926 deletions

View File

@ -27,7 +27,7 @@ jobs:
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" style="" transform="translate(0,0)"><path d="M227.227 21.777c-1.845 0-3.704.05-5.567.157-15.314.875-30.76 5.305-39.494 10.863l-.008 73.15c2.884-.094 5.777-.147 8.676-.142 23.382.036 47.104 3.286 68.47 9.513l.01-87.507c-7.034-3.518-19.178-6.03-32.087-6.033zm80.74 9.16c-11.925.15-23.077 2.364-29.967 5.596l-.008 77.602v7.658c38.486 15.67 64.814 42.48 58.735 78.764l-.96 5.73-5.562 1.674c-17.45 5.253-34.872 9.703-52.225 13.335V246.53c25.562-.704 51.327-2.687 77.145-6.098l.02-197.928c-8.284-5.563-23.508-10.243-38.842-11.328-2.792-.198-5.584-.273-8.336-.238zM143.223 46.294c-1.176-.015-2.374-.01-3.588.02-4.175.1-8.533.468-12.903 1.152-15.67 2.454-31.477 8.565-40.406 15.402l-.01 72.955c18.808-15.81 46.704-25.143 77.15-28.54l.007-57.966c-4.82-1.752-12.018-2.916-20.25-3.023zm258.394 3.46c-10.804.117-20.722 1.93-27.043 4.655l-.02 183.182c25.074-4.02 50.16-9.412 75.122-16.358l1.99-158.447c-8.352-5.9-23.648-11.025-39.05-12.553-3.698-.366-7.398-.517-11-.478zm-222.775 74.202c-53.72.702-101.407 20.365-97.887 66.6 15.836-3.918 30.84-5.893 44.94-6.1 34.84-.51 64.213 9.704 87.318 27.613 34.608-3.11 69.852-10 105.412-20.314.14-41.287-74.098-68.657-139.783-67.8zm-48.877 78.65c-1.296-.003-2.603.012-3.92.045-17.256.436-36.45 4.03-57.566 11.037 5.79 53.808 26.325 106.41 58.5 143.346 6.226 7.15 12.856 13.712 19.875 19.615 29.303 9.282 69.26 12.917 110.534 12.14 3.777-55.805-8.717-108.357-36.193-142.74-21.265-26.61-51.064-43.39-91.232-43.444zm129.326 22.282c-9.358 1.637-18.69 3.016-27.995 4.15 1.54 1.74 3.043 3.52 4.502 5.346 3.146 3.937 6.094 8.062 8.873 12.334 9.916.144 19.868.125 29.857-.106H259.29v-21.723zm191.817 15.343c-65.406 17.826-131.462 25.41-195.85 25.315 16.998 35.144 23.828 78.093 21.013 122.6 42.482-2.08 85.03-8.23 118.187-15.983 26.693-32.78 47.37-77.118 56.65-131.932zM400.51 389.9c-38.334 9.145-87.95 16.056-136.873 17.454-47.67 1.36-94.336-2.228-129.448-15.262l-.01 78.93c27.187 12.568 76.414 20.205 127.318 20.298 51.224.094 104.214-7.173 139-20.773l.012-80.647z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1 +0,0 @@
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" style="" transform="translate(0,0)"><path d="M245.813 23.188c-1.228-.006-2.455.027-3.657.093-10.103.56-19.646 3.682-30.156 11.25l20.72 196.782c-8.394 2.127-16.676 4.47-24.814 7.094L137.72 57.812c-7.032-1.706-17.442-.3-27.126 4.626-10.248 5.213-19.034 13.84-22.813 22.937L155.03 261.5c-7.414 4.345-14.59 9.137-21.5 14.47l-74.343-94.25c-16.34.698-34.965 14.455-37.562 32.655C28.89 222.693 93.978 297.77 126 357.405c10.3 19.184 29.543 50.725 39.188 70.064 5.83 11.693 16.004 24.238 27.843 32.342 11.84 8.104 24.7 11.82 37.907 8.282l112.907-30.22c5.493-1.47 9.196-5.39 13.22-11.937 4.02-6.545 7.535-15.137 12.905-23 20.61-30.185 50.432-76.085 115.186-112.062-2.696-15.053-7.405-24.57-12.72-29.563-6.03-5.667-13.198-7.372-23.686-5.843-18.062 2.63-43.498 17.063-69.594 36.874-1.68 1.39-3.318 2.802-4.937 4.22l-7-61.252 42.5-155.718c-4.478-7.355-13.806-13.258-24.845-15.97-10.874-2.67-22.506-1.698-30.28 1.595l-38.75 149.874c-9.365 1.58-18.732 3.17-28.064 4.812L273.69 27.5c-10.057-2.52-19.284-4.272-27.875-4.313zM234.343 255l30.157 56.625 54.406-33.906-33.78 54.186L341.562 362l-64.157-2.188 2.188 64.032-30.03-56.344-54.283 33.813 33.97-54.438-56.53-30.125 63.78 2.156L234.344 255z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1 +0,0 @@
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" style="" transform="translate(0,0)"><path d="M102.5 26.03l90.03 345.75 289.22 23.25-90.063-345.75L102.5 26.03zm-18.906 1.564c-30.466 11.873-55.68 53.098-49.75 75.312l3.25 11.78c.667-1.76 1.36-3.522 2.093-5.28C49.097 85.7 65.748 62.64 89.564 50.5l-5.97-22.906zm10.844 41.593c-16.657 10.012-29.92 28.077-38 47.407-5.247 12.55-8.038 25.63-8.75 36.53L112.5 388.407c.294-.55.572-1.106.875-1.656 10.603-19.252 27.823-37.695 51.125-48.47L94.437 69.19zm74.874 287.594c-17.677 9.078-31.145 23.717-39.562 39-4.464 8.107-7.27 16.364-8.688 23.75l11.688 42.408 1.625.125c-3.84-27.548 11.352-60.504 41.25-81.094l-6.313-24.19zm26.344 34c-32.567 17.27-46.51 52.44-41.844 72.94l289.844 24.5c-5.34-7.79-8.673-17.947-8.594-28.5l-22.406-9L459 443.436l-13.5-12.875c5.604-6.917 13.707-13.05 24.813-17.687L195.656 390.78z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ import * as applications from "./module/applications/_module.mjs"
import { handleSocketEvent } from "./module/socket.mjs"
import CthulhuEternalUtils from "./module/utils.mjs"
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) } } }
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 () {
console.info("Cthulhu Eternal RPG | Initializing System")
@ -33,8 +33,7 @@ Hooks.once("init", function () {
CONFIG.Actor.documentClass = documents.CthulhuEternalActor
CONFIG.Actor.dataModels = {
protagonist: models.CthulhuEternalProtagonist,
vehicle: models.CthulhuEternalVehicle,
creature: models.CthulhuEternalCreature
vehicle: models.CthulhuEternalVehicle
}
CONFIG.Item.documentClass = documents.CthulhuEternalItem
@ -48,16 +47,13 @@ Hooks.once("init", function () {
bond: models.CthulhuEternalBond,
arcane: models.CthulhuEternalArcane,
gear: models.CthulhuEternalGear,
archetype: models.CthulhuEternalArchetype,
ritual: models.CthulhuEternalRitual,
tome: models.CthulhuEternalTome
archetype: models.CthulhuEternalArchetype
}
// Register sheet application classes
Actors.unregisterSheet("core", ActorSheet)
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalProtagonistSheet, { types: ["protagonist"], makeDefault: true })
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalVehicleSheet, { types: ["vehicle"], makeDefault: true })
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalCreatureSheet, { types: ["creature"], makeDefault: true })
Items.unregisterSheet("core", ItemSheet)
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalSkillSheet, { types: ["skill"], makeDefault: true })
@ -70,8 +66,6 @@ Hooks.once("init", function () {
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalBondSheet, { types: ["bond"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalGearSheet, { types: ["gear"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArchetypeSheet, { types: ["archetype"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalRitualSheet, { types: ["ritual"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalTomeSheet, { types: ["tome"], makeDefault: true })
// Other Document Configuration
CONFIG.ChatMessage.documentClass = documents.CthulhuEternalChatMessage
@ -97,7 +91,6 @@ Hooks.once("init", function () {
console.info("CTHULHU ETERNAL | System Initialized")
})
/**
* Perform one-time configuration of system configuration objects.
*/
@ -121,20 +114,31 @@ Hooks.once("ready", function () {
})
Hooks.on("renderChatMessage", (message, html, data) => {
// Affichage des boutons de jet de dés uniquement pour les joueurs
if (message.author.id === game.user.id) {
html.find(".nudge-roll").each((i, btn) => {
btn.style.display = "inline"
})
html.find(".nudge-roll").click((event) => {
CthulhuEternalUtils.nudgeRoll(message)
})
const typeMessage = data.message.flags.CthulhuEternal?.typeMessage
// Message de demande de jet de dés
if (typeMessage === "askRoll") {
// Affichage des boutons de jet de dés uniquement pour les joueurs
if (game.user.isGM) {
html.find(".ask-roll-dice").each((i, btn) => {
btn.style.display = "none"
})
} 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)
})
}
}
})
// Dice-so-nice Ready
Hooks.once("diceSoNiceReady", (dice3d) => {
//configureDiceSoNice(dice3d)
configureDiceSoNice(dice3d)
})
/**

View File

@ -2,8 +2,7 @@
"TYPES": {
"Actor": {
"protagonist": "Protagonist",
"vehicle": "Vehicle",
"creature": "Creature"
"vehicle": "Vehicle"
},
"Item": {
"skill": "Skill",
@ -15,9 +14,7 @@
"mentaldisorder": "Mental Disorder",
"bond": "Bond" ,
"arcane": "Arcane",
"archetype": "Archetype",
"ritual": "Ritual",
"tome": "Tome"
"archetype": "Archetype"
}
},
"CTHULHUETERNAL": {
@ -40,86 +37,6 @@
},
"Protagonist": {
"FIELDS": {
"damageBonus": {
"label": "Dmg.Bonus"
},
"resources": {
"permanentRating": {
"label": "Permanent Rating"
},
"hand": {
"label": "Hand"
},
"stowed": {
"label": "Stowed"
},
"storage": {
"label": "Storage"
}
},
"biodata": {
"feature": {
"label": "Feature"
},
"adaptedToViolence": {
"label": "Adapted to violence"
},
"adaptedToHelplessness": {
"label": "Adapted to helplessness"
},
"harshness": {
"label": "Harshness"
},
"age": {
"label": "Age"
},
"gender": {
"label": "Gender"
},
"hair": {
"label": "Hair"
},
"eyes": {
"label": "Eyes"
},
"height": {
"label": "Height"
},
"home": {
"label": "Home"
},
"birthplace": {
"label": "Birthplace"
},
"label": "Biodata"
},
"characteristics:": {
"str": {
"label": "Strength"
},
"dex": {
"label": "Dexterity"
},
"int": {
"label": "Intelligence"
},
"pow": {
"label": "Power"
},
"con": {
"label": "Constitution"
},
"char": {
"label": "Charisma"
}
}
}
},
"Creature": {
"FIELDS": {
"damageBonus": {
"label": "Dmg.Bonus"
},
"resources": {
"permanentRating": {
"label": "Permanent Rating"
@ -266,12 +183,6 @@
"riflecarabine": "Rifle/Carabine"
},
"FIELDS": {
"hasDirectSkill": {
"label": "Has direct skill"
},
"directSkillValue": {
"label": "Direct skill value"
},
"state": {
"label": "State"
},
@ -413,85 +324,7 @@
"harsh": "Harsh",
"veryHarsh": "Very Harsh"
},
"Tome": {
"FIELDS": {
"language": {
"label": "Language"
},
"settings": {
"label": "Settings"
},
"studyTime": {
"label": "Study Time"
},
"sanLoss": {
"label": "SAN Loss"
},
"unnaturalSkill": {
"label": "Unnatural Skill"
},
"rituals": {
"label": "Rituals"
},
"minimumEra": {
"label": "Minimum Era"
},
"otherBenefits": {
"label": "Other Benefits"
},
"creationDate": {
"label": "Creation Date"
},
"description": {
"label": "Description"
}
},
"Label": {
"tomeDetails": "Tome Details"
},
"Button": {
"addRitual": "Add Ritual"
}
},
"Ritual": {
"Simple": "Simple",
"Complex": "Complex",
"Elaborate": "Elaborate",
"FIELDS": {
"ritualType": {
"label": "Type"
},
"studyTime": {
"label": "Study time"
},
"studySAN": {
"label": "Study SAN"
},
"activationTime": {
"label": "Activation time"
},
"activationSAN": {
"label": "Activation SAN"
},
"activationWP": {
"label": "Activation WP"
},
"description": {
"label": "Description"
}
}
},
"Label": {
"creature": "Creature",
"Rituals": "Rituals",
"Tomes": "Tomes",
"otherBenefits": "Other Benefits",
"Unarmed": "Unarmed",
"Cured": "Cured",
"Uncured": "Uncured",
"nudgedRoll": "Nudged Roll",
"selectNewValue": "Select the new value",
"wpCost": "WP Cost",
"Hand": "Hand",
"Stowed": "Stowed",
"Storage": "Storage",
@ -591,9 +424,7 @@
"newGear": "New Gear",
"newArcane": "New Arcane",
"newArchetype": "New Archetype",
"newSkill": "New Skill",
"newTome": "New Tome",
"newRitual": "New Ritual"
"newSkill": "New Skill"
},
"ChatMessage": {
"exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points."
@ -606,10 +437,7 @@
},
"Roll": {
"skill": "Skill",
"roll": "Roll",
"applyNudge": "Apply",
"cancel": "Cancel",
"nudgeRoll": "Nudge Roll"
"roll": "Roll"
},
"Tooltip": {
"sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP.",
@ -617,11 +445,10 @@
},
"Chat": {
},
"Notifications": {
"Notitications": {
"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",
"WrongEra": "The era of the item does not match the ear of the system"
"skillAlreadyExists": "Skill already exists"
}
}
}

View File

@ -9,7 +9,4 @@ export { default as CthulhuEternalMentalDisorderSheet } from "./sheets/mentaldis
export { default as CthulhuEternalGearSheet } from "./sheets/gear-sheet.mjs"
export { default as CthulhuEternalMotivationSheet } from "./sheets/motivation-sheet.mjs"
export { default as CthulhuEternalArchetypeSheet } from "./sheets/archetype-sheet.mjs"
export { default as CthulhuEternalRitualSheet } from "./sheets/ritual-sheet.mjs"
export { default as CthulhuEternalVehicleSheet } from "./sheets/vehicle-sheet.mjs"
export { default as CthulhuEternalCreatureSheet } from "./sheets/creature-sheet.mjs"
export { default as CthulhuEternalTomeSheet } from "./sheets/tome-sheet.mjs"

View File

@ -1,294 +0,0 @@
// System Module Imports
import { Utils } from './utils.js'
import { SYSTEM } from "../../config/system.mjs"
export let ActionHandler = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's ActionHandler class and builds system-defined actions for the HUD
*/
ActionHandler = class ActionHandler extends coreModule.api.ActionHandler {
/**
* Build system actions
* Called by Token Action HUD Core
* @override
* @param {array} groupIds
*/
async buildSystemActions(groupIds) {
// Set actor and token variables
this.actors = (!this.actor) ? this._getActors() : [this.actor]
this.actorType = this.actor?.type
// Set items variable
if (this.actor) {
let items = this.actor.items
items = coreModule.api.Utils.sortItemsByName(items)
this.items = items
}
if (this.actorType !== 'vehicle') {
this.#buildCharacterActions()
} else if (!this.actor) {
this.#buildMultipleTokenActions()
}
}
/**
* Build character actions
* @private
*/
#buildCharacterActions() {
this.buildAttributes()
this.buildOther()
this.buildLuck()
this.buildSkills()
this.buildEquipment()
}
#showValue() {
return game.settings.get('token-action-hud-core', 'tooltips') === 'none'
}
async buildAttributes() {
const actions = []
for (const key in this.actor.system.characteristics) {
const encodedValue = [coreModule.api.Utils.i18n('attributes'), 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),
id: key,
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue
})
}
await this.addActions(actions, {
id: 'attributes',
type: 'system'
})
}
async buildLuck() {
const actions = []
const tooltip = {
content: '50',
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Luck'),
id: 'luck',
info1: this.#showValue() ? { text: '50' } : null,
tooltip,
encodedValue: ['attributes', 'luck'].join(this.delimiter)
})
await this.addActions(actions, { id: 'luck', type: 'system' })
}
async buildOther() {
if (typeof this.actor.system.sanity.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_sanity',
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),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
id: 'sanity',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'sanity'].join(this.delimiter)
},
{
name: '+',
id: 'sanity_add',
encodedValue: ['attributes', 'sanity_add'].join(this.delimiter)
},
{
name: '-',
id: 'sanity_subtract',
encodedValue: ['attributes', 'sanity_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_sanity', type: 'system' })
}
if (typeof this.actor.system.hp.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_health',
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),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
id: 'health',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'health'].join(this.delimiter)
},
{
name: '+',
id: 'health_add',
encodedValue: ['attributes', 'health_add'].join(this.delimiter)
},
{
name: '-',
id: 'health_subtract',
encodedValue: ['attributes', 'health_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_health', type: 'system' })
}
if (typeof this.actor.system.wp.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_wp',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'),
type: 'system'
}
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
const tooltip = {
content: String(this.actor.system.wp.value + '/' + this.actor.system.wp.max),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'),
id: 'wp',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'wp'].join(this.delimiter)
},
{
name: '+',
id: 'wp_add',
encodedValue: ['attributes', 'wp_add'].join(this.delimiter)
},
{
name: '-',
id: 'wp_subtract',
encodedValue: ['attributes', 'wp_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_wp', type: 'system' })
}
}
async buildSkills() {
const actions = []
let actorSkills = this.actor.items.filter(item => item.type === 'skill')
for (const skill in actorSkills) {
if (skill.system.computeScore() > 0) {
const tooltip = {
content: String(skill.skill.system.computeScore()),
direction: 'LEFT'
}
actions.push({
name: skill.name,
id: skill.id,
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['skills', s].join(this.delimiter)
})
}
}
await this.addActions(actions, { id: 'skills', type: 'system' })
}
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) {
// Push the weapon name as a new group
const groupData = {
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 = []
const tooltip = {
content: String(skill.system.computeScore()),
direction: 'LEFT'
}
weapons.push({
name: skill.name,
id: skill._id,
info1: this.#showValue() ? { text: tooltip.content } : null,
encodedValue: ['weapons', item._id].join(this.delimiter),
tooltip
})
const damageTooltip = {
content: String(item.system.damage),
direction: 'LEFT'
}
if (item.system.damage !== '') {
weapons.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage'),
id: 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
})
}
await this.addActions(weapons, {
id: 'weapons_' + item._id,
type: 'system'
})
}/* else if (item.type === 'ritual') {
rituals.push({
name: item.name,
id: item._id,
encodedValue: ['rituals', item.name].join(this.delimiter)
})
} */
/* await this.addActions(rituals, {
id: 'rituals',
type: 'system'
}) */
}
}
/**
* Build multiple token actions
* @private
* @returns {object}
*/
#buildMultipleTokenActions() {
}
}
})

View File

@ -1,38 +0,0 @@
/**
* Module-based constants
*/
export const SYSTEM = {
ID: 'fvtt-cthulhu-eternal'
}
/**
* Core module
*/
export const CORE_MODULE = {
ID: 'token-action-hud-core'
}
/**
* Core module version required by the system module
*/
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'
}
/**
* 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' }
}

View File

@ -1,49 +0,0 @@
import { GROUP } from './constants.js'
/**
* Default layout and groups
*/
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
}
})

View File

@ -1,304 +0,0 @@
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 {
/**
* 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('|')
const knownCharacters = ['character']
// 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))
// 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
}
}
}
})

View File

@ -1,91 +0,0 @@
// System Module Imports
import { ActionHandler } from './action-handler.js'
import { RollHandler as Core } from './roll-handler.js'
import { SYSTEM } from './constants.js'
import { DEFAULTS } from './defaults.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 {
/**
* 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
}
}
}
}
})

View File

@ -1,55 +0,0 @@
import { SYSTEM } 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
*/
Utils = class Utils {
/**
* Get setting
* @param {string} key The key
* @param {string=null} defaultValue The default value
* @returns {string} The setting value
*/
static getSetting(key, defaultValue = null) {
let value = defaultValue ?? null
try {
value = game.settings.get(SYSTEM.ID, key)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
return value
}
/**
* Set setting
* @param {string} key The key
* @param {string} value The value
*/
static async setSetting(key, value) {
try {
value = await game.settings.set(MODULE.ID, key, value)
coreModule.api.Logger.debug(`Setting '${key}' set to '${value}'`)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
}
}
})

View File

@ -96,6 +96,7 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
drop: this._canDragDrop.bind(this),
}
d.callbacks = {
dragstart: this._onDragStart.bind(this),
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this),
}
@ -132,6 +133,70 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
return true //this.isEditable && this.document.isOwner
}
/**
* Callback actions which occur at the beginning of a drag start workflow.
* @param {DragEvent} event The originating DragEvent
* @protected
*/
_onDragStart(event) {
if ("link" in event.target.dataset) return
const el = event.currentTarget.closest('[data-drag="true"]')
const dragType = el.dataset.dragType
let dragData = {}
let target
switch (dragType) {
case "save":
target = event.currentTarget.querySelector("input")
dragData = {
actorId: this.document.id,
type: "roll",
rollType: target.dataset.rollType,
rollTarget: target.dataset.rollTarget,
value: target.value,
}
break
case "resource":
target = event.currentTarget.querySelector("select")
dragData = {
actorId: this.document.id,
type: "roll",
rollType: target.dataset.rollType,
rollTarget: target.dataset.rollTarget,
value: target.value,
}
break
case "damage":
dragData = {
actorId: this.document.id,
type: "rollDamage",
rollType: el.dataset.dragType,
rollTarget: el.dataset.itemId,
}
break
case "attack":
dragData = {
actorId: this.document.id,
type: "rollAttack",
rollValue: el.dataset.rollValue,
rollTarget: el.dataset.rollTarget,
}
break
default:
// Handle other cases or do nothing
break
}
// Extract the data you need
if (!dragData) return
// Set data transfer
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
}
/**
* Callback actions which occur when a dragged element is over a drop target.
* @param {DragEvent} event The originating DragEvent

View File

@ -1,175 +0,0 @@
import CthulhuEternalActorSheet from "./base-actor-sheet.mjs"
export default class CthulhuEternalCreatureSheet extends CthulhuEternalActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["creature"],
position: {
width: 860,
height: 620,
},
window: {
contentClasses: ["creature-content"],
},
actions: {
createArmor: CthulhuEternalCreatureSheet.#onCreateArmor,
createWeapon: CthulhuEternalCreatureSheet.#onCreateWeapon,
createSkill: CthulhuEternalCreatureSheet.#onCreateSkill,
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-main.hbs",
},
tabs: {
template: "templates/generic/tab-navigation.hbs",
},
skills: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-skills.hbs",
},
biography: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-biography.hbs",
},
}
/** @override */
tabGroups = {
sheet: "skills",
}
/**
* Prepare an array of form header tabs.
* @returns {Record<string, Partial<ApplicationTab>>}
*/
#getTabs() {
const tabs = {
skills: { id: "skills", group: "sheet", icon: "fa-solid fa-shapes", label: "CTHULHUETERNAL.Label.skills" },
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "CTHULHUETERNAL.Label.biography" },
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
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.tooltipsCharacteristic = {
str: game.i18n.localize("CTHULHUETERNAL.Characteristic.Str"),
dex: game.i18n.localize("CTHULHUETERNAL.Characteristic.Dex"),
con: game.i18n.localize("CTHULHUETERNAL.Characteristic.Con"),
int: game.i18n.localize("CTHULHUETERNAL.Characteristic.Int"),
pow: game.i18n.localize("CTHULHUETERNAL.Characteristic.Pow"),
cha: game.i18n.localize("CTHULHUETERNAL.Characteristic.Cha")
}
return context
}
/** @override */
async _preparePartContext(partId, context) {
const doc = this.document
switch (partId) {
case "main":
break
case "skills":
context.tab = context.tabs.skills
context.skills = doc.itemTypes.skill
context.skills.sort((a, b) => a.name.localeCompare(b.name))
context.weapons = doc.itemTypes.weapon
context.weapons.sort((a, b) => a.name.localeCompare(b.name))
context.armors = doc.itemTypes.armor
context.armors.sort((a, b) => a.name.localeCompare(b.name))
break
case "biography":
context.tab = context.tabs.biography
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
break
}
return context
}
/**
* Creates a new attack item directly from the sheet and embeds it into the document.
* @param {Event} event The initiating click event.
* @param {HTMLElement} target The current target of the event listener.
*/
static #onCreateWeapon(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newWeapon"), type: "weapon" }])
}
static #onCreateArmor(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newArmor"), type: "armor" }])
}
static #onCreateSkill(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newSkill"), type: "skill" }])
}
/**
* Handles the roll action triggered by user interaction.
*
* @param {PointerEvent} event The event object representing the user interaction.
* @param {HTMLElement} target The target element that triggered the roll.
*
* @returns {Promise<void>} A promise that resolves when the roll action is complete.
*
* @throws {Error} Throws an error if the roll type is not recognized.
*
* @description This method checks the current mode (edit or not) and determines the type of roll
* (save, resource, or damage) based on the target element's data attributes. It retrieves the
* corresponding value from the document's system and performs the roll.
*/
async _onRoll(event, target) {
const rollType = $(event.currentTarget).data("roll-type")
let item
let li
// Debug : console.log(">>>>", event, target, rollType)
// Deprecated : if (this.isEditMode) return
switch (rollType) {
case "char":
let charId = $(event.currentTarget).data("char-id")
item = foundry.utils.duplicate(this.actor.system.characteristics[charId])
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.${charId}Long`)
item.targetScore = item.value * 5
break
case "skill":
li = $(event.currentTarget).parents(".item");
item = this.actor.items.get(li.data("item-id"));
break
case "weapon":
case "damage":
li = $(event.currentTarget).parents(".item");
item = this.actor.items.get(li.data("item-id"));
item.damageBonus = this.actor.system.damageBonus
break
default:
throw new Error(`Unknown roll type ${rollType}`)
}
await this.document.system.roll(rollType, item)
}
async _onDrop(event) {
if (!this.isEditable || !this.isEditMode) return
const data = TextEditor.getDragEventData(event)
// Handle different data types
switch (data.type) {
case "Item":
const item = await fromUuid(data.uuid)
return super._onDropItem(item)
}
}
}

View File

@ -20,9 +20,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
createInjury: CthulhuEternalProtagonistSheet.#onCreateInjury,
createMentalDisorder: CthulhuEternalProtagonistSheet.#onCreateMentalDisorder,
createMotivation: CthulhuEternalProtagonistSheet.#onCreateMotivation,
createSkill: CthulhuEternalProtagonistSheet.#onCreateSkill,
createRitual: CthulhuEternalProtagonistSheet.#onCreateRitual,
createTome: CthulhuEternalProtagonistSheet.#onCreateTome,
createSkill: CthulhuEternalProtagonistSheet.#onCreateSkill
},
}
@ -110,10 +108,6 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
context.armors.sort((a, b) => a.name.localeCompare(b.name))
context.gears = doc.itemTypes.gear
context.gears.sort((a, b) => a.name.localeCompare(b.name))
context.rituals = doc.itemTypes.ritual
context.rituals.sort((a, b) => a.name.localeCompare(b.name))
context.tomes = doc.itemTypes.tome
context.tomes.sort((a, b) => a.name.localeCompare(b.name))
break
case "status":
context.tab = context.tabs.status
@ -121,13 +115,13 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
context.injuries.sort((a, b) => a.name.localeCompare(b.name))
context.mentaldisorders = doc.itemTypes.mentaldisorder
context.mentaldisorders.sort((a, b) => a.name.localeCompare(b.name))
context.motivations = doc.itemTypes.motivation
context.motivations.sort((a, b) => a.name.localeCompare(b.name))
context.bonds = doc.itemTypes.bond
context.bonds.sort((a, b) => a.name.localeCompare(b.name))
break
case "biography":
context.tab = context.tabs.biography
context.motivations = doc.itemTypes.motivation
context.motivations.sort((a, b) => a.name.localeCompare(b.name))
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
break
@ -176,14 +170,6 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newSkill"), type: "skill" }])
}
static #onCreateRitual(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newRitual"), type: "ritual" }])
}
static #onCreateTome(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newTome"), type: "tome" }])
}
/**
* Handles the roll action triggered by user interaction.
*
@ -224,7 +210,6 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
case "damage":
li = $(event.currentTarget).parents(".item");
item = this.actor.items.get(li.data("item-id"));
item.damageBonus = this.actor.system.damageBonus
break
case "san":
item = foundry.utils.duplicate(this.actor.system.san)
@ -249,4 +234,5 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
}
}
// #endregion
}

View File

@ -1,28 +0,0 @@
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
export default class CthulhuEternalRitualSheet extends CthulhuEternalItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["ritual"],
position: {
width: 600,
},
window: {
contentClasses: ["ritual-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/ritual.hbs",
},
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -1,28 +0,0 @@
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
export default class CthulhuEternalTomeSheet extends CthulhuEternalItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["tome"],
position: {
width: 600,
},
window: {
contentClasses: ["tome-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/tome.hbs",
},
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -1,6 +1,6 @@
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
import LethalFantasyItemSheet from "./base-item-sheet.mjs"
export default class CthulhuEternalWeaponSheet extends CthulhuEternalItemSheet {
export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["weapon"],

View File

@ -42,18 +42,18 @@ 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: "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", 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.25rem",titleFontSize: "1.5rem",imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
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%)" },
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%)" },
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%)" },
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%)" },
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%)"},
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%)" },
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%)"},
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%)"},
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%)"},
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%)" },
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%)" },
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%))" }
}
export const RESOURCE_RATING = {
@ -113,8 +113,6 @@ export const RESOURCE_BREAKDOWN = [
{ 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 VEHICLE_SPEED = {
"none": "CTHULHUETERNAL.Label.None",
"slow": "CTHULHUETERNAL.Label.Slow",
@ -142,13 +140,6 @@ export const WEAPON_SKILL_MAPPING = {
"rangedfirearm": "CTHULHUETERNAL.Skill.Firearms",
"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: {
"melee": "CTHULHUETERNAL.Skill.Melee",
"rangedprimitive": "CTHULHUETERNAL.Skill.Firearms",
@ -220,9 +211,9 @@ export const WEAPON_SKILL_MAPPING = {
}
export const MODIFIER_CHOICES = {
"-40": "-40",
"-20": "-20",
"-10": "-10",
"-20": "-20",
"-40": "-40",
"+0": "+0",
"+10": "+10",
"+20": "+20",
@ -238,12 +229,6 @@ export const MULTIPLIER_CHOICES = {
"5": "5"
}
export const RITUAL_TYPES = {
"simple": "CTHULHUETERNAL.Ritual.Simple",
"complex": "CTHULHUETERNAL.Ritual.Complex",
"elaborate": "CTHULHUETERNAL.Ritual.Elaborate"
}
/**
* Include all constant definitions within the SYSTEM global export
* @type {Object}
@ -266,7 +251,5 @@ export const SYSTEM = {
VEHICLE_SPEED,
MODIFIER_CHOICES,
MULTIPLIER_CHOICES,
ASCII,
DAMAGE_BONUS,
RITUAL_TYPES
ASCII
}

View File

@ -23,8 +23,6 @@ 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" } })
}
return super.create(data, options);
@ -54,13 +52,6 @@ export default class CthulhuEternalActor extends Actor {
continue
}
}
if (i.type === "bond") {
if (i.system.bondType === "individual") {
i.system.value = this.system.characteristics.cha.value
} else {
i.system.value = Math.floor(this.system.resources.permanentRating / 2)
}
}
newData.push(i)
}
return super.createEmbeddedDocuments(embeddedName, newData, operation)

View File

@ -1,7 +1,7 @@
export const defaultItemImg = {
weapon: "systems/fvtt-cthulhu-eternal/assets/icons/icon_weapon.svg",
armor: "systems/fvtt-cthulhu-eternal/assets/icons/icon_armor.svg",
gear: "systems/fvtt-cthulhu-eternal/assets/icons/icon_equipment.svg",
gear: "systems/fvtt-cthulhu-eternal/assets/icons/icon_gear.svg",
skill: "systems/fvtt-cthulhu-eternal/assets/icons/icon_skill.svg",
archetype: "systems/fvtt-cthulhu-eternal/assets/icons/icon_archetype.svg",
bond: "systems/fvtt-cthulhu-eternal/assets/icons/icon_bond.svg",
@ -9,8 +9,6 @@ export const defaultItemImg = {
arcane: "systems/fvtt-cthulhu-eternal/assets/icons/icon_arcane.svg",
injury: "systems/fvtt-cthulhu-eternal/assets/icons/icon_injury.svg",
motivation: "systems/fvtt-cthulhu-eternal/assets/icons/icon_motivation.svg",
ritual: "systems/fvtt-cthulhu-eternal/assets/icons/icon_ritual.svg",
tome: "systems/fvtt-cthulhu-eternal/assets/icons/icon_tome.svg",
}
export default class CthulhuEternalItem extends Item {

View File

@ -1,6 +1,5 @@
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalRoll extends Roll {
/**
* The HTML template path used to render dice checks of this type
@ -80,14 +79,6 @@ export default class CthulhuEternalRoll extends Roll {
return this.options.isExhausted
}
get isNudgedRoll() {
return this.options.isNudgedRoll
}
get wpCost() {
return this.options.wpCost
}
static updateResourceDialog(options) {
let rating = 0
if (options.rollItem.enableHand) {
@ -122,8 +113,7 @@ export default class CthulhuEternalRoll extends Roll {
static async prompt(options = {}) {
let formula = "1d100"
let hasModifier = true
let hasMultiplier = false
options.isNudge = true
let hasMultiplier = false
switch (options.rollType) {
case "skill":
@ -133,7 +123,6 @@ export default class CthulhuEternalRoll extends Roll {
case "san":
case "char":
options.initialScore = options.rollItem.targetScore
options.isNudge = (options.rollType !== "san")
break
case "resource":
hasModifier = false
@ -144,20 +133,15 @@ export default class CthulhuEternalRoll extends Roll {
options.rollItem.enableHand = true
options.rollItem.enableStowed = true
options.rollItem.enableStorage = true
options.isNudge = false
break
case "damage":
let formula = options.rollItem.system.damage
if ( options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") {
formula += ` + ${options.rollItem.damageBonus}`
}
let damageRoll = new Roll(formula)
await damageRoll.evaluate()
await damageRoll.toMessage({
flavor: `${options.rollItem.name} - Damage Roll`
});
let isLethal = false
options.isNudge = false
if (options.rollItem.system.lethality > 0) {
let lethalityRoll = new Roll("1d100")
await lethalityRoll.evaluate()
@ -169,32 +153,20 @@ export default class CthulhuEternalRoll extends Roll {
return
case "weapon":
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]) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType"))
console.log("WP Not found", era, options.rollItem.system.weaponType)
return
}
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
let actor = game.actors.get(options.actorId)
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])
let actor = game.actors.get(options.actorId)
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 = 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)
break
default:
options.initialScore = 50
@ -275,7 +247,7 @@ export default class CthulhuEternalRoll extends Roll {
render: (event, dialog) => {
$(".roll-skill-multiplier").change(event => {
options.multiplier = Number(event.target.value)
this.updateResourceDialog(options)
this.updateResourceDialog(options)
})
}
})
@ -287,10 +259,10 @@ export default class CthulhuEternalRoll extends Roll {
rollData.rollMode = rollContext.visibility
// Update target score
console.log("Rolldata", rollData, options)
if (options.rollType === "resource") {
console.log(rollData)
if (options.rollType === "resource" ) {
rollData.targetScore = options.initialScore * Number(rollContext.multiplier)
} else {
} else {
rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100)
if (rollData.isLowWP || rollData.isExhausted) {
rollData.targetScore -= 20
@ -298,54 +270,48 @@ export default class CthulhuEternalRoll extends Roll {
if (rollData.isZeroWP) {
rollData.targetScore = 0
}
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
const roll = new this(formula, options.data, rollData)
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
let resultType = "failure"
let dec = Math.floor(this.total / 10)
let unit = this.total - (dec * 10)
if (this.total <= rollData.targetScore) {
let dec = Math.floor(roll.total / 10)
let unit = roll.total - (dec * 10)
if (roll.total <= rollData.targetScore) {
resultType = "success"
// Detect if decimal == unit in the dire total result
if (dec === unit || this.total === 1) {
if (dec === unit || roll.total === 1) {
resultType = "successCritical"
}
} else {
// Detect if decimal == unit in the dire total result
if (dec === unit || this.total === 100) {
if (dec === unit || roll.total === 100) {
resultType = "failureCritical"
}
}
this.options.resultType = resultType
if (this.options.isNudgedRoll) {
this.options.isSuccess = resultType === "success" || resultType === "successCritical"
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
this.options.isCritical = false
} else {
this.options.isSuccess = resultType === "success" || resultType === "successCritical"
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
}
this.options.isLowWP = rollData.isLowWP
this.options.isZeroWP = rollData.isZeroWP
this.options.isExhausted = rollData.isExhausted
this.options.rollData = foundry.utils.duplicate(rollData)
roll.options.resultType = resultType
roll.options.isSuccess = resultType === "success" || resultType === "successCritical"
roll.options.isFailure = resultType === "failure" || resultType === "failureCritical"
roll.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
roll.options.isLowWP = rollData.isLowWP
roll.options.isZeroWP = rollData.isZeroWP
roll.options.isExhausted = rollData.isExhausted
/**
* A hook event that fires after the roll has been made.
*/
if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return
return roll
}
/**
@ -421,8 +387,9 @@ export default class CthulhuEternalRoll extends Roll {
cardData.isLowWP = this.isLowWP
cardData.isZeroWP = this.isZeroWP
cardData.isExhausted = this.isExhausted
cardData.isNudgedRoll = this.isNudgedRoll
cardData.wpCost = this.wpCost
console.log(cardData)
cardData.cssClass = cardData.css.join(" ")
cardData.tooltip = isPrivate ? "" : await this.getTooltip()

View File

@ -9,8 +9,5 @@ export { default as CthulhuEternalBond } from "./bond.mjs"
export { default as CthulhuEternalGear } from "./gear.mjs"
export { default as CthulhuEternalMotivation } from "./motivation.mjs"
export { default as CthulhuEternalArchetype } from "./archetype.mjs"
export { default as CthulhuEternalRitual } from "./ritual.mjs"
export { default as CthulhuEternalVehicle } from "./vehicle.mjs"
export { default as CthulhuEternalCreature } from "./creature.mjs"
export { default as CthulhuEternalTome } from "./tome.mjs"

View File

@ -5,8 +5,7 @@ export default class CthulhuEternalArchetype extends foundry.abstract.TypeDataMo
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
schema.description = new fields.HTMLField({
required: false,
@ -20,5 +19,4 @@ export default class CthulhuEternalArchetype extends foundry.abstract.TypeDataMo
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Archetype"]
}

View File

@ -6,10 +6,7 @@ export default class CthulhuEternalArmor extends foundry.abstract.TypeDataModel
const requiredInteger = { required: true, nullable: false, integer: true }
schema.description = new fields.HTMLField({ required: true, textSearch: true })
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
schema.protection = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })

View File

@ -1,80 +0,0 @@
import { SYSTEM } from "../config/system.mjs"
import CthulhuEternalRoll from "../documents/roll.mjs"
export default class CthulhuEternalCreature extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
// Carac
const characteristicField = (label) => {
const schema = {
value: new fields.NumberField({ ...requiredInteger, initial: 3, min: 0 }),
feature: new fields.StringField({ required: true, nullable: false, initial: "" })
}
return new fields.SchemaField(schema, { label })
}
schema.characteristics = new fields.SchemaField(
Object.values(SYSTEM.CHARACTERISTICS).reduce((obj, characteristic) => {
obj[characteristic.id] = characteristicField(characteristic.label)
return obj
}, {}),
)
schema.wp = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 3, min: 0 }),
exhausted: new fields.BooleanField({ required: true, initial: false })
})
schema.hp = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
})
schema.movement = new fields.StringField({ required: true, initial: "" })
schema.sanLoss = new fields.StringField({ required: true, initial: "1/1D6" })
schema.armor = new fields.StringField({ required: true, initial: "" })
schema.size = new fields.StringField({ required: true, initial: "medium", choices: SYSTEM.CREATURE_SIZE })
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.notes = new fields.HTMLField({ required: true, textSearch: true })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Creature"]
/** */
/**
* Rolls a dice for a character.
* @param {("save"|"resource|damage")} rollType The type of the roll.
* @param {number} rollItem The target value for the roll. Which caracteristic or resource. If the roll is a damage roll, this is the id of the item.
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
*/
async roll(rollType, rollItem) {
let opponentTarget
const hasTarget = opponentTarget !== undefined
let roll = await CthulhuEternalRoll.prompt({
rollType,
rollItem,
isLowWP: false,
isZeroWP: false,
isExhausted: false,
actorId: this.parent.id,
actorName: this.parent.name,
actorImage: this.parent.img,
hasTarget,
target: opponentTarget
})
if (!roll) return null
await roll.toMessage({}, { rollMode: roll.options.rollMode })
}
}

View File

@ -7,10 +7,7 @@ export default class CthulhuEternalGHear extends foundry.abstract.TypeDataModel
const requiredInteger = { required: true, nullable: false, integer: true }
schema.description = new fields.HTMLField({ required: true, textSearch: true })
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES })

View File

@ -165,6 +165,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
}
}
isLowWP() {
return this.wp.value <= 2
}
@ -177,17 +178,6 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
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() {
let updates = {}
let bp = Math.max(this.san.value - this.characteristics.pow.value, 0)

View File

@ -1,24 +0,0 @@
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalRitual extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
schema.ritualType = new fields.StringField({ required: true, initial: "simple", choices: SYSTEM.RITUAL_TYPES })
schema.studyTime = new fields.StringField({ required: true, initial: "X days", textSearch: true })
schema.studySAN = new fields.StringField({ required: true, initial: "1d4", textSearch: true })
schema.activationTime = new fields.StringField({ required: true, initial: "X turns", textSearch: true })
schema.activationWP = new fields.StringField({ required: true, initial: "1d4", textSearch: true })
schema.activationSAN = new fields.StringField({ required: true, initial: "1d6", textSearch: true })
schema.description = new fields.HTMLField({ required: true, textSearch: true })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Ritual"]
}

View File

@ -6,9 +6,7 @@ export default class CthulhuEternalSkill extends foundry.abstract.TypeDataModel
const requiredInteger = { required: true, nullable: false, integer: true }
schema.description = new fields.HTMLField({ required: true, textSearch: true })
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
schema.base = new fields.StringField({ required: true, initial: "0" })
schema.bonus = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })

View File

@ -1,64 +0,0 @@
import { SYSTEM } from "../config/system.mjs";
export default class CthulhuEternalTome extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
const schema = {};
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.minimumEra = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.creationDate = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
// Language field
schema.language = new fields.StringField({
required: true,
initial: "Latin",
textSearch: true
});
// studyTime field
schema.studyTime = new fields.StringField({
required: true,
initial: "X days",
textSearch: true
});
// SAN loss field
schema.sanLoss = new fields.StringField({
required: true,
initial: "1d4",
textSearch: true
});
// Unnatural skill field
schema.unnaturalSkill = new fields.StringField({
required: true,
initial: "1d4",
textSearch: true
});
schema.rituals = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
schema.otherBenefits = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
schema.description = new fields.HTMLField({ required: true, textSearch: true })
return schema;
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Tome"];
}

View File

@ -7,8 +7,7 @@ export default class CthulhuEternalVehicle extends foundry.abstract.TypeDataMode
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
schema.hp = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),

View File

@ -1,20 +1,15 @@
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel {
export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const schema = {}
const requiredInteger = { required: true, nullable: false, integer: true }
schema.description = new fields.HTMLField({ required: true, textSearch: true })
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
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.damage = new fields.StringField({required: true, initial: "1d6"})
schema.baseRange = new fields.StringField({required: true, initial: ""})
schema.rangeUnit = new fields.StringField({ required: true, initial: "yard", choices: SYSTEM.WEAPON_RANGE_UNIT })

View File

@ -1,8 +1,4 @@
import CthulhuEternalRoll from "./documents/roll.mjs"
import { SystemManager } from './applications/hud/system-manager.js'
import { SYSTEM } from "./config/system.mjs"
export default class CthulhuEternalUtils {
static registerSettings() {
@ -181,82 +177,12 @@ 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() {
const era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
let eraCSS = SYSTEM.ERA_CSS[era];
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-secondary', eraCSS.secondaryFont);
document.documentElement.style.setProperty('--font-title', eraCSS.titleFont);

View File

@ -1 +1 @@
MANIFEST-000140
MANIFEST-000076

View File

@ -1,8 +1,8 @@
2025/02/09-18:56:19.542927 7f46adffb6c0 Recovering log #138
2025/02/09-18:56:19.597959 7f46adffb6c0 Delete type=3 #136
2025/02/09-18:56:19.598032 7f46adffb6c0 Delete type=0 #138
2025/02/09-19:16:45.192949 7f46abbff6c0 Level-0 table #143: started
2025/02/09-19:16:45.192979 7f46abbff6c0 Level-0 table #143: 0 bytes OK
2025/02/09-19:16:45.199734 7f46abbff6c0 Delete type=0 #141
2025/02/09-19:16:45.210582 7f46abbff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/02/09-19:16:45.220994 7f46abbff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/01/25-20:17:02.992814 7f697a7fc6c0 Recovering log #74
2025/01/25-20:17:03.002900 7f697a7fc6c0 Delete type=3 #72
2025/01/25-20:17:03.002968 7f697a7fc6c0 Delete type=0 #74
2025/01/25-20:19:31.386247 7f6978bff6c0 Level-0 table #79: started
2025/01/25-20:19:31.386288 7f6978bff6c0 Level-0 table #79: 0 bytes OK
2025/01/25-20:19:31.417028 7f6978bff6c0 Delete type=0 #77
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/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)

View File

@ -1,8 +1,8 @@
2025/02/09-18:43:17.595623 7f46ac7f86c0 Recovering log #134
2025/02/09-18:43:17.606503 7f46ac7f86c0 Delete type=3 #132
2025/02/09-18:43:17.606590 7f46ac7f86c0 Delete type=0 #134
2025/02/09-18:55:41.771958 7f46abbff6c0 Level-0 table #139: started
2025/02/09-18:55:41.772001 7f46abbff6c0 Level-0 table #139: 0 bytes OK
2025/02/09-18:55:41.779302 7f46abbff6c0 Delete type=0 #137
2025/02/09-18:55:41.793230 7f46abbff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/02/09-18:55:41.793270 7f46abbff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/01/25-20:09:49.585129 7f697a7fc6c0 Recovering log #70
2025/01/25-20:09:49.662901 7f697a7fc6c0 Delete type=3 #68
2025/01/25-20:09:49.662960 7f697a7fc6c0 Delete type=0 #70
2025/01/25-20:11:19.050068 7f6978bff6c0 Level-0 table #75: started
2025/01/25-20:11:19.050103 7f6978bff6c0 Level-0 table #75: 0 bytes OK
2025/01/25-20:11:19.078755 7f6978bff6c0 Delete type=0 #73
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/25-20:11:19.078946 7f6978bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

@ -1,644 +0,0 @@
.creature-content {
.sheet-common();
.creature-sheet-common();
overflow: scroll;
}
.sheet-tabs {
background-color: var(--color-light-1);
}
.creature-main {
background-color: var(--color-light-1);
display: flex;
.creature-pc {
display: flex;
gap: 4px;
flex: 1;
.creature-left {
min-width: 180px;
display: flex;
flex-direction: column;
.creature-left-image {
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 8px;
.creature-img {
height: 140px;
width: auto;
border: none;
}
}
.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 {
flex: none;
}
}
.creature-dmax-edit {
input {
display: flex;
width: 60px;
font-size: calc(var(--font-size-standard) * 1.4);
align-items: center;
justify-content: center;
padding: 0 5px 0 5px;
text-align: center;
}
}
}
.creature-right {
display: flex;
flex-direction: column;
gap: 5px;
.creature-name {
display: flex;
input {
font-family: var(--font-title);
font-size: var(--font-size-title);
width: 400px;
}
}
.san {
align-content: flex-start;
input {
min-width: 2.2rem;
max-width: 2.2rem;
margin-bottom: 4px;
}
select {
min-width: 6rem;
max-width: 6rem;
}
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
font-size: 0.9rem;
}
.button {
min-width: 4rem;
max-width: 4rem;
}
.san-checkbox {
min-width: 1rem;
max-width: 1rem;
}
.label-short-field {
font-size: 0.9rem;
max-width: 3rem;
min-width: 3rem;
flex-grow: 1;
}
.label-recovery {
margin-left: 4px;
}
.label-field {
font-size: 0.9rem;
max-width: 6rem;
min-width: 6rem;
flex-grow: 1;
}
.label-bp {
flex-grow: 1;
max-width: 3rem;
min-width: 3rem;
margin-left: 4px;
}
.label-insanity {
flex-grow: 1;
margin-left: 4px;
max-width: 8rem;
min-width: 8rem;
}
.spacing {
margin-left: 4px;
}
.d100 {
flex: 0;
}
}
.willpower {
input {
min-width: 2.4rem;
max-width: 2.4rem;
}
input[type="checkbox"] {
min-width: 1rem;
max-width: 1rem;
}
.label-field {
flex-grow: 1;
margin-left: 4px;
max-width: 5rem;
min-width: 5rem;
font-size: 0.9rem;
}
.checkbox {
flex-grow: 0;
min-width: 1rem;
max-width: 1rem;
}
}
label {
min-width: 120px;
}
}
}
.creature-pc-play {
min-width: 500px;
}
.creature-pc-edit {
min-width: 650px;
}
.creature-characteristics {
background-color: var(--color-light-1);
display: flex;
flex-direction: column;
gap: 5px;
flex: 1;
.creature-characteristic {
display: flex;
align-items: center;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.rollable {
min-width: 3rem;
max-width: 3rem;
}
.char-text {
margin-left: 0.5rem;
}
.d100 {
flex: 0;
max-width: 0.6rem;
}
.form-group {
flex: 0;
padding-left: 5px;
.form-fields {
font-size: 1.1rem;
flex: none;
width: 40px;
}
}
}
}
.creature-characteristic-play {
min-width: 225px;
}
.creature-characteristic-edit {
min-width: 400px;
}
}
.creature-biography {
background-color: var(--color-light-1);
prose-mirror.inactive {
min-height: 40px;
}
prose-mirror.active {
min-height: 150px;
}
.field-label {
margin-left: 8px;
}
.adapted {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
label {
min-width: 20rem;
}
}
.resources {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
label {
min-width: 8rem;
}
}
.features,
.biodata {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
label {
min-width: 3rem;
}
.feature {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
}
}
}
.tab.creature-skills {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.armors {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.armor {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.protection {
min-width: 5rem;
max-width: 5rem;
}
.name {
min-width: 8rem;
max-width: 8rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.weapons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.weapon {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.damage {
min-width: 6rem;
max-width: 6rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.skills {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.skill {
display: flex;
align-items: center;
gap: 4px;
margin-left: 4px;
min-width: 12.3rem;
max-width: 12.3rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.score {
min-width: 1.2rem;
max-width: 1.2rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.creature-status {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.bonds {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.bond {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.type {
min-width: 6rem;
max-width: 6rem;
}
.level {
min-width: 2rem;
max-width: 2rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.motivations {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.motivation {
display: flex;
align-items: center;
gap: 4px;
min-width: 14rem;
max-width: 14rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.mentaldisorders {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.mentaldisorder {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
max-width: 14rem;
}
.cured {
min-width: 5rem;
max-width: 5rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.injuries {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.injury {
display: flex;
align-items: center;
gap: 4px;
min-width: 16rem;
max-width: 16rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
max-width: 14rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.creature-equipment {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.gears {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.gear {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.rituals {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.ritual {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.tomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.tome {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
prose-mirror.inactive {
min-height: 40px;
}
prose-mirror.active {
min-height: 150px;
}
}

View File

@ -44,19 +44,9 @@
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-family: "IMFell";
src: url("../assets/fonts/IMFeDPrm28P.ttf") format("truetype");
}
@font-face {
font-family: "SailRegular";
src: url("../assets/fonts/Sail-Regular.ttf") format("truetype");
src: url("../assets/fonts/IMFell.ttf") format("truetype");
}
@font-face {

View File

@ -5,7 +5,6 @@
@import "mixins.less";
@import "protagonist.less";
@import "vehicle.less";
@import "creature.less";
@import "skill.less";
@import "injury.less";
@import "weapon.less";
@ -17,8 +16,6 @@
@import "gear.less";
@import "arcane.less";
@import "archetype.less";
@import "ritual.less";
@import "tome.less";
}
@import "roll.less";

View File

@ -1,13 +1,13 @@
:root {
--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: url("../assets/ui/jazzage_background_main.webp");*/
--font-primary: "RozhaOne";
--font-secondary: "RozhaOne";
--font-title: "Broadway";
--logo-standard: url("../assets/logos/reanimated-ce-logo.webp");
--color-success: rgb(15, 122, 15);
--color-success: rgb(18, 233, 18);
--color-failure: darkred;
--color-warning: darkorange;
--color-critical-success: rgb(21, 39, 204);

View File

@ -68,13 +68,6 @@
}
}
.creature-sheet-common {
label {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.0);
}
}
.item-sheet-common {
.form-fields {
padding-top: 4px;

View File

@ -34,25 +34,6 @@
}
}
.protagonist-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;
}
}
.protagonist-dv,
.protagonist-dmax {
.form-fields {
@ -81,7 +62,7 @@
display: flex;
input {
font-family: var(--font-title);
font-size: var(--font-size-title);
font-size: calc(var(--font-size-standard) * 1.4);
width: 400px;
}
}
@ -101,7 +82,7 @@
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
font-size: 0.9rem;
}
}
.button {
min-width: 4rem;
max-width: 4rem;
@ -160,14 +141,54 @@
min-width: 5rem;
font-size: 0.9rem;
}
.checkbox {
.checkbox {
flex-grow: 0;
min-width: 1rem;
max-width: 1rem;
}
}
label {
min-width: 120px;
.protagonist-infos {
display: flex;
flex-direction: column;
gap: 4px;
label {
min-width: 120px;
}
.protagonist-hp {
display: flex;
gap: 2px;
align-items: center;
.protagonist-hp-value {
.form-fields input {
flex: none;
width: 50px;
margin-left: 4px;
font-size: calc(var(--font-size-standard) * 1.4);
}
}
.protagonist-hp-max {
clear: both;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 3px 0;
align-items: center;
input {
width: 50px;
text-align: center;
font-size: calc(var(--font-size-standard) * 1.4);
}
}
.hp-separator {
font-size: calc(var(--font-size-standard) * 1.2);
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
}
@ -202,10 +223,6 @@
.char-text {
margin-left: 0.5rem;
}
.d100 {
flex: 0;
max-width: 0.6rem;
}
.form-group {
flex: 0;
padding-left: 5px;
@ -238,7 +255,7 @@
.field-label {
margin-left: 8px;
}
.adapted {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -247,7 +264,7 @@
min-width: 20rem;
}
}
.resources {
display: grid;
grid-template-columns: repeat(3, 1fr);
@ -263,14 +280,40 @@
grid-template-columns: repeat(2, 1fr);
gap: 8px;
label {
min-width: 3rem;
min-width: 3.0rem;
}
.feature {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
}
}
.motivations {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.motivation {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
min-width: 14rem;
max-width: 14rem;
.controls {
min-width: 2rem;
max-width: 2rem;
}
.name {
min-width: 8rem;
max-width: 8rem;
}
.item-img {
width: 32px;
height: 32px;
margin: 4px 0 0 0;
}
}
}
}
@ -293,26 +336,20 @@
display: flex;
align-items: center;
gap: 4px;
margin-left: 4px;
min-width: 12.3rem;
max-width: 12.3rem;
min-width: 10rem;
max-width: 10rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.score {
min-width: 1.2rem;
max-width: 1.2rem;
min-width: 2rem;
max-width: 2rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
min-width: 8rem;
max-width: 8rem;
}
.item-img {
width: 24px;
@ -333,7 +370,6 @@
padding-left: 5px;
}
}
.bonds {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -342,20 +378,19 @@
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
min-width: 16rem;
max-width: 16rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.type {
min-width: 6rem;
max-width: 6rem;
min-width: 5rem;
max-width: 5rem;
}
.level {
min-width: 2rem;
@ -368,34 +403,6 @@
}
}
}
.motivations {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.motivation {
display: flex;
align-items: center;
gap: 4px;
min-width: 14rem;
max-width: 14rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.mentaldisorders {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -404,21 +411,16 @@
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
min-width: 16rem;
max-width: 16rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.name {
min-width: 14rem;
max-width: 14rem;
}
.cured {
min-width: 5rem;
max-width: 5rem;
}
.item-img {
width: 24px;
height: 24px;
@ -426,7 +428,6 @@
}
}
}
.injuries {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -438,9 +439,8 @@
min-width: 16rem;
max-width: 16rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.name {
min-width: 14rem;
@ -481,9 +481,8 @@
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.damage {
min-width: 6rem;
@ -509,16 +508,15 @@
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
max-width: 13srem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.protection {
min-width: 5rem;
@ -535,7 +533,6 @@
}
}
}
.gears {
display: grid;
grid-template-columns: repeat(3, 1fr);
@ -545,84 +542,23 @@
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
max-width: 13srem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
min-width: 2rem;
max-width: 2rem;
}
.damage {
min-width: 5rem;
max-width: 5rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.rituals {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.ritual {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.tomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.tome {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
min-width: 8rem;
max-width: 8rem;
}
.item-img {
width: 24px;

View File

@ -1,22 +0,0 @@
.ritual-content {
.sheet-common();
.item-sheet-common();
fieldset {
margin-top: 8px;
background-color: var(--color-light-1);
}
.header {
background-color: var(--color-light-1);
display: flex;
img {
width: 50px;
height: 50px;
}
}
label {
flex: 10%;
}
}

View File

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

View File

@ -1,22 +0,0 @@
.tome-content {
.sheet-common();
.item-sheet-common();
fieldset {
margin-top: 8px;
background-color: var(--color-light-1);
}
.header {
background-color: var(--color-light-1);
display: flex;
img {
width: 50px;
height: 50px;
}
}
label {
flex: 10%;
}
}

View File

@ -6,7 +6,7 @@
"download": "#{DOWNLOAD}#",
"url": "https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal",
"license": "LICENSE",
"version": "12.0.5",
"version": "12.0.4",
"authors": [
{
"name": "Uberwald",
@ -35,8 +35,7 @@
"documentTypes": {
"Actor": {
"protagonist": { "htmlFields": ["description", "notes"] },
"vehicle": { "htmlFields": ["description", "notes"] },
"creature": { "htmlFields": ["description", "notes"] }
"vehicle": { "htmlFields": ["description", "notes"] }
},
"Item": {
"skill": { "htmlFields": ["description"] },
@ -48,9 +47,7 @@
"motivation": { "htmlFields": ["description"] },
"arcane": { "htmlFields": ["description"] },
"gear": { "htmlFields": ["description"] },
"archetype": { "htmlFields": ["description"] },
"ritual": { "htmlFields": ["description"] },
"tome": { "htmlFields": ["description"] }
"archetype": { "htmlFields": ["description"] }
}
},
"packs": [

View File

@ -14,10 +14,6 @@
<li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li>
{{/if}}
{{#if isNudgedRoll}}
<li><strong>{{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} WP spent</strong></li>
{{/if}}
{{#if weapon}}
<li><strong>Weapon : {{weapon.name}}</strong></li>
{{/if}}
@ -51,24 +47,14 @@
{{#if isCritical}}
<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"><i class="fa-solid fa-circle-sort-down"></i></a>
{{/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"}}</li>
{{else}}
<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>
<li class="result-failure">{{localize "CTHULHUETERNAL.Label.failure"}}</li>
{{/if}}
{{/if}}
</ul>

View File

@ -1,12 +0,0 @@
<section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</section>

View File

@ -1,95 +0,0 @@
<section class="creature-main creature-main-{{ifThen isPlayMode 'play' 'edit'}}">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.creature"}}</legend>
<div class="creature-pc creature-pc-{{ifThen isPlayMode 'play' 'edit'}}">
<div class="creature-left">
<div class="creature-left-image">
<img class="creature-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
data-tooltip="{{actor.name}}" />
</div>
</div>
<div class="creature-right">
<div class="creature-name">
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
<a class="control" data-action="toggleSheet" data-tooltip="CTHULHUETERNAL.ToggleSheet"
data-tooltip-direction="UP">
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
</a>
</div>
<fieldset class="creature-hp">
<legend>{{localize "CTHULHUETERNAL.Label.HP"}}</legend>
<div class="flexrow">
{{formField systemFields.hp.fields.value value=system.hp.value}}
<span class="hp-separator">/</span>
{{formField systemFields.hp.fields.max value=system.hp.max }}
</div>
<div class="flexrow ">
{{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}}
</div>
</fieldset>
<fieldset class="willpower">
<legend>{{localize "CTHULHUETERNAL.Label.willpower"}}</legend>
<div class="flexrow">
<label class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</label>
{{formInput systemFields.wp.fields.value value=system.wp.value}}
<label class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</label>
{{formInput systemFields.wp.fields.max value=system.wp.max rootId=partId }}
<label class="label-field">{{localize "CTHULHUETERNAL.Label.exhausted"}}</label>
{{formInput systemFields.wp.fields.exhausted value=system.wp.exhausted classes="checkbox"}}
</div>
</fieldset>
</div>
</div>
</fieldset>
<fieldset class="creature-characteristics creature-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
<legend>{{localize "CTHULHUETERNAL.Label.characteristics"}}</legend>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="str" data-tooltip="{{system.characteristics.str.feature}}">{{localize
"CTHULHUETERNAL.Label.strShort"}}</label>
{{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.str.value 5}}</label>
</div>
<div class="creature-characteristic">
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="dex" data-tooltip="{{system.characteristics.dex.feature}}">{{localize
"CTHULHUETERNAL.Label.dexShort"}}</label>
{{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.dex.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="con" data-tooltip="{{system.characteristics.con.feature}}">{{localize
"CTHULHUETERNAL.Label.conShort"}}</label>
{{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.con.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="int" data-tooltip="{{system.characteristics.int.feature}}">{{localize
"CTHULHUETERNAL.Label.intShort"}}</label>
{{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.int.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="pow" data-tooltip="{{system.characteristics.pow.feature}}">{{localize
"CTHULHUETERNAL.Label.powShort"}}</label>
{{formField systemFields.characteristics.fields.pow.fields.value value=system.characteristics.pow.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.pow.value 5}}</label>
</div>
</fieldset>
</section>

View File

@ -1,57 +0,0 @@
<section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}}
</legend>
<div class="weapons">
{{#each weapons as |item|}}
{{!log 'weapon' this}}
<div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}">
{{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="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>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.skills"}}" data-tooltip-direction="UP">{{localize "CTHULHUETERNAL.Label.skills"}}</legend>
<div class="skills">
{{#each skills as |item|}}
<div class="skill item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<div class="name rollable" data-roll-type="skill" data-tooltip="{{{item.description}}}" data-tooltip-direction="UP">{{item.name}}
</div>
<div class="score" >
{{item.system.skillTotal}}
</div>
<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>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
</section>

39
templates/manager.hbs Normal file
View File

@ -0,0 +1,39 @@
<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,18 +0,0 @@
<div class="fvtt-cthulhu-eternal-roll-dialog">
<fieldSet class="dialog-modifier">
<legend>{{localize "CTHULHUETERNAL.Label.selectNewValue"}}</legend>
<select name="modifiedValue" class="nudged-score-select">
{{selectOptions nudgeOptions selected=rollResultIndex}}
</select>
</fieldSet>
<fieldSet>
<legend>{{localize "CTHULHUETERNAL.Label.wpCost"}}</legend>
<div>
Willpower points cost :
<input class="text" value="0" id="nudged-wp-cost" disabled >
</div>
</fieldSet>
</div>

View File

@ -81,55 +81,4 @@
</div>
</fieldset>
{{#if (count tomes)}}
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.Tomes"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addTome"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createTome"></i></a>{{/if}}
</legend>
<div class="tomes">
{{#each tomes as |item|}}
<div class="tome" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<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>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
{{#if (count rituals)}}
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.Rituals"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addRitual"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createRitual"></i></a>{{/if}}
</legend>
<div class="rituals">
{{#each rituals as |item|}}
<div class="ritual" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<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>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
</section>

View File

@ -9,16 +9,13 @@
<img class="protagonist-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
data-tooltip="{{actor.name}}" />
</div>
<fieldset class="protagonist-hp">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.HP"}}</legend>
<div class="flexrow">
{{formField systemFields.hp.fields.value value=system.hp.value}}
<span class="hp-separator">/</span>
/
{{formField systemFields.hp.fields.max value=system.hp.max rootId=partId disabled=true}}
</div>
<div class="flexrow ">
{{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}}
</div>
</fieldset>
</div>
@ -35,9 +32,8 @@
<fieldset class="san">
<legend>{{localize "CTHULHUETERNAL.Label.SAN"}}</legend>
<div class="flexrow">
<label class="label-field rollable" data-roll-type="san" ><img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
{{localize "CTHULHUETERNAL.Label.current"}}</label>
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="label-field rollable" data-roll-type="san" >{{localize "CTHULHUETERNAL.Label.current"}}</label>
{{formInput systemFields.san.fields.value value=system.san.value}}
<span class="label-field label-recovery">{{localize "CTHULHUETERNAL.Label.recovery"}}</span>

View File

@ -12,7 +12,7 @@
{{item.name}}
</div>
<div class="type">
{{upperFirst item.system.bondType}}
{{item.system.bondType}}
</div>
<div class="level">
{{item.system.value}}
@ -56,13 +56,6 @@
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<div class="cured">
{{#if item.system.cured}}
{{localize 'CTHULHUETERNAL.Label.Cured'}}
{{else}}
{{localize 'CTHULHUETERNAL.Label.Uncured'}}
{{/if}}
</div>
<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>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>

View File

@ -1,23 +0,0 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<fieldset>
{{formField systemFields.ritualType value=system.ritualType localize=true}}
{{formField systemFields.studyTime value=system.studyTime}}
{{formField systemFields.studySAN value=system.studySAN}}
{{formField systemFields.activationTime value=system.activationTime}}
{{formField systemFields.activationSAN value=system.activationSAN}}
{{formField systemFields.activationWP value=system.activationWP}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

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

View File

@ -1,42 +0,0 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<fieldset>
<div class="form-group">
{{formField systemFields.language value=system.language }}
</div>
<div class="form-group">
{{formField systemFields.minimumEra value=system.minimumEra localize=true }}
</div>
<div class="form-group">
{{formField systemFields.creationDate value=system.creationDate }}
</div>
<div class="form-group">
{{formField systemFields.studyTime value=system.studyTime }}
</div>
<div class="form-group">
{{formField systemFields.sanLoss value=system.sanLoss }}
</div>
<div class="form-group">
{{formField systemFields.unnaturalSkill value=system.unnaturalSkill }}
</div>
<div class="form-group">
<label>{{localize "CTHULHUETERNAL.Label.Rituals"}} </label>
<textarea class="form-control" rows="3" name="system.rituals" data-tooltip="{{localize "CTHULHUETERNAL.Label.Rituals"}}">{{system.rituals}}</textarea>
</div>
<div class="form-group">
<label>{{localize "CTHULHUETERNAL.Label.otherBenefits"}} </label>
<textarea class="form-control" rows="3" name="system.otherBenefits" data-tooltip="{{localize "CTHULHUETERNAL.Label.otherBenefits"}}">{{system.otherBenefits}}</textarea>
</div>
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

@ -13,11 +13,6 @@
{{formField systemFields.state value=system.state localize=true}}
{{formField systemFields.hasDirectSkill value=system.hasDirectSkill }}
{{#if system.hasDirectSkill}}
{{formField systemFields.directSkillValue value=system.directSkillValue }}
{{/if}}
{{formField systemFields.damage value=system.damage}}
{{formField systemFields.baseRange value=system.baseRange}}
{{formField systemFields.rangeUnit value=system.rangeUnit localize=true}}