Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52877e3a68 | |||
| a06dfa0ae9 | |||
| 0836cada75 | |||
| 61ed1597e7 | |||
| 96062c6fd9 | |||
| f6b35536de | |||
| 7d27562bb4 | |||
| 64f2efdcb9 | |||
| 66f7aade25 | |||
| 8f682a1458 | |||
| fa3054f24b | |||
| 59a891630e | |||
| 35b88b3914 | |||
| cb8bcfd9ea | |||
| eedce1a498 | |||
| 76a99fe33f | |||
| 59a39850ce | |||
| 6eeb391d1a | |||
| c7727076bf | |||
| d0411f9ec9 | |||
| e5653a4edc | |||
| 527e33a805 | |||
| b5857cb3b7 | |||
| 7a06e8a5c9 | |||
| b4d6616cb4 | |||
| aaef4dd896 | |||
| a3c6509862 | |||
| c2fe34e7a6 | |||
| 46176b2782 | |||
| b7f13500a6 | |||
| bd8b098b35 | |||
| 71d3f777bf | |||
| 157163672c |
@@ -8,45 +8,56 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||||
|
|
||||||
#- uses: actions/checkout@v3
|
#- uses: actions/checkout@v3
|
||||||
- uses: RouxAntoine/checkout@v3.5.4
|
- uses: RouxAntoine/checkout@v3.5.4
|
||||||
|
|
||||||
# get part of the tag after the `v`
|
# get part of the tag after the `v`
|
||||||
- name: Extract tag version number
|
- name: Extract tag version number
|
||||||
id: get_version
|
id: get_version
|
||||||
uses: battila7/get-version-action@v2
|
uses: battila7/get-version-action@v2
|
||||||
|
|
||||||
# Substitute the Manifest and Download URLs in the module.json
|
# Substitute the Manifest and Download URLs in the module.json
|
||||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||||
id: sub_manifest_link_version
|
id: sub_manifest_link_version
|
||||||
uses: microsoft/variable-substitution@v1
|
uses: microsoft/variable-substitution@v1
|
||||||
with:
|
with:
|
||||||
files: 'system.json'
|
files: "system.json"
|
||||||
env:
|
env:
|
||||||
version: ${{steps.get_version.outputs.version-without-v}}
|
version: ${{steps.get_version.outputs.version-without-v}}
|
||||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||||
manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
|
manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
|
||||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip
|
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip
|
||||||
|
|
||||||
# Create a zip file with all files required by the module to add to the release
|
# Create a zip file with all files required by the module to add to the release
|
||||||
- run: |
|
- run: |
|
||||||
apt update -y
|
apt update -y
|
||||||
apt install -y zip
|
apt install -y zip
|
||||||
|
|
||||||
- run: zip -r ./fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip system.json README.md LICENSE assets/ css/ lang/ module/ packs-system/ templates/ lethal-fantasy.mjs
|
- run: zip -r ./fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip system.json README.md LICENSE assets/ css/ lang/ module/ packs-system/ templates/ lethal-fantasy.mjs
|
||||||
|
|
||||||
- name: setup go
|
- name: setup go
|
||||||
uses: https://github.com/actions/setup-go@v4
|
uses: https://github.com/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '>=1.20.1'
|
go-version: ">=1.20.1"
|
||||||
|
|
||||||
- name: Use Go Action
|
- name: Use Go Action
|
||||||
id: use-go-action
|
id: use-go-action
|
||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
with:
|
with:
|
||||||
files: |-
|
files: |-
|
||||||
./fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip
|
./fvtt-lethal-fantasy-${{github.event.release.tag_name}}.zip
|
||||||
system.json
|
system.json
|
||||||
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
|
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
||||||
|
|
||||||
|
- name: Publish to Foundry server
|
||||||
|
uses: djlechuck/foundryvtt-publish-package-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.FOUNDRY_PUBLISH_KEY }}
|
||||||
|
id: "fvtt-lethal-fantasy"
|
||||||
|
version: ${{github.event.release.tag_name}}
|
||||||
|
manifest: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json"
|
||||||
|
notes: "https://www.uberwald.me/gitea/public/fvtt-lethal-fantasy/raw/branch/main/changelog.md"
|
||||||
|
compatibility-minimum: "13"
|
||||||
|
compatibility-verified: "13"
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -1,6 +1,20 @@
|
|||||||
|
|
||||||
<h2><em>Lethal Fantasy RPG</em> for Foundry Virtual TableTop</h2>
|
## Lethal Fantasy RPG for Foundry Virtual TableTop
|
||||||
|
|
||||||
<div align="center">
|
The Official game system for playing Lethal Fantasy TTRPG: The Role Playing Game on FoundryVTT. This fully functional system is the foundational framework to build your game.
|
||||||
|
|
||||||
</div>
|
This product's format, programming code, and presentation is copyrighted by Lethal Fantasy Games LLC.
|
||||||
|
|
||||||
|
This system & product are used with permission granted as part of the partnership agreement between Foundry Gaming LLC and Lethal Fantasy Games LLC. It uses the following trademarks and/or copyrights:
|
||||||
|
|
||||||
|
© 2025 Lethal Fantasy Games. Content copyright Ted McClintock, Lethal Fantasy Games LLC. All Rights Reserved. Lethal Fantasy® is a Registered Trademark of Lethal Fantasy Games LLC. All Rights Reserved.
|
||||||
|
|
||||||
|
Lethal Fantasy Games is ©2025 Lethal Fantasy Games, LLC. All rights reserved. Lethal Fantasy, Lethal Fantasy Games, and their associated logos are trademarks of Lethal Fantasy Games, LLC. https://lethalfantasy.com/
|
||||||
|
|
||||||
|
For inquiries on developing content for this ruleset please contact Lethalted@lethalfantasy.com
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
Please join our Discord server Lethal Fantasy games https://discord.gg/UDvnnyvreV
|
||||||
|
|
||||||
|
It's the place to ask questions on how to use the system, make feature request and follow the development of the system.
|
||||||
1
assets/icons/broken-heart.svg
Normal file
1
assets/icons/broken-heart.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g class="" style="" transform="translate(0,0)"><path d="M373.47 25.5c-33.475-.064-67.614 13.444-94.44 43.156l37.22 145.156-33.437.032 35.343 132.093-116.718-188.375 50.03 5.375L202.5 47.312C120.437-1.43 4.756 40.396 8.5 158.156c4.402 138.44 191.196 184.6 247.406 331.625 59.376-147.035 251.26-184.33 246.656-331.624-2.564-82.042-64.6-132.532-129.093-132.656z" fill="#fff" fill-opacity="1"></path></g></svg>
|
||||||
|
After Width: | Height: | Size: 506 B |
5
changelog.md
Normal file
5
changelog.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## v13.0.12
|
||||||
|
|
||||||
|
- Fix favor/disfavor
|
||||||
|
- Fix granted dice
|
||||||
|
- Cosmetic fixes
|
||||||
File diff suppressed because it is too large
Load Diff
47
lang/en.json
47
lang/en.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"COMBAT": {
|
"COMBAT": {
|
||||||
"Round": "Second",
|
"Round": "Second {round}",
|
||||||
"Rounds": "Seconds",
|
"Rounds": "Seconds",
|
||||||
"RoundNext": "Next second"
|
"RoundNext": "Next second"
|
||||||
},
|
},
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
},
|
},
|
||||||
"challenges": {
|
"challenges": {
|
||||||
"agility": {
|
"agility": {
|
||||||
"label": "Agility"
|
"label": "Dexterity"
|
||||||
},
|
},
|
||||||
"dying": {
|
"dying": {
|
||||||
"label": "Dying"
|
"label": "Dying"
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
},
|
},
|
||||||
"challenges": {
|
"challenges": {
|
||||||
"agility": {
|
"agility": {
|
||||||
"label": "Agility"
|
"label": "Dexterity"
|
||||||
},
|
},
|
||||||
"dying": {
|
"dying": {
|
||||||
"label": "Dying"
|
"label": "Dying"
|
||||||
@@ -281,6 +281,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Label": {
|
"Label": {
|
||||||
|
"agility": "Dexterity",
|
||||||
|
"applyDamage": "Apply damage to:",
|
||||||
|
"selectTarget": "Select target for attack:",
|
||||||
|
"rollDamage": "Roll Damage",
|
||||||
"gotoToken": "Go to token",
|
"gotoToken": "Go to token",
|
||||||
"combatAction": "Combat action",
|
"combatAction": "Combat action",
|
||||||
"currentAction": "Current ongoing action",
|
"currentAction": "Current ongoing action",
|
||||||
@@ -303,8 +307,10 @@
|
|||||||
"grantedAttackDice": "Granted attack",
|
"grantedAttackDice": "Granted attack",
|
||||||
"grantedDamageDice": "Granted damage",
|
"grantedDamageDice": "Granted damage",
|
||||||
"grantedDefenseDice": "Granted defense",
|
"grantedDefenseDice": "Granted defense",
|
||||||
"damageResistance": "Damage resistance",
|
"damageResistance": "DR",
|
||||||
"damageResistanceShort": "DR",
|
"damageResistanceShort": "DR",
|
||||||
|
"shieldDamageReduction": "Shield DR",
|
||||||
|
"shieldDefenseDice": "Shield dice",
|
||||||
"stealth": "Stealth",
|
"stealth": "Stealth",
|
||||||
"progressionDice": "Progression/Lethargy dice",
|
"progressionDice": "Progression/Lethargy dice",
|
||||||
"rollProgressionCount": "Roll progression count",
|
"rollProgressionCount": "Roll progression count",
|
||||||
@@ -348,7 +354,7 @@
|
|||||||
"cha": "CHA",
|
"cha": "CHA",
|
||||||
"challenge": "Challenge",
|
"challenge": "Challenge",
|
||||||
"challenges": {
|
"challenges": {
|
||||||
"agility": "Agility",
|
"agility": "Dexterity",
|
||||||
"dying": "Dying",
|
"dying": "Dying",
|
||||||
"strength": "Strength"
|
"strength": "Strength"
|
||||||
},
|
},
|
||||||
@@ -420,7 +426,9 @@
|
|||||||
"monster-damage": "Monster damage",
|
"monster-damage": "Monster damage",
|
||||||
"monster-defense": "Monster defense",
|
"monster-defense": "Monster defense",
|
||||||
"weapons": "Weapons",
|
"weapons": "Weapons",
|
||||||
"wis": "WIS"
|
"wis": "WIS",
|
||||||
|
"weapon-damage-medium": "Weapon damage medium",
|
||||||
|
"weapon-damage-small": "Weapon damage small"
|
||||||
},
|
},
|
||||||
"Miracle": {
|
"Miracle": {
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
@@ -552,7 +560,7 @@
|
|||||||
"label": "Min"
|
"label": "Min"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"damagereduction": {
|
"damageReduction": {
|
||||||
"label": "Damage reduction"
|
"label": "Damage reduction"
|
||||||
},
|
},
|
||||||
"defense": {
|
"defense": {
|
||||||
@@ -855,6 +863,31 @@
|
|||||||
"melee": "Melee",
|
"melee": "Melee",
|
||||||
"ranged": "Ranged"
|
"ranged": "Ranged"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Dialog": {
|
||||||
|
"applyDamageTo": "Apply damage to",
|
||||||
|
"weapon": "Weapon",
|
||||||
|
"totalDamage": "Total Damage",
|
||||||
|
"damageReduction": "Damage Reduction",
|
||||||
|
"armorDR": "Armor DR",
|
||||||
|
"shieldDR": "Shield DR",
|
||||||
|
"totalDR": "Total DR",
|
||||||
|
"selectOption": "Select damage application option",
|
||||||
|
"noDR": "No DR",
|
||||||
|
"withArmor": "With Armor DR only",
|
||||||
|
"withAll": "With Armor + Shield DR",
|
||||||
|
"damage": "damage"
|
||||||
|
},
|
||||||
|
"DamageApplied": {
|
||||||
|
"subtitle": "suffered damage",
|
||||||
|
"damageDealt": "Damage dealt",
|
||||||
|
"from": "from"
|
||||||
|
},
|
||||||
|
"ProgressionMessage": {
|
||||||
|
"canAct": "ready to act!",
|
||||||
|
"cannotAct": "cannot act this second",
|
||||||
|
"diceResult": "Dice result",
|
||||||
|
"progressionCount": "Progression count:"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TYPES": {
|
"TYPES": {
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import * as models from "./module/models/_module.mjs"
|
|||||||
import * as documents from "./module/documents/_module.mjs"
|
import * as documents from "./module/documents/_module.mjs"
|
||||||
import * as applications from "./module/applications/_module.mjs"
|
import * as applications from "./module/applications/_module.mjs"
|
||||||
|
|
||||||
import { LethalFantasyCombatTracker, LethalFantasyCombat} from "./module/applications/combat.mjs"
|
import { LethalFantasyCombatTracker, LethalFantasyCombat } from "./module/applications/combat.mjs"
|
||||||
import { Macros } from "./module/macros.mjs"
|
import { Macros } from "./module/macros.mjs"
|
||||||
import { setupTextEnrichers } from "./module/enrichers.mjs"
|
import { setupTextEnrichers } from "./module/enrichers.mjs"
|
||||||
import { default as LethalFantasyUtils } from "./module/utils.mjs"
|
import { default as LethalFantasyUtils } 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 () {
|
Hooks.once("init", function () {
|
||||||
console.info("Lethal Fantasy RPG | Initializing System")
|
console.info("Lethal Fantasy RPG | Initializing System")
|
||||||
@@ -55,20 +55,20 @@ Hooks.once("init", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register sheet application classes
|
// Register sheet application classes
|
||||||
Actors.unregisterSheet("core", ActorSheet)
|
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
|
||||||
Actors.registerSheet("lethalFantasy", applications.LethalFantasyCharacterSheet, { types: ["character"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyCharacterSheet, { types: ["character"], makeDefault: true })
|
||||||
Actors.registerSheet("lethalFantasy", applications.LethalFantasyMonsterSheet, { types: ["monster"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("lethalFantasy", applications.LethalFantasyMonsterSheet, { types: ["monster"], makeDefault: true })
|
||||||
|
|
||||||
Items.unregisterSheet("core", ItemSheet)
|
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasySkillSheet, { types: ["skill"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasySkillSheet, { types: ["skill"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyGiftSheet, { types: ["gift"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyGiftSheet, { types: ["gift"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyVulnerabilitySheet, { types: ["vulnerability"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyVulnerabilitySheet, { types: ["vulnerability"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyWeaponSheet, { types: ["weapon"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyWeaponSheet, { types: ["weapon"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasySpellSheet, { types: ["spell"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasySpellSheet, { types: ["spell"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyArmorSheet, { types: ["armor"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyArmorSheet, { types: ["armor"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyShieldSheet, { types: ["shield"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyShieldSheet, { types: ["shield"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyEquipmentSheet, { types: ["equipment"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyEquipmentSheet, { types: ["equipment"], makeDefault: true })
|
||||||
Items.registerSheet("lethalFantasy", applications.LethalFantasyMiracleSheet, { types: ["miracle"], makeDefault: true })
|
foundry.documents.collections.Items.registerSheet("lethalFantasy", applications.LethalFantasyMiracleSheet, { types: ["miracle"], makeDefault: true })
|
||||||
|
|
||||||
// Other Document Configuration
|
// Other Document Configuration
|
||||||
CONFIG.ChatMessage.documentClass = documents.LethalFantasyChatMessage
|
CONFIG.ChatMessage.documentClass = documents.LethalFantasyChatMessage
|
||||||
@@ -89,12 +89,13 @@ Hooks.once("init", function () {
|
|||||||
|
|
||||||
setupTextEnrichers()
|
setupTextEnrichers()
|
||||||
LethalFantasyUtils.registerHandlebarsHelpers()
|
LethalFantasyUtils.registerHandlebarsHelpers()
|
||||||
|
LethalFantasyUtils.setHookListeners()
|
||||||
|
|
||||||
console.info("LETHAL FANTASY | System Initialized")
|
console.info("LETHAL FANTASY | System Initialized")
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform one-time configuration of system configuration objects.
|
* Perform one-time configuration of system configuration objects.f
|
||||||
*/
|
*/
|
||||||
function preLocalizeConfig() {
|
function preLocalizeConfig() {
|
||||||
const localizeConfigObject = (obj, keys) => {
|
const localizeConfigObject = (obj, keys) => {
|
||||||
@@ -104,19 +105,18 @@ function preLocalizeConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONFIG.Dice.rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
|
||||||
|
|
||||||
// localizeConfigObject(SYSTEM.ACTION.TAG_CATEGORIES, ["label"])
|
|
||||||
// localizeConfigObject(CONFIG.Dice.rollModes, ["label"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Hooks.once("ready", function () {
|
Hooks.once("ready", function () {
|
||||||
console.info("LETHAL FANTASY | Ready")
|
console.info("LETHAL FANTASY | Ready")
|
||||||
|
|
||||||
|
// Initialiser la table des résultats D30
|
||||||
|
documents.D30Roll.initialize()
|
||||||
|
|
||||||
if (!SYSTEM.DEV_MODE) {
|
if (!SYSTEM.DEV_MODE) {
|
||||||
registerWorldCount("lethalFantasy")
|
registerWorldCount("lethalFantasy")
|
||||||
}
|
}
|
||||||
|
|
||||||
_showUserGuide()
|
_showUserGuide()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,7 +129,12 @@ Hooks.once("ready", function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Hooks.on("renderChatMessage", (message, html, data) => {
|
// Test if version below 13
|
||||||
|
let hookName = "renderChatMessage"
|
||||||
|
if (foundry.utils.isNewerVersion(game.version, "12.0",)) {
|
||||||
|
hookName = "renderChatMessageHTML"
|
||||||
|
}
|
||||||
|
Hooks.on(hookName, (message, html, data) => {
|
||||||
const typeMessage = data.message.flags.lethalFantasy?.typeMessage
|
const typeMessage = data.message.flags.lethalFantasy?.typeMessage
|
||||||
// Message de demande de jet de dés
|
// Message de demande de jet de dés
|
||||||
if (typeMessage === "askRoll") {
|
if (typeMessage === "askRoll") {
|
||||||
@@ -150,12 +155,422 @@ Hooks.on("renderChatMessage", (message, html, data) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gestion du survol et du clic sur les boutons de dégâts pour les GMs
|
||||||
|
if (game.user.isGM) {
|
||||||
|
// Show damage buttons only for GM
|
||||||
|
$(html).find(".li-apply-wounds").each((i, btn) => {
|
||||||
|
btn.style.display = "block"
|
||||||
|
})
|
||||||
|
|
||||||
|
$(html).find(".apply-wounds-btn").hover(
|
||||||
|
function (event) {
|
||||||
|
// Mouse enter - select the token and pan to it
|
||||||
|
let combatantId = $(this).data("combatant-id")
|
||||||
|
if (combatantId && game.combat) {
|
||||||
|
let combatant = game.combat.combatants.get(combatantId)
|
||||||
|
if (combatant?.token) {
|
||||||
|
let token = canvas.tokens.get(combatant.token.id)
|
||||||
|
if (token) {
|
||||||
|
token.control({ releaseOthers: true })
|
||||||
|
canvas.animatePan(token.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (event) {
|
||||||
|
// Mouse leave - release selection
|
||||||
|
canvas.tokens.releaseAll()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$(html).find(".apply-wounds-btn").click((event) => {
|
||||||
|
LethalFantasyUtils.applyDamage(message, event)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestion du survol et du clic sur les boutons de défense
|
||||||
|
$(html).find(".request-defense-btn").hover(
|
||||||
|
function (event) {
|
||||||
|
// Mouse enter - select the token and pan to it
|
||||||
|
let tokenId = $(this).data("token-id")
|
||||||
|
if (tokenId) {
|
||||||
|
let token = canvas.tokens.get(tokenId)
|
||||||
|
if (token) {
|
||||||
|
token.control({ releaseOthers: true })
|
||||||
|
canvas.animatePan(token.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (event) {
|
||||||
|
// Mouse leave - release selection
|
||||||
|
canvas.tokens.releaseAll()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gestionnaire pour les boutons de demande de défense
|
||||||
|
$(html).find(".request-defense-btn").off("click").on("click", (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
const button = $(event.currentTarget)
|
||||||
|
const combatantId = button.data("combatant-id")
|
||||||
|
const tokenId = button.data("token-id")
|
||||||
|
|
||||||
|
// Récupérer le combattant soit du combat, soit directement du token
|
||||||
|
let combatant = null
|
||||||
|
let token = null
|
||||||
|
|
||||||
|
if (game.combat && combatantId) {
|
||||||
|
combatant = game.combat.combatants.get(combatantId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas de combattant trouvé, chercher le token directement
|
||||||
|
if (!combatant && tokenId) {
|
||||||
|
token = canvas.tokens.get(tokenId)
|
||||||
|
if (token) {
|
||||||
|
// Créer un pseudo-combattant avec les infos du token
|
||||||
|
combatant = {
|
||||||
|
actor: token.actor,
|
||||||
|
name: token.name,
|
||||||
|
token: token,
|
||||||
|
actorId: token.actorId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!combatant) return
|
||||||
|
|
||||||
|
// Récupérer les informations de l'attaquant depuis le message
|
||||||
|
const attackerName = message.rolls[0]?.actorName || "Unknown"
|
||||||
|
const attackerId = message.rolls[0]?.actorId
|
||||||
|
const weaponName = message.rolls[0]?.rollName || "weapon"
|
||||||
|
const attackRoll = message.rolls[0]?.rollTotal || 0
|
||||||
|
const defenderName = combatant.name
|
||||||
|
const attackWeaponId = message.rolls[0]?.rollTarget?.weapon?.id || message.rolls[0]?.rollTarget?.weapon?._id
|
||||||
|
const attackRollType = message.rolls[0]?.type
|
||||||
|
const attackRollKey = message.rolls[0]?.rollTarget?.rollKey
|
||||||
|
|
||||||
|
// Préparer le message de demande de défense
|
||||||
|
const defenseMsg = {
|
||||||
|
type: "requestDefense",
|
||||||
|
attackerName: attackerName,
|
||||||
|
attackerId: attackerId,
|
||||||
|
defenderName: defenderName,
|
||||||
|
weaponName: weaponName,
|
||||||
|
attackRoll: attackRoll,
|
||||||
|
attackWeaponId: attackWeaponId,
|
||||||
|
attackRollType: attackRollType,
|
||||||
|
attackRollKey: attackRollKey,
|
||||||
|
combatantId: combatantId,
|
||||||
|
tokenId: tokenId
|
||||||
|
}
|
||||||
|
|
||||||
|
// Envoyer le message socket à l'utilisateur contrôlant le combatant
|
||||||
|
const owners = game.users.filter(u =>
|
||||||
|
combatant.actor.testUserPermission(u, "OWNER")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Récupérer l'acteur attaquant pour vérifier qui l'a lancé
|
||||||
|
const attacker = game.actors.get(attackerId)
|
||||||
|
const attackerOwners = attacker ? game.users.filter(u => attacker.testUserPermission(u, "OWNER")).map(u => u.id) : []
|
||||||
|
|
||||||
|
let messageSent = false
|
||||||
|
owners.forEach(owner => {
|
||||||
|
// Ne pas afficher le dialogue à l'attaquant lui-même s'il contrôle aussi le défenseur
|
||||||
|
if (attackerOwners.includes(owner.id) && owner.id === game.user.id) {
|
||||||
|
// Ne rien faire - on ne veut pas que l'attaquant se défende contre lui-même
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner.id === game.user.id) {
|
||||||
|
// Si l'utilisateur actuel est le propriétaire du défenseur (mais pas l'attaquant), appeler directement
|
||||||
|
LethalFantasyUtils.showDefenseRequest({ ...defenseMsg, userId: owner.id })
|
||||||
|
messageSent = true
|
||||||
|
} else {
|
||||||
|
// Sinon, envoyer via socket
|
||||||
|
game.socket.emit(`system.${SYSTEM.id}`, {
|
||||||
|
...defenseMsg,
|
||||||
|
userId: owner.id
|
||||||
|
})
|
||||||
|
messageSent = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Notification pour l'attaquant
|
||||||
|
if (messageSent) {
|
||||||
|
ui.notifications.info(`Defense request sent to ${defenderName}'s controller`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Gestionnaire pour les boutons de jet de dégâts (armes et résultats de combat)
|
||||||
|
$(html).find(".damage-roll-btn, .roll-damage-btn").off("click").on("click", async (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
const button = $(event.currentTarget)
|
||||||
|
const weaponId = button.data("weapon-id")
|
||||||
|
const attackKey = button.data("attack-key")
|
||||||
|
let attackerId = button.data("attacker-id")
|
||||||
|
const defenderId = button.data("defender-id")
|
||||||
|
const damageType = button.data("damage-type")
|
||||||
|
const damageFormula = button.data("damage-formula")
|
||||||
|
const damageModifier = button.data("damage-modifier")
|
||||||
|
const isMonster = button.data("is-monster")
|
||||||
|
|
||||||
|
// Récupérer l'acteur (soit depuis le message, soit depuis attackerId)
|
||||||
|
let actor = attackerId ? game.actors.get(attackerId) : game.actors.get(message.rolls[0]?.actorId)
|
||||||
|
if (!actor) {
|
||||||
|
ui.notifications.error("Actor not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour les boutons de résultat de combat (monster damage)
|
||||||
|
if (damageType === "monster" && attackKey) {
|
||||||
|
await actor.system.prepareMonsterRoll("monster-damage", attackKey, undefined, undefined, undefined, defenderId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour les monstres, utiliser prepareMonsterRoll
|
||||||
|
if (isMonster || actor.type === "monster") {
|
||||||
|
await actor.system.prepareMonsterRoll("monster-damage", weaponId, undefined, undefined, damageModifier)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour les personnages, récupérer l'arme
|
||||||
|
const weapon = actor.items.get(weaponId)
|
||||||
|
if (!weapon) {
|
||||||
|
ui.notifications.error("Weapon not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancer les dégâts avec la bonne méthode
|
||||||
|
const rollType = damageType === "small" ? "weapon-damage-small" : "weapon-damage-medium"
|
||||||
|
await actor.prepareRoll(rollType, weaponId, undefined, defenderId)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Masquer les boutons de dommages dans les messages de résultat de combat si l'utilisateur n'est pas l'attaquant
|
||||||
|
$(html).find(".roll-damage-btn").each(function() {
|
||||||
|
const button = $(this)
|
||||||
|
const attackerId = button.data("attacker-id")
|
||||||
|
|
||||||
|
if (attackerId) {
|
||||||
|
const attacker = game.actors.get(attackerId)
|
||||||
|
// Masquer le bouton si l'utilisateur n'est pas GM et ne possède pas l'attaquant
|
||||||
|
if (!game.user.isGM && !attacker?.testUserPermission(game.user, "OWNER")) {
|
||||||
|
button.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
|
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
|
||||||
LethalFantasyUtils.pushCombatOptions(html, options);
|
LethalFantasyUtils.pushCombatOptions(html, options);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hook pour ajouter les données d'attaque au message de défense
|
||||||
|
Hooks.on("preCreateChatMessage", (message) => {
|
||||||
|
const rollType = message.rolls[0]?.options?.rollType
|
||||||
|
|
||||||
|
// Si c'est un message de défense et qu'on a des données en attente
|
||||||
|
if ((rollType === "weapon-defense" || rollType === "monster-defense") && game.lethalFantasy?.nextDefenseData) {
|
||||||
|
// Ajouter les données dans les flags du message
|
||||||
|
message.updateSource({
|
||||||
|
[`flags.${SYSTEM.id}.attackData`]: game.lethalFantasy.nextDefenseData
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("Added attack data to defense message:", game.lethalFantasy.nextDefenseData)
|
||||||
|
|
||||||
|
// Nettoyer
|
||||||
|
delete game.lethalFantasy.nextDefenseData
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Hook global pour gérer l'offre de Grit à l'attaquant après une défense
|
||||||
|
Hooks.on("createChatMessage", async (message) => {
|
||||||
|
const rollType = message.rolls[0]?.options?.rollType
|
||||||
|
|
||||||
|
console.log("Defense hook checking message, rollType:", rollType)
|
||||||
|
|
||||||
|
// Vérifier si c'est un message de défense
|
||||||
|
if (rollType !== "weapon-defense" && rollType !== "monster-defense") return
|
||||||
|
|
||||||
|
// Récupérer les données d'attaque depuis les flags
|
||||||
|
const attackData = message.flags?.[SYSTEM.id]?.attackData
|
||||||
|
|
||||||
|
console.log("Defense message confirmed, attackData:", attackData)
|
||||||
|
|
||||||
|
if (!attackData) {
|
||||||
|
console.log("No attack data found in message flags")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { attackerId, attackRoll, attackerName, defenderName, attackWeaponId, attackRollType, attackRollKey, defenderId } = attackData
|
||||||
|
let defenseRoll = message.rolls[0]?.options?.rollTotal || message.rolls[0]?.total || 0
|
||||||
|
|
||||||
|
console.log("Processing defense:", { attackRoll, defenseRoll, attackerId, defenderId })
|
||||||
|
|
||||||
|
// Attendre l'animation 3D
|
||||||
|
if (game?.dice3d) {
|
||||||
|
await game.dice3d.waitFor3DAnimationByMessageID(message.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer le défenseur et l'attaquant
|
||||||
|
const defender = game.actors.get(defenderId)
|
||||||
|
const attacker = game.actors.get(attackerId)
|
||||||
|
|
||||||
|
// Si le défenseur est un personnage qui perd, proposer Grit/Luck (seulement s'il a des points)
|
||||||
|
// Seulement si l'utilisateur actuel est le propriétaire du défenseur
|
||||||
|
let defenderHandledBonus = false
|
||||||
|
if (defender?.type === "character" && defenseRoll < attackRoll && !game.user.isGM && defender.isOwner) {
|
||||||
|
const hasGritOrLuck = (defender.system.grit.current > 0) || (defender.system.luck.current > 0)
|
||||||
|
|
||||||
|
if (hasGritOrLuck) {
|
||||||
|
const bonusRoll = await LethalFantasyUtils.offerGritLuckBonus(
|
||||||
|
defender,
|
||||||
|
attackRoll,
|
||||||
|
defenseRoll,
|
||||||
|
attackerName,
|
||||||
|
defenderName
|
||||||
|
)
|
||||||
|
if (bonusRoll > 0) {
|
||||||
|
defenseRoll += bonusRoll
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defenderHandledBonus = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let attackRollFinal = attackRoll
|
||||||
|
let attackerHandledBonus = false
|
||||||
|
|
||||||
|
// Si l'attaquant est un personnage qui perd et a du Grit
|
||||||
|
// Seulement si l'utilisateur actuel est le propriétaire de l'attaquant (pas le MJ)
|
||||||
|
if (attacker?.type === "character" && attackRollFinal <= defenseRoll && attacker.system.grit.current > 0) {
|
||||||
|
// Vérifier si l'utilisateur est un propriétaire non-GM de l'attaquant
|
||||||
|
const isAttackerOwner = !game.user.isGM && attacker.testUserPermission(game.user, "OWNER")
|
||||||
|
|
||||||
|
if (isAttackerOwner) {
|
||||||
|
console.log("Offering Grit to attacker")
|
||||||
|
|
||||||
|
const attackBonus = await LethalFantasyUtils.offerAttackerGritBonus(
|
||||||
|
attacker,
|
||||||
|
attackRollFinal,
|
||||||
|
defenseRoll,
|
||||||
|
attackerName,
|
||||||
|
defenderName
|
||||||
|
)
|
||||||
|
|
||||||
|
attackRollFinal += attackBonus
|
||||||
|
attackerHandledBonus = true
|
||||||
|
} else {
|
||||||
|
console.log("Not attacker owner or is GM, skipping Grit offer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer le message de comparaison - uniquement par le client qui a géré le dernier bonus
|
||||||
|
// Priorité: attaquant si il a géré le bonus, sinon défenseur si il a géré le bonus, sinon défenseur
|
||||||
|
const shouldCreateMessage = attackerHandledBonus || (!attackerHandledBonus && defenderHandledBonus) || (!attackerHandledBonus && !defenderHandledBonus && defender.isOwner)
|
||||||
|
|
||||||
|
if (shouldCreateMessage) {
|
||||||
|
console.log("Creating comparison message", { attackerHandledBonus, defenderHandledBonus, isDefenderOwner: defender.isOwner })
|
||||||
|
|
||||||
|
await LethalFantasyUtils.compareAttackDefense({
|
||||||
|
attackerName,
|
||||||
|
attackerId,
|
||||||
|
attackRoll: attackRollFinal,
|
||||||
|
attackWeaponId,
|
||||||
|
attackRollType,
|
||||||
|
attackRollKey,
|
||||||
|
defenderName,
|
||||||
|
defenderId,
|
||||||
|
defenseRoll
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log("Skipping message creation", { attackerHandledBonus, defenderHandledBonus })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Hook pour appliquer automatiquement les dégâts si une cible est définie
|
||||||
|
Hooks.on("createChatMessage", async (message) => {
|
||||||
|
// Vérifier si c'est un message de dégâts avec un defenderId
|
||||||
|
const defenderId = message.rolls[0]?.options?.defenderId
|
||||||
|
const isDamage = message.rolls[0]?.options?.rollData?.isDamage
|
||||||
|
|
||||||
|
console.log("Auto-damage hook:", { defenderId, isDamage, rollType: message.rolls[0]?.options?.rollType })
|
||||||
|
|
||||||
|
if (!defenderId || !isDamage) return
|
||||||
|
|
||||||
|
// Récupérer l'attaquant depuis le roll
|
||||||
|
const attackerId = message.rolls[0]?.options?.actorId
|
||||||
|
const attacker = attackerId ? game.actors.get(attackerId) : null
|
||||||
|
|
||||||
|
// Déterminer qui doit appliquer les dégâts :
|
||||||
|
// 1. Si l'attaquant a un propriétaire joueur, seul ce joueur applique
|
||||||
|
// 2. Si l'attaquant n'a que le MJ comme propriétaire (monstre), seul le MJ applique
|
||||||
|
const attackerOwners = attacker ? game.users.filter(u =>
|
||||||
|
!u.isGM && attacker.testUserPermission(u, "OWNER")
|
||||||
|
) : []
|
||||||
|
|
||||||
|
let shouldApplyDamage = false
|
||||||
|
if (attackerOwners.length > 0) {
|
||||||
|
// L'attaquant a des propriétaires joueurs, seul le premier propriétaire applique
|
||||||
|
shouldApplyDamage = attackerOwners[0].id === game.user.id
|
||||||
|
} else {
|
||||||
|
// L'attaquant n'a que le MJ, seul le MJ applique
|
||||||
|
shouldApplyDamage = game.user.isGM
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shouldApplyDamage) {
|
||||||
|
console.log("Auto-damage hook: Not responsible for applying damage, skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Auto-damage hook: Applying damage as responsible user")
|
||||||
|
|
||||||
|
// Attendre l'animation 3D avant d'appliquer les dégâts
|
||||||
|
if (game?.dice3d) {
|
||||||
|
await game.dice3d.waitFor3DAnimationByMessageID(message.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer le défenseur
|
||||||
|
const defender = game.actors.get(defenderId)
|
||||||
|
if (!defender) {
|
||||||
|
console.warn("Defender not found:", defenderId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer les dégâts (utiliser rollTotal qui contient le total calculé)
|
||||||
|
const damageTotal = message.rolls[0]?.options?.rollTotal || message.rolls[0]?.total || 0
|
||||||
|
const weaponName = message.rolls[0]?.options?.rollName || "Unknown Weapon"
|
||||||
|
const attackerName = message.rolls[0]?.options?.actorName || "Unknown Attacker"
|
||||||
|
|
||||||
|
// Calculer les DR
|
||||||
|
const armorDR = defender.computeDamageReduction() || 0
|
||||||
|
|
||||||
|
// Appliquer les dégâts avec armure DR par défaut
|
||||||
|
const finalDamage = Math.max(0, damageTotal - armorDR)
|
||||||
|
await defender.applyDamage(-finalDamage)
|
||||||
|
|
||||||
|
// Créer un message de confirmation
|
||||||
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
"systems/fvtt-lethal-fantasy/templates/damage-applied-message.hbs",
|
||||||
|
{
|
||||||
|
targetName: defender.name,
|
||||||
|
damage: finalDamage,
|
||||||
|
drText: armorDR > 0 ? `Armor DR: ${armorDR}` : "",
|
||||||
|
weaponName: weaponName,
|
||||||
|
attackerName: attackerName,
|
||||||
|
rawDamage: damageTotal
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: messageContent,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor: defender })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a macro when dropping an entity on the hotbar
|
* Create a macro when dropping an entity on the hotbar
|
||||||
* Item - open roll dialog
|
* Item - open roll dialog
|
||||||
|
|||||||
@@ -1,18 +1,54 @@
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class LethalFantasyCombatTracker extends CombatTracker {
|
export class LethalFantasyCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
||||||
|
|
||||||
async getData(options) {
|
static PARTS = {
|
||||||
let data = await super.getData(options);
|
"header": {
|
||||||
for (let u of data.turns) {
|
"template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-header-v2.hbs"
|
||||||
|
},
|
||||||
|
"tracker": {
|
||||||
|
"template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-v2.hbs"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-footer-v2.hbs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = foundry.utils.mergeObject(super.DEFAULT_OPTIONS, {
|
||||||
|
actions: {
|
||||||
|
initiativePlus: LethalFantasyCombatTracker.#initiativePlus,
|
||||||
|
initiativeMinus: LethalFantasyCombatTracker.#initiativeMinus,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
async _prepareContext(options) {
|
||||||
|
let data = await super._prepareContext(options);
|
||||||
|
console?.log("Combat Tracker Data", data);
|
||||||
|
/*for (let u of data.turns) {
|
||||||
let c = game.combat.combatants.get(u.id);
|
let c = game.combat.combatants.get(u.id);
|
||||||
u.progressionCount = c.system.progressionCount
|
u.progressionCount = c.system.progressionCount
|
||||||
u.isMonster = c.actor.type === "monster"
|
u.isMonster = c.actor.type === "monster"
|
||||||
}
|
}
|
||||||
console.log("Combat Data", data);
|
console.log("Combat Data", data);*/
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static #initiativePlus(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
let cId = ev.target.closest(".combatant").dataset.combatantId;
|
||||||
|
let c = game.combat.combatants.get(cId);
|
||||||
|
c.update({ 'initiative': c.initiative + 1 });
|
||||||
|
console.log("Initiative Plus");
|
||||||
|
}
|
||||||
|
|
||||||
|
static #initiativeMinus(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
let cId = ev.target.closest(".combatant").dataset.combatantId;
|
||||||
|
let c = game.combat.combatants.get(cId);
|
||||||
|
let newInit = Math.max(c.initiative - 1, 0);
|
||||||
|
c.update({ 'initiative': newInit });
|
||||||
|
}
|
||||||
|
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
// Display Combat settings
|
// Display Combat settings
|
||||||
@@ -21,7 +57,6 @@ export class LethalFantasyCombatTracker extends CombatTracker {
|
|||||||
let cId = ev.currentTarget.closest(".combatant").dataset.combatantId;
|
let cId = ev.currentTarget.closest(".combatant").dataset.combatantId;
|
||||||
let c = game.combat.combatants.get(cId);
|
let c = game.combat.combatants.get(cId);
|
||||||
c.update({ 'initiative': c.initiative + 1 });
|
c.update({ 'initiative': c.initiative + 1 });
|
||||||
console.log("Initiative Plus");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
html.find(".initiative-minus").click(ev => {
|
html.find(".initiative-minus").click(ev => {
|
||||||
@@ -160,10 +195,10 @@ export class LethalFantasyCombat extends Combat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let c of this.combatants) {
|
for (let c of this.combatants) {
|
||||||
if ( nextRound >= c.initiative) {
|
if (nextRound >= c.initiative) {
|
||||||
let user = game.users.find(u => u.active && u.character && u.character.id === c.actor.id);
|
let user = game.users.find(u => u.active && u.character && u.character.id === c.actor.id);
|
||||||
if (user?.hasPlayerOwner) {
|
if (user?.hasPlayerOwner) {
|
||||||
game.socket.emit(`system.${SYSTEM.id}`, { type: "rollProgressionDice", progressionCount: c.system.progressionCount+1, actorId: c.actor.id, combatId: this.id, combatantId: c.id });
|
game.socket.emit(`system.${SYSTEM.id}`, { type: "rollProgressionDice", progressionCount: c.system.progressionCount + 1, actorId: c.actor.id, combatId: this.id, combatantId: c.id });
|
||||||
} else {
|
} else {
|
||||||
user = game.users.find(u => u.active && u.isGM);
|
user = game.users.find(u => u.active && u.isGM);
|
||||||
c.actor.system.rollProgressionDice(this.id, c.id);
|
c.actor.system.rollProgressionDice(this.id, c.id);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default class LethalFantasyArmorSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
|
|||||||
actor: this.document,
|
actor: this.document,
|
||||||
system: this.document.system,
|
system: this.document.system,
|
||||||
source: this.document.toObject(),
|
source: this.document.toObject(),
|
||||||
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
|
||||||
isEditMode: this.isEditMode,
|
isEditMode: this.isEditMode,
|
||||||
isPlayMode: this.isPlayMode,
|
isPlayMode: this.isPlayMode,
|
||||||
isEditable: this.isEditable,
|
isEditable: this.isEditable,
|
||||||
@@ -100,7 +100,7 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
|
|||||||
dragover: this._onDragOver.bind(this),
|
dragover: this._onDragOver.bind(this),
|
||||||
drop: this._onDrop.bind(this),
|
drop: this._onDrop.bind(this),
|
||||||
}
|
}
|
||||||
return new DragDrop(d)
|
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ export default class LethalFantasyActorSheet extends HandlebarsApplicationMixin(
|
|||||||
if ("link" in event.target.dataset) return
|
if ("link" in event.target.dataset) return
|
||||||
|
|
||||||
const el = event.currentTarget.closest('[data-drag="true"]')
|
const el = event.currentTarget.closest('[data-drag="true"]')
|
||||||
const dragType = el.dataset.dragType
|
const dragType = el?.dataset?.dragType
|
||||||
|
|
||||||
let dragData = {}
|
let dragData = {}
|
||||||
|
|
||||||
|
|||||||
@@ -58,22 +58,22 @@ export default class LethalFantasyItemSheet extends HandlebarsApplicationMixin(f
|
|||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = {
|
let context = await super._prepareContext()
|
||||||
fields: this.document.schema.fields,
|
context.fields = this.document.schema.fields
|
||||||
systemFields: this.document.system.schema.fields,
|
context.systemFields = this.document.system.schema.fields
|
||||||
item: this.document,
|
context.item = this.document
|
||||||
system: this.document.system,
|
context.system = this.document.system
|
||||||
source: this.document.toObject(),
|
context.source = this.document.toObject()
|
||||||
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
isEditMode: this.isEditMode,
|
context.isEditMode = this.isEditMode
|
||||||
isPlayMode: this.isPlayMode,
|
context.isPlayMode = this.isPlayMode
|
||||||
isEditable: this.isEditable,
|
context.isEditable = this.isEditable
|
||||||
}
|
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
|
super._onRender(context, options)
|
||||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ export default class LethalFantasyItemSheet extends HandlebarsApplicationMixin(f
|
|||||||
dragover: this._onDragOver.bind(this),
|
dragover: this._onDragOver.bind(this),
|
||||||
drop: this._onDrop.bind(this),
|
drop: this._onDrop.bind(this),
|
||||||
}
|
}
|
||||||
return new DragDrop(d)
|
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,21 +90,31 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
|
|||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
_generateTooltip(type, target) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _preparePartContext(partId, context) {
|
async _preparePartContext(partId, context) {
|
||||||
const doc = this.document
|
const doc = this.document
|
||||||
switch (partId) {
|
switch (partId) {
|
||||||
case "main":
|
case "main":
|
||||||
|
context.armorDR = this.actor.getArmorDR()
|
||||||
|
context.damageReduction = this.actor.computeDamageReduction()
|
||||||
|
context.damageReductionShield = this.actor.getShieldDR()
|
||||||
break
|
break
|
||||||
case "skills":
|
case "skills": {
|
||||||
context.tab = context.tabs.skills
|
context.tab = context.tabs.skills
|
||||||
context.skills = doc.itemTypes.skill
|
context.skills = doc.itemTypes.skill
|
||||||
|
// Organiser les skills par catégorie
|
||||||
|
const categories = ['layperson', 'professional', 'weapon', 'armor', 'resist']
|
||||||
|
context.skillsByCategory = categories.map(cat => {
|
||||||
|
return {
|
||||||
|
category: cat,
|
||||||
|
label: `LETHALFANTASY.Skill.Category.${cat}`,
|
||||||
|
skills: context.skills.filter(s => s.system.category === cat)
|
||||||
|
}
|
||||||
|
}).filter(catData => catData.skills.length > 0)
|
||||||
context.gifts = doc.itemTypes.gift
|
context.gifts = doc.itemTypes.gift
|
||||||
context.vulnerabilities = doc.itemTypes.vulnerability
|
context.vulnerabilities = doc.itemTypes.vulnerability
|
||||||
break
|
break
|
||||||
|
}
|
||||||
case "spells":
|
case "spells":
|
||||||
context.tab = context.tabs.spells
|
context.tab = context.tabs.spells
|
||||||
context.spells = doc.itemTypes.spell
|
context.spells = doc.itemTypes.spell
|
||||||
@@ -127,8 +137,8 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
|
|||||||
break
|
break
|
||||||
case "biography":
|
case "biography":
|
||||||
context.tab = context.tabs.biography
|
context.tab = context.tabs.biography
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.description, { async: true })
|
||||||
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
|
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.notes, { async: true })
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
@@ -143,18 +153,17 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
|
|||||||
*/
|
*/
|
||||||
async _onDrop(event) {
|
async _onDrop(event) {
|
||||||
if (!this.isEditable || !this.isEditMode) return
|
if (!this.isEditable || !this.isEditMode) return
|
||||||
const data = TextEditor.getDragEventData(event)
|
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||||
|
|
||||||
// Handle different data types
|
// Handle different data types
|
||||||
switch (data.type) {
|
if (data.type === "Item") {
|
||||||
case "Item":
|
const item = await fromUuid(data.uuid)
|
||||||
const item = await fromUuid(data.uuid)
|
return this._onDropItem(item)
|
||||||
return this._onDropItem(item)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onRangedAttackDefense(event, target) {
|
static async #onRangedAttackDefense(event, target) {
|
||||||
const hasTarget = false
|
// Future use : const hasTarget = false
|
||||||
|
|
||||||
let roll = await LethalFantasyRoll.promptRangedDefense({
|
let roll = await LethalFantasyRoll.promptRangedDefense({
|
||||||
actorId: this.actor.id,
|
actorId: this.actor.id,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasyEquipmentSheet extends LethalFantasyItemSheet
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,4 @@ export default class LethalFantasyGiftSheet extends LethalFantasyItemSheet {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
|
||||||
async _prepareContext() {
|
|
||||||
const context = await super._prepareContext()
|
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasyMiracleSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,6 @@ export default class LethalFantasyMonsterSheet extends LethalFantasyActorSheet {
|
|||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
_generateTooltip(type, target) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
async _preparePartContext(partId, context) {
|
async _preparePartContext(partId, context) {
|
||||||
const doc = this.document
|
const doc = this.document
|
||||||
@@ -78,8 +75,8 @@ export default class LethalFantasyMonsterSheet extends LethalFantasyActorSheet {
|
|||||||
break
|
break
|
||||||
case "biography":
|
case "biography":
|
||||||
context.tab = context.tabs.biography
|
context.tab = context.tabs.biography
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.description, { async: true })
|
||||||
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
|
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.notes, { async: true })
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
@@ -165,9 +162,11 @@ export default class LethalFantasyMonsterSheet extends LethalFantasyActorSheet {
|
|||||||
|
|
||||||
async _onRoll(event, target) {
|
async _onRoll(event, target) {
|
||||||
if (this.isEditMode) return
|
if (this.isEditMode) return
|
||||||
const rollType = event.target.dataset.rollType
|
const rollable = event.target.closest('.rollable')
|
||||||
let rollKey = event.target.dataset.rollKey
|
if (!rollable) return
|
||||||
let rollDice = event.target.dataset?.rollDice || "0"
|
const rollType = rollable.dataset.rollType
|
||||||
|
let rollKey = rollable.dataset.rollKey
|
||||||
|
let rollDice = rollable.dataset?.rollDice || "0"
|
||||||
this.actor.system.prepareMonsterRoll(rollType, rollKey, rollDice)
|
this.actor.system.prepareMonsterRoll(rollType, rollKey, rollDice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasyShieldSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasySkillSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasySpellSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasyVulnerabilitySheet extends LethalFantasyItemSh
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet {
|
|||||||
/** @override */
|
/** @override */
|
||||||
async _prepareContext() {
|
async _prepareContext() {
|
||||||
const context = await super._prepareContext()
|
const context = await super._prepareContext()
|
||||||
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
|
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
152
module/config/d30_results_tables.json
Normal file
152
module/config/d30_results_tables.json
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
{
|
||||||
|
"d30_dice_results": {
|
||||||
|
"30": {
|
||||||
|
"melee_attack": "Possible Lethal or Vital Strike or Add D20E to Attack",
|
||||||
|
"ranged_attack": "Possible Lethal or Vital Strike or Add D20E to Attack",
|
||||||
|
"melee_defense": "Possible Flawless or Legendary Defense or Add D20E to Defense",
|
||||||
|
"arcane_spell_attack": "Possible Lethal or Vital Magical Strike or Add D20E to Spell Attack",
|
||||||
|
"arcane_spell_defense": "Possible Spell Catastrophe or adds D20E to Spell Defense",
|
||||||
|
"skill_rolls": "Skill Succeeds Regardless of Opposing Roll / Success at highest level / Matching 30s cancel each other out"
|
||||||
|
},
|
||||||
|
"29": {
|
||||||
|
"melee_attack": "Gain 1 Grit",
|
||||||
|
"ranged_attack": "Gain 1 Grit",
|
||||||
|
"melee_defense": "Gain 1 Grit",
|
||||||
|
"arcane_spell_attack": "Gain 1 Grit",
|
||||||
|
"arcane_spell_defense": "Gain 1 Grit",
|
||||||
|
"skill_rolls": "Gain 1 Grit"
|
||||||
|
},
|
||||||
|
"28": {
|
||||||
|
"melee_attack": "Shield Destruction",
|
||||||
|
"ranged_attack": "empty",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"27": {
|
||||||
|
"melee_attack": "Granted D6 (1-6) Attack Modifier for This Melee Attack",
|
||||||
|
"ranged_attack": "Granted D6 (1-6) Attack Modifier for This Ranged Attack",
|
||||||
|
"melee_defense": "Granted 1 Luck dice for Use in This Combat Only",
|
||||||
|
"arcane_spell_attack": "No Spell Lethargy (the Aether Approves)",
|
||||||
|
"arcane_spell_defense": "Caster Suffers Severe pain and will be under a flash of pain for 1D6E seconds",
|
||||||
|
"skill_rolls": "Granted D6 (1-6) Skill Modifier for this Skill Attempt"
|
||||||
|
},
|
||||||
|
"26": {
|
||||||
|
"melee_attack": "Shield Destruction",
|
||||||
|
"ranged_attack": "empty",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"25": {
|
||||||
|
"melee_attack": "Bleed, Knock-Back on Hit",
|
||||||
|
"ranged_attack": "Bleed",
|
||||||
|
"melee_defense": "Kick, Punch or Shield Bash",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "Add 1 to Skill Roll"
|
||||||
|
},
|
||||||
|
"21": {
|
||||||
|
"melee_attack": "Hit Inflicts Flash of Pain 1D6E seconds",
|
||||||
|
"ranged_attack": "Hit Inflicts Flash of Pain 1D6E seconds",
|
||||||
|
"melee_defense": "Defender Recovers or ignores any flash of pain",
|
||||||
|
"arcane_spell_attack": "Magical Damage inflicts Flash of pain 1D6E seconds",
|
||||||
|
"arcane_spell_defense": "Caster Suffers Severe pain and will be under a flash of pain for 1D6E seconds",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"20": {
|
||||||
|
"melee_attack": "Possible Vicious Strike. Bleed, Knock-back on Hit",
|
||||||
|
"ranged_attack": "Possible Vicious Strike. Bleeding wound inflicted on hit.",
|
||||||
|
"melee_defense": "Possible 20/20 defense (avoids Any Attack Except a Lethal Strike). Grants a Kick, Punch or Shield Bash counter",
|
||||||
|
"arcane_spell_attack": "Possible Vicious Application of a Magical Attack",
|
||||||
|
"arcane_spell_defense": "Possible 20/20 Spell defense (Saves Against Any Magical Attack Except a Lethal Magical Strike)",
|
||||||
|
"skill_rolls": "20 Added to Skill Roll"
|
||||||
|
},
|
||||||
|
"15": {
|
||||||
|
"melee_attack": "Bleed, Knock-back on Hit",
|
||||||
|
"ranged_attack": "Bleed",
|
||||||
|
"melee_defense": "Kick, Punch or Shield Bash",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "Add 1 to Skill Roll"
|
||||||
|
},
|
||||||
|
"13": {
|
||||||
|
"melee_attack": "empty",
|
||||||
|
"ranged_attack": "empty",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"11": {
|
||||||
|
"melee_attack": "Flurry Attack or Hit to Miss",
|
||||||
|
"ranged_attack": "Roll 2x Damage Dice",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"melee_attack": "Bleed, Knock-back on Hit",
|
||||||
|
"ranged_attack": "Bleed",
|
||||||
|
"melee_defense": "Kick, Punch or Shield Bash",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "Add 1 to Skill Roll"
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"melee_attack": "Mulligan, Can Choose to Re-roll This Attack",
|
||||||
|
"ranged_attack": "Mulligan, Can Choose to Re-Roll This Attack",
|
||||||
|
"melee_defense": "Mulligan, Can Choose to Re-Roll This Defense",
|
||||||
|
"arcane_spell_attack": "Mulligan, Can Re-Roll This Spell Attack",
|
||||||
|
"arcane_spell_defense": "Mulligan, Can Re-Roll This Spell Defense",
|
||||||
|
"skill_rolls": "Mulligan, Can Re-Roll This Skill roll"
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"melee_attack": "Flurry Attack on Hit or Miss",
|
||||||
|
"ranged_attack": "Roll 2x Double Damage Dice",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"melee_attack": "Bleed, Knock-back on Hit",
|
||||||
|
"ranged_attack": "Bleed",
|
||||||
|
"melee_defense": "Kick, Punch, or Shield Bash",
|
||||||
|
"arcane_spell_attack": "empty",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "Add 1 to Skill Roll"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"melee_attack": "Triple Damage",
|
||||||
|
"ranged_attack": "Triple Damage",
|
||||||
|
"melee_defense": "DR Tripled including Shield",
|
||||||
|
"arcane_spell_attack": "Triple Damage on Spell Damage",
|
||||||
|
"arcane_spell_defense": "D12 Added to Spell Defense Modifier",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"melee_attack": "Double Damage",
|
||||||
|
"ranged_attack": "Double Damage",
|
||||||
|
"melee_defense": "DR Doubled including Shield",
|
||||||
|
"arcane_spell_attack": "Double Damage on Spell Damage",
|
||||||
|
"arcane_spell_defense": "D6 Added to Spell Defense Modifier",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"melee_attack": "empty",
|
||||||
|
"ranged_attack": "Possible Fumble Ranged ammo is broken unrecoverable",
|
||||||
|
"melee_defense": "empty",
|
||||||
|
"arcane_spell_attack": "Possible Spell Calamity or Catastrophe",
|
||||||
|
"arcane_spell_defense": "empty",
|
||||||
|
"skill_rolls": "empty"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"flash_of_pain": "Causes the victim to defend with disfavor. They can only walk and cannot attack, cast spells, call miracles or perform skills.",
|
||||||
|
"shield_destruction_condition": "Occurs only if damage exceeds the shields DR."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,118 +44,121 @@ export const MONEY = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const MORTAL_CHOICES = {
|
export const MORTAL_CHOICES = {
|
||||||
"mankind": {label: "Mankind", value: "Mankind", defenseBonus: 0},
|
"mankind": { label: "Mankind", id: "mankind", defenseBonus: 0 },
|
||||||
"elf": {label: "Elf", value: "Elf", defenseBonus: 0},
|
"elf": { label: "Elf", id: "elf", defenseBonus: 0 },
|
||||||
"dwarf": {label: "Dwarf", value: "Dwarf", defenseBonus: 0},
|
"dwarf": { label: "Dwarf", id: "dwarf", defenseBonus: 0 },
|
||||||
"halfelf": {label: "Half-Elf", value: "Half-Elf", defenseBonus: 0},
|
"halfelf": { label: "Half-Elf", id: "halfelf", defenseBonus: 0 },
|
||||||
"halforc": {label: "Half-Orc", value: "Half-Orc", defenseBonus: 0},
|
"halforc": { label: "Half-Orc", id: "halforc", defenseBonus: 0 },
|
||||||
"gnome": {label: "Gnome", value: "Gnome", defenseBonus: 2},
|
"gnome": { label: "Gnome", id: "gnome", defenseBonus: 2 },
|
||||||
"shirefolk": {label: "Shire Folk", value: "Shire Folk", defenseBonus: 2},
|
"halflings": { label: "Halfling", id: "halflings", defenseBonus: 2 }
|
||||||
"Elf": {label: "Elf", value: "Elf", defenseBonus: 0},
|
|
||||||
"Half-orc": {label: "Half-Orc", value: "Half-Orc", defenseBonus: 0},
|
|
||||||
"Half-Orc": {label: "Half-Orc", value: "Half-Orc", defenseBonus: 0},
|
|
||||||
"Dwarf": {label: "Dwarf", value: "Dwarf", defenseBonus: 0},
|
|
||||||
"Half-elf": {label: "Half-Elf", value: "Half-Elf", defenseBonus: 0},
|
|
||||||
"Gnome": {label: "Gnome", value: "Gnome", defenseBonus: 2},
|
|
||||||
"Shire Folk": {label: "Shire Folk", value: "Shire Folk", defenseBonus: 2},
|
|
||||||
"Shire folk": {label: "Shire Folk", value: "Shire Folk", defenseBonus: 2},
|
|
||||||
"Mankind": {label: "Human", value: "Human", defenseBonus: 0},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FAVOR_CHOICES = {
|
export const FAVOR_CHOICES = {
|
||||||
"none": {label: "None", value: "none"},
|
"none": { label: "None", value: "none" },
|
||||||
"favor": {label: "Favor", value: "favor"},
|
"favor": { label: "Favor", value: "favor" },
|
||||||
"disfavor": {label: "Disfavor", value: "disfavor"}
|
"disfavor": { label: "Disfavor", value: "disfavor" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MOVEMENT_CHOICES = {
|
export const MOVEMENT_CHOICES = {
|
||||||
"none": {label: "None (D8E)", value: "D8"},
|
"none": { label: "None (D20E Disfavor)", disfavor: true, value: "2D20kl" },
|
||||||
"walk": {label: "Walk (D10E)", value: "D10"},
|
"walk": { label: "Walk (D20E)", disfavor: true, value: "D20" },
|
||||||
"jog": {label: "Jog (D12E)", value: "D12"},
|
"incombat": { label: "In Combat (D20E)", favor: false, value: "D20" },
|
||||||
"run": {label: "Run (D20E)", value: "D20"},
|
"run": { label: "Jog/Run/Sprint (D20E Favor)", favor: true, value: "2D20kh" }
|
||||||
"incombat": {label: "In Combat (D12E)", value: "D12"}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MOVE_DIRECTION_CHOICES = {
|
export const MOVE_DIRECTION_CHOICES = {
|
||||||
"none": {label: "None (+0)", value: "0"},
|
"away": { label: "Away (+0)", value: "+0" },
|
||||||
"away": {label: "Away (+4)", value: "+4"},
|
"toward": { label: "Toward (0)", value: "0" },
|
||||||
"toward": {label: "Toward (+0)", value: "0"},
|
"lateral": { label: "Lateral (Red +5)", value: "+5" },
|
||||||
"lateral": {label: "Lateral (+10)", value: "+10"}
|
"none": { label: "None (+0)", value: "0" },
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SIZE_CHOICES = {
|
export const SIZE_CHOICES = {
|
||||||
"tiny": {label: "Tiny (+10)", value: "+10"},
|
"tiny": { label: "Tiny (Blue +11)", value: "+11" },
|
||||||
"small": {label: "Small (+5)", value: "+5"},
|
"small": { label: "Small (Purple +7)", value: "+7" },
|
||||||
"medium": {label: "Medium (+0)", value: "0"},
|
"medium": { label: "Medium (Red +5)", value: "+5" },
|
||||||
"huge": {label: "Huge (-10)", value: "-10"}
|
"large": { label: "Large (Yellow +1)", value: "+1" },
|
||||||
|
"huge": { label: "Huge (0)", value: "0" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RANGE_CHOICES = {
|
export const RANGE_CHOICES = {
|
||||||
"pointblank": {label: "Point Blank (-5)", value: "-5"},
|
"pointblank": { label: "Point Blank (Special)", value: "pointblank" },
|
||||||
"short": {label: "Short (+0)", value: "0"},
|
"short": { label: "Short (+0)", value: "0" },
|
||||||
"medium": {label: "Medium (+8)", value: "+8"},
|
"medium": { label: "Medium (Red +5)", value: "+5" },
|
||||||
"long": {label: "Long (+15)", value: "+15"},
|
"long": { label: "Long (Purle +7)", value: "+7" },
|
||||||
"extreme": {label: "Extreme (+20)", value: "+20"},
|
"extreme": { label: "Extreme (Grey +9)", value: "+9" },
|
||||||
"beyondskill": {label: "Beyond Skill (+25)", value: "+25"}
|
"beyondskill": { label: "Beyond Skill (Blue +11)", value: "beyondskill" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ATTACKER_AIM_CHOICES = {
|
export const ATTACKER_AIM_CHOICES = {
|
||||||
"simple": {label: "Simple (+0)", value: "0"},
|
"simple": { label: "Simple (+0)", value: "0" },
|
||||||
"careful": {label: "Careful (-4)", value: "-4"},
|
"careful": { label: "Careful (Red +5)", value: "+4" },
|
||||||
"focused": {label: "Focused (-8)", value: "-8"}
|
"focused": { label: "Focused (Grey +9)", value: "+9" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SPELL_LETHARGY_DICE = [
|
export const SPELL_LETHARGY_DICE = [
|
||||||
{dice: "D6", level: "1-5", value: "6", maxLevel: 5},
|
{ dice: "D6", level: "1-5", value: "6", maxLevel: 5 },
|
||||||
{dice: "D8", level: "6-10", value: "8", maxLevel: 10},
|
{ dice: "D8", level: "6-10", value: "8", maxLevel: 10 },
|
||||||
{dice: "D10", value: "10", level: "11-15", maxLevel: 15},
|
{ dice: "D10", value: "10", level: "11-15", maxLevel: 15 },
|
||||||
{dice: "D12", value: "12", level: "16-20", maxLevel: 20},
|
{ dice: "D12", value: "12", level: "16-20", maxLevel: 20 },
|
||||||
{dice: "D20", value: "20", level: "21-25", maxLevel: 25}
|
{ dice: "D20", value: "20", level: "21-25", maxLevel: 25 }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const GRANTED_DICE_CHOICES = {
|
||||||
|
"0": { label: "None", value: "0" },
|
||||||
|
"D2": { label: "D2", value: "D2" },
|
||||||
|
"D3": { label: "D3", value: "D3" },
|
||||||
|
"D4": { label: "D4", value: "D4" },
|
||||||
|
"D6": { label: "D6", value: "D6" },
|
||||||
|
"D8": { label: "D8", value: "D8" },
|
||||||
|
"D10": { label: "D10", value: "D10" },
|
||||||
|
"D12": { label: "D12", value: "D12" },
|
||||||
|
"D20": { label: "D20", value: "D20" }
|
||||||
|
}
|
||||||
|
|
||||||
export const INITIATIVE_DICE_CHOICES_PER_CLASS = {
|
export const INITIATIVE_DICE_CHOICES_PER_CLASS = {
|
||||||
"untrained": [
|
"untrained": [
|
||||||
{ "name": "Asleep or totally distracted (2D12)", "value": "2D12" },
|
{ "name": "Asleep or totally distracted (2D12)", "value": "2D12" },
|
||||||
{ "name": "Awake but unsuspecting (2D8)", "value": "2D8" },
|
{ "name": "Awake but unsuspecting (2D8)", "value": "2D8" },
|
||||||
{ "name": "Declared Ready on Alert (2D6)", "value": "2D6" },
|
{ "name": "Declared Ready on Alert (2D6)", "value": "2D6" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (2D4)", "value": "2D4" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (2D4)", "value": "2D4" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (2D3)", "value": "2D3" }
|
{ "name": "Aware and know exactly where the enemy is (2D3)", "value": "2D3" }*/
|
||||||
],
|
],
|
||||||
"fighter": [
|
"fighter": [
|
||||||
{ "name": "Asleep or totally distracted (1D12)", "value": "1D12" },
|
{ "name": "Asleep or totally distracted (1D12)", "value": "1D12" },
|
||||||
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
||||||
{ "name": "Declared Ready on Alert (1D6)", "value": "1D6" },
|
{ "name": "Declared Ready on Alert (1)", "value": "1" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (1D4)", "value": "1D4" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (1D4)", "value": "1D4" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (1D3)", "value": "1D3" }
|
{ "name": "Aware and know exactly where the enemy is (1D3)", "value": "1D3" }*/
|
||||||
],
|
],
|
||||||
"rogue": [
|
"rogue": [
|
||||||
{ "name": "Asleep or totally distracted (1D10)", "value": "1D10" },
|
{ "name": "Asleep or totally distracted (1D10)", "value": "1D10" },
|
||||||
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
||||||
{ "name": "Declared Ready on Alert (1D6)", "value": "1D6" },
|
{ "name": "Declared Ready on Alert (1)", "value": "1" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (1D3)", "value": "1D3" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (1D3)", "value": "1D3" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (1D2)", "value": "1D2" }
|
{ "name": "Aware and know exactly where the enemy is (1D2)", "value": "1D2" }*/
|
||||||
],
|
],
|
||||||
"ranger": [
|
"ranger": [
|
||||||
{ "name": "Asleep or totally distracted (1D10)", "value": "1D10" },
|
{ "name": "Asleep or totally distracted (1D10)", "value": "1D10" },
|
||||||
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
{ "name": "Awake but unsuspecting (1D8)", "value": "1D8" },
|
||||||
{ "name": "Declared Ready on Alert (1D6)", "value": "1D6" },
|
{ "name": "Declared Ready on Alert (1)", "value": "1" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (1D4)", "value": "1D4" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (1D4)", "value": "1D4" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (1D3)", "value": "1D3"}
|
{ "name": "Aware and know exactly where the enemy is (1D3)", "value": "1D3" }*/
|
||||||
],
|
],
|
||||||
"cleric": [
|
"cleric": [
|
||||||
{ "name": "Asleep or totally distracted (1D12)", "value": "1D12" },
|
{ "name": "Asleep or totally distracted (1D12)", "value": "1D12" },
|
||||||
{ "name": "Awake but unsuspecting (1D10)", "value": "1D10" },
|
{ "name": "Awake but unsuspecting (1D10)", "value": "1D10" },
|
||||||
{ "name": "Declared Ready on Alert (1D8)", "value": "1D8" },
|
{ "name": "Declared Ready on Alert (1)", "value": "1" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (1D6)", "value": "1D6" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (1D6)", "value": "1D6" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (1D4)", "value": "1D4" }
|
{ "name": "Aware and know exactly where the enemy is (1D4)", "value": "1D4" }*/
|
||||||
],
|
],
|
||||||
"magicuser": [
|
"magicuser": [
|
||||||
{ "name": "Sleeping to recover Aether Points (2D20)", "value": "2D20" },
|
{ "name": "Sleeping to recover Aether Points (2D20)", "value": "2D20" },
|
||||||
{ "name": "Asleep or totally distracted (1D20)", "value": "1D20" },
|
{ "name": "Asleep or totally distracted (1D20)", "value": "1D20" },
|
||||||
{ "name": "Awake but unsuspecting (1D12)", "value": "1D12" },
|
{ "name": "Awake but unsuspecting (1D12)", "value": "1D12" },
|
||||||
{ "name": "Declared Ready on Alert (1D10)", "value": "1D10" },
|
{ "name": "Declared Ready on Alert (1)", "value": "1" },
|
||||||
{ "name": "Aware of the enemy, can hear them but not see (1D8)", "value": "1D8" },
|
/*{ "name": "Aware of the enemy, can hear them but not see (1D8)", "value": "1D8" },
|
||||||
{ "name": "Aware and know exactly where the enemy is (1D6)", "value": "1D6" }
|
{ "name": "Aware and know exactly where the enemy is (1D6)", "value": "1D6" }*/
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,12 +172,12 @@ export const CHAR_CLASSES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CHAR_CLASSES_DEFINES = {
|
export const CHAR_CLASSES_DEFINES = {
|
||||||
"untrained": {id: "untrained", label: "Untrained"},
|
"untrained": { id: "untrained", label: "Untrained" },
|
||||||
"fighter": {id: "fighter", label: "Fighter"},
|
"fighter": { id: "fighter", label: "Fighter" },
|
||||||
"rogue": {id: "rogue", label: "Rogue"},
|
"rogue": { id: "rogue", label: "Rogue" },
|
||||||
"ranger": {id: "ranger", label: "Ranger"},
|
"ranger": { id: "ranger", label: "Ranger" },
|
||||||
"cleric": {id: "cleric", label: "Cleric"},
|
"cleric": { id: "cleric", label: "Cleric" },
|
||||||
"magicuser": {id: "magicuser", label: "Magic User"}
|
"magicuser": { id: "magicuser", label: "Magic User" }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DICE_VALUES = {
|
export const DICE_VALUES = {
|
||||||
@@ -187,10 +190,10 @@ export const DICE_VALUES = {
|
|||||||
"d20": "D20"
|
"d20": "D20"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CHARACTERISTIC_ATTACK = [ "str", "int", "wis", "dex"]
|
export const CHARACTERISTIC_ATTACK = ["str", "int", "wis", "dex"]
|
||||||
export const CHARACTERISTIC_RANGED_ATTACK = [ "int", "wis", "dex"]
|
export const CHARACTERISTIC_RANGED_ATTACK = ["int", "wis", "dex"]
|
||||||
export const CHARACTERISTIC_DEFENSE = [ "int", "wis", "dex" ]
|
export const CHARACTERISTIC_DEFENSE = ["int", "wis", "dex"]
|
||||||
export const CHARACTERISTIC_DAMAGE = [ "str" ]
|
export const CHARACTERISTIC_DAMAGE = ["str"]
|
||||||
|
|
||||||
export const DEFENSE_DICE_VALUES = {
|
export const DEFENSE_DICE_VALUES = {
|
||||||
"0": "0",
|
"0": "0",
|
||||||
@@ -226,41 +229,41 @@ export const SPELL_CRITICAL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CHOICE_MODIFIERS = {
|
export const CHOICE_MODIFIERS = {
|
||||||
"-9": "-9",
|
"-9": "-9",
|
||||||
"-8": "-8",
|
"-8": "-8",
|
||||||
"-7": "-7",
|
"-7": "-7",
|
||||||
"-6": "-6",
|
"-6": "-6",
|
||||||
"-5": "-5",
|
"-5": "-5",
|
||||||
"-4": "-4",
|
"-4": "-4",
|
||||||
"-3": "-3",
|
"-3": "-3",
|
||||||
"-2": "-2",
|
"-2": "-2",
|
||||||
"-1": "-1",
|
"-1": "-1",
|
||||||
"+0": "0",
|
"+0": "0",
|
||||||
"+1": "+1",
|
"+1": "+1",
|
||||||
"+2": "+2",
|
"+2": "+2",
|
||||||
"+3": "+3",
|
"+3": "+3",
|
||||||
"+4": "+4",
|
"+4": "+4",
|
||||||
"+5": "+5",
|
"+5": "+5",
|
||||||
"+6": "+6",
|
"+6": "+6",
|
||||||
"+7": "+7",
|
"+7": "+7",
|
||||||
"+8": "+8",
|
"+8": "+8",
|
||||||
"+9": "+9",
|
"+9": "+9",
|
||||||
"+10": "+10",
|
"+10": "+10",
|
||||||
"+11": "+11",
|
"+11": "+11",
|
||||||
"+12": "+12",
|
"+12": "+12",
|
||||||
"+13": "+13",
|
"+13": "+13",
|
||||||
"+14": "+14",
|
"+14": "+14",
|
||||||
"+15": "+15",
|
"+15": "+15",
|
||||||
"+16": "+16",
|
"+16": "+16",
|
||||||
"+17": "+17",
|
"+17": "+17",
|
||||||
"+18": "+18",
|
"+18": "+18",
|
||||||
"+19": "+19",
|
"+19": "+19",
|
||||||
"+20": "+20",
|
"+20": "+20",
|
||||||
"+21": "+21",
|
"+21": "+21",
|
||||||
"+22": "+22",
|
"+22": "+22",
|
||||||
"+23": "+23",
|
"+23": "+23",
|
||||||
"+24": "+24",
|
"+24": "+24",
|
||||||
"+25": "+25"
|
"+25": "+25"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ASCII = `
|
export const ASCII = `
|
||||||
@@ -319,5 +322,6 @@ export const SYSTEM = {
|
|||||||
MORTAL_CHOICES,
|
MORTAL_CHOICES,
|
||||||
SPELL_CRITICAL,
|
SPELL_CRITICAL,
|
||||||
MIRACLE_TYPES,
|
MIRACLE_TYPES,
|
||||||
SPELL_LETHARGY_DICE
|
SPELL_LETHARGY_DICE,
|
||||||
|
GRANTED_DICE_CHOICES
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ export { default as LethalFantasyActor } from "./actor.mjs"
|
|||||||
export { default as LethalFantasyItem } from "./item.mjs"
|
export { default as LethalFantasyItem } from "./item.mjs"
|
||||||
export { default as LethalFantasyRoll } from "./roll.mjs"
|
export { default as LethalFantasyRoll } from "./roll.mjs"
|
||||||
export { default as LethalFantasyChatMessage } from "./chat-message.mjs"
|
export { default as LethalFantasyChatMessage } from "./chat-message.mjs"
|
||||||
|
export { default as D30Roll } from "./d30-roll.mjs"
|
||||||
|
|||||||
@@ -65,13 +65,96 @@ export default class LethalFantasyActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goodSkill.weaponSkillModifier = maxValue * multiplier
|
goodSkill.weaponSkillModifier = Math.ceil(maxValue * multiplier)
|
||||||
return goodSkill
|
return goodSkill
|
||||||
}
|
}
|
||||||
|
|
||||||
/* *************************************************/
|
/* *************************************************/
|
||||||
async prepareRoll(rollType, rollKey, rollDice ) {
|
async applyDamage(hpLoss) {
|
||||||
console.log("Preparing roll", rollType, rollKey, rollDice)
|
let hp = this.system.hp.value + hpLoss
|
||||||
|
if (hp < 0) {
|
||||||
|
hp = 0
|
||||||
|
}
|
||||||
|
this.update({ "system.hp.value": hp })
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
computeDamageReduction() {
|
||||||
|
// Pour les monstres, utiliser hp.damageResistance et combat.damageReduction
|
||||||
|
if (this.type === "monster") {
|
||||||
|
let hpDR = Number(this.system.hp?.damageResistance) || 0
|
||||||
|
let combatDR = Number(this.system.combat?.damageReduction) || 0
|
||||||
|
return hpDR + combatDR
|
||||||
|
}
|
||||||
|
// Pour les personnages, utiliser biodata et items
|
||||||
|
let naturalDR = Number(this.system.biodata?.naturalDR) || 0
|
||||||
|
let magicDR = Number(this.system.biodata?.magicDR) || 0
|
||||||
|
let armorDR = this.getArmorDR()
|
||||||
|
return naturalDR + magicDR + armorDR
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
getShieldDR() {
|
||||||
|
// Pour les monstres, utiliser combat.shieldDamageReduction
|
||||||
|
if (this.type === "monster") {
|
||||||
|
return Number(this.system.combat?.shieldDamageReduction) || 0
|
||||||
|
}
|
||||||
|
// Pour les personnages, utiliser les items de type shield
|
||||||
|
let dr = 0
|
||||||
|
for (let item of this.items) {
|
||||||
|
if (item.type === "shield" && item.system.equipped) {
|
||||||
|
dr += Number(item.system.damageReduction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dr
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
getArmorDR() {
|
||||||
|
let dr = 0
|
||||||
|
for (let item of this.items) {
|
||||||
|
if (item.type === "armor" && item.system.equipped) {
|
||||||
|
dr += Number(item.system.damageReduction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dr
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
getArmorDefenseValue() {
|
||||||
|
let defenseValue = 0
|
||||||
|
for (let item of this.items) {
|
||||||
|
if (item.type === "armor" && item.system.equipped) {
|
||||||
|
defenseValue += Number(item.system.defense)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defenseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
fuzzyNameSearchWeaponSkills(weaponName, weaponClass = null) {
|
||||||
|
// Get all weapon skills without the " skill" suffix
|
||||||
|
let skills = this.items.filter((i) => i.type === "skill" && i.system.weaponClass === weaponClass && i.system.category === "weapon")
|
||||||
|
// Remove parenthesis in the weapon name for better matching
|
||||||
|
weaponName = weaponName.replace(/\(.*?\)/g, "").trim()
|
||||||
|
// Now search if we find all the words of the weapon name in the skill name
|
||||||
|
skills = skills.filter((s) => {
|
||||||
|
let skillName = s.name.toLowerCase().replace(" skill", "").trim()
|
||||||
|
let wName = weaponName.toLowerCase().trim()
|
||||||
|
let wWords = wName.split(" ")
|
||||||
|
for (let w of wWords) {
|
||||||
|
if (!skillName.includes(w)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return skills
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *************************************************/
|
||||||
|
async prepareRoll(rollType, rollKey, rollDice, defenderId) {
|
||||||
|
console.log("Preparing roll", rollType, rollKey, rollDice, defenderId)
|
||||||
let rollTarget
|
let rollTarget
|
||||||
switch (rollType) {
|
switch (rollType) {
|
||||||
case "granted":
|
case "granted":
|
||||||
@@ -80,7 +163,7 @@ export default class LethalFantasyActor extends Actor {
|
|||||||
formula: foundry.utils.duplicate(this.system.granted[rollKey]),
|
formula: foundry.utils.duplicate(this.system.granted[rollKey]),
|
||||||
rollKey: rollKey
|
rollKey: rollKey
|
||||||
}
|
}
|
||||||
if ( rollTarget.formula === "" || rollTarget.formula === undefined) {
|
if (rollTarget.formula === "" || rollTarget.formula === undefined) {
|
||||||
rollTarget.formula = 0
|
rollTarget.formula = 0
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -117,60 +200,64 @@ export default class LethalFantasyActor extends Actor {
|
|||||||
rollTarget.rollKey = rollKey
|
rollTarget.rollKey = rollKey
|
||||||
break
|
break
|
||||||
case "shield-roll": {
|
case "shield-roll": {
|
||||||
rollTarget = this.items.find((i) => i.type === "shield" && i.id === rollKey)
|
rollTarget = this.items.find((i) => i.type === "shield" && i.id === rollKey)
|
||||||
let shieldSkill = this.items.find((i) => i.type === "skill" && i.name.toLowerCase() === rollTarget.name.toLowerCase())
|
let shieldSkill = this.items.find((i) => i.type === "skill" && i.name.toLowerCase() === rollTarget.name.toLowerCase())
|
||||||
rollTarget.skill = shieldSkill
|
rollTarget.skill = shieldSkill
|
||||||
rollTarget.rollKey = rollKey
|
rollTarget.rollKey = rollKey
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "weapon-damage-small":
|
case "weapon-damage-small":
|
||||||
case "weapon-damage-medium":
|
case "weapon-damage-medium":
|
||||||
case "weapon-attack":
|
case "weapon-attack":
|
||||||
case "weapon-defense": {
|
case "weapon-defense": {
|
||||||
let weapon = this.items.find((i) => i.type === "weapon" && i.id === rollKey)
|
let weapon = this.items.find((i) => i.type === "weapon" && i.id === rollKey)
|
||||||
let skill
|
let skill
|
||||||
let skills = this.items.filter((i) => i.type === "skill" && i.name.toLowerCase() === weapon.name.toLowerCase())
|
let skills = this.items.filter((i) => i.type === "skill" && i.system.category === "weapon" && i.name.toLowerCase() === weapon.name.toLowerCase())
|
||||||
|
if (skills.length > 0) {
|
||||||
|
skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
|
||||||
|
} else {
|
||||||
|
skills = this.fuzzyNameSearchWeaponSkills(weapon.name, weapon.system.weaponClass)
|
||||||
if (skills.length > 0) {
|
if (skills.length > 0) {
|
||||||
skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
|
skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
|
||||||
} else {
|
} else {
|
||||||
skills = this.items.filter((i) => i.type === "skill" && i.name.toLowerCase().replace(" skill", "") === weapon.name.toLowerCase())
|
skills = this.items.filter((i) => i.type === "skill" && i.system.category === "weapon" && i.system.weaponClass === weapon.system.weaponClass)
|
||||||
if (skills.length > 0) {
|
if (skills.length > 0) {
|
||||||
skill = this.getBestWeaponClassSkill(skills, rollType, 1.0)
|
skill = this.getBestWeaponClassSkill(skills, rollType, 0.5)
|
||||||
} else {
|
} else {
|
||||||
skills = this.items.filter((i) => i.type === "skill" && i.system.weaponClass === weapon.system.weaponClass)
|
skills = this.items.filter((i) => i.type === "skill" && i.system.category === "weapon" && i.system.weaponClass.includes(SYSTEM.WEAPON_CATEGORIES[weapon.system.weaponClass]))
|
||||||
if (skills.length > 0) {
|
if (skills.length > 0) {
|
||||||
skill = this.getBestWeaponClassSkill(skills, rollType, 0.5)
|
skill = this.getBestWeaponClassSkill(skills, rollType, 0.25)
|
||||||
} else {
|
} else {
|
||||||
skills = this.items.filter((i) => i.type === "skill" && i.system.weaponClass.includes(SYSTEM.WEAPON_CATEGORIES[weapon.system.weaponClass]))
|
ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
|
||||||
if (skills.length > 0) {
|
return
|
||||||
skill = this.getBestWeaponClassSkill(skills, rollType, 0.25)
|
|
||||||
} else {
|
|
||||||
ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!weapon || !skill) {
|
|
||||||
console.error("Weapon or skill not found", weapon, skill)
|
|
||||||
ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rollTarget = skill
|
|
||||||
rollTarget.weapon = weapon
|
|
||||||
rollTarget.weaponSkillModifier = skill.weaponSkillModifier
|
|
||||||
rollTarget.rollKey = rollKey
|
|
||||||
rollTarget.combat = foundry.utils.duplicate(this.system.combat)
|
|
||||||
if ( rollType === "weapon-damage-small" || rollType === "weapon-damage-medium") {
|
|
||||||
rollTarget.grantedDice = this.system.granted.damageDice
|
|
||||||
}
|
|
||||||
if ( rollType === "weapon-attack") {
|
|
||||||
rollTarget.grantedDice = this.system.granted.attackDice
|
|
||||||
}
|
|
||||||
if ( rollType === "weapon-defense") {
|
|
||||||
rollTarget.grantedDice = this.system.granted.defenseDice
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!weapon || !skill) {
|
||||||
|
console.error("Weapon or skill not found", weapon, skill)
|
||||||
|
ui.notifications.warn(game.i18n.localize("LETHALFANTASY.Notifications.skillNotFound"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Créer un objet plain au lieu de modifier directement le skill
|
||||||
|
rollTarget = {
|
||||||
|
...skill,
|
||||||
|
weapon: weapon,
|
||||||
|
weaponSkillModifier: skill.weaponSkillModifier,
|
||||||
|
rollKey: rollKey,
|
||||||
|
combat: foundry.utils.duplicate(this.system.combat)
|
||||||
|
}
|
||||||
|
if (rollType === "weapon-damage-small" || rollType === "weapon-damage-medium") {
|
||||||
|
rollTarget.grantedDice = this.system.granted.damageDice
|
||||||
|
}
|
||||||
|
if (rollType === "weapon-attack") {
|
||||||
|
rollTarget.grantedDice = this.system.granted.attackDice
|
||||||
|
}
|
||||||
|
if (rollType === "weapon-defense") {
|
||||||
|
rollTarget.armorDefense = this.getArmorDefenseValue()
|
||||||
|
rollTarget.grantedDice = this.system.granted.defenseDice
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
|
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
|
||||||
@@ -181,7 +268,7 @@ export default class LethalFantasyActor extends Actor {
|
|||||||
rollTarget.magicUser = this.system.biodata.magicUser
|
rollTarget.magicUser = this.system.biodata.magicUser
|
||||||
rollTarget.actorModifiers = foundry.utils.duplicate(this.system.modifiers)
|
rollTarget.actorModifiers = foundry.utils.duplicate(this.system.modifiers)
|
||||||
rollTarget.actorLevel = this.system.biodata.level
|
rollTarget.actorLevel = this.system.biodata.level
|
||||||
await this.system.roll(rollType, rollTarget)
|
await this.system.roll(rollType, rollTarget, defenderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
215
module/documents/d30-roll.mjs
Normal file
215
module/documents/d30-roll.mjs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/**
|
||||||
|
* Classe pour gérer les résultats du D30 dans Lethal Fantasy
|
||||||
|
*/
|
||||||
|
export default class D30Roll {
|
||||||
|
/**
|
||||||
|
* Table des résultats D30 chargée depuis le fichier JSON
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
static resultsTable = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définitions des conditions spéciales
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
static definitions = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types de jets supportés
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
static ROLL_TYPES = {
|
||||||
|
MELEE_ATTACK: "melee_attack",
|
||||||
|
RANGED_ATTACK: "ranged_attack",
|
||||||
|
MELEE_DEFENSE: "melee_defense",
|
||||||
|
ARCANE_SPELL_ATTACK: "arcane_spell_attack",
|
||||||
|
ARCANE_SPELL_DEFENSE: "arcane_spell_defense",
|
||||||
|
SKILL_ROLLS: "skill_rolls"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise la classe en chargeant la table des résultats
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async initialize() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("systems/fvtt-lethal-fantasy/module/config/d30_results_tables.json")
|
||||||
|
const data = await response.json()
|
||||||
|
|
||||||
|
this.resultsTable = data.d30_dice_results
|
||||||
|
this.definitions = data.definitions
|
||||||
|
|
||||||
|
console.log("D30Roll | D30 results table loaded successfully")
|
||||||
|
} catch (error) {
|
||||||
|
console.error("D30Roll | Error loading D30 table:", error)
|
||||||
|
ui.notifications.error("Unable to load D30 results table")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère le résultat d'un jet de D30
|
||||||
|
* @param {number} diceValue La valeur du dé (1-30)
|
||||||
|
* @param {string} rollType Le type de jet externe (ex: "weapon-attack", "spell-attack", etc.)
|
||||||
|
* @param {Object} weapon L'arme ou l'objet utilisé (optionnel, nécessaire pour certains types)
|
||||||
|
* @returns {string|null} Le résultat correspondant ou null si vide/non trouvé
|
||||||
|
*/
|
||||||
|
static getResult(diceValue, rollType, weapon = null) {
|
||||||
|
if (!this.resultsTable) {
|
||||||
|
console.warn("D30Roll | Results table is not initialized. Call D30Roll.initialize() first.")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation des paramètres
|
||||||
|
if (diceValue < 1 || diceValue > 30) {
|
||||||
|
console.warn(`D30Roll | Invalid dice value: ${diceValue}. Must be between 1 and 30.`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert external rollType to internal rollType
|
||||||
|
const internalType = this.convertToInternalType(rollType, weapon)
|
||||||
|
|
||||||
|
if (!internalType) {
|
||||||
|
console.warn(`D30Roll | Could not convert roll type: ${rollType}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.values(this.ROLL_TYPES).includes(internalType)) {
|
||||||
|
console.warn(`D30Roll | Invalid internal roll type: ${internalType}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultEntry = this.resultsTable[diceValue]
|
||||||
|
if (!resultEntry) {
|
||||||
|
console.warn(`D30Roll | No entry found for value ${diceValue}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = resultEntry[internalType]
|
||||||
|
|
||||||
|
// Retourne null si le résultat est "empty"
|
||||||
|
if (result === "empty" || !result) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convertit un rollType externe en rollType interne
|
||||||
|
* @param {string} externalType Le type de jet externe (ex: "weapon-attack")
|
||||||
|
* @param {Object} weapon L'arme ou l'objet utilisé (optionnel)
|
||||||
|
* @returns {string|null} Le type interne correspondant ou null
|
||||||
|
*/
|
||||||
|
static convertToInternalType(externalType, weapon = null) {
|
||||||
|
// Attack types - need weapon to determine if melee or ranged
|
||||||
|
if (externalType === "weapon-attack") {
|
||||||
|
if (!weapon) {
|
||||||
|
console.warn("D30Roll | Weapon object required for weapon-attack type")
|
||||||
|
return this.ROLL_TYPES.MELEE_ATTACK // Default to melee
|
||||||
|
}
|
||||||
|
return weapon.system?.weaponType === "ranged"
|
||||||
|
? this.ROLL_TYPES.RANGED_ATTACK
|
||||||
|
: this.ROLL_TYPES.MELEE_ATTACK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monster attacks - default to melee
|
||||||
|
if (externalType === "monster-attack") {
|
||||||
|
// Check if weapon object has range information
|
||||||
|
if (weapon?.system?.weaponType === "ranged") {
|
||||||
|
return this.ROLL_TYPES.RANGED_ATTACK
|
||||||
|
}
|
||||||
|
return this.ROLL_TYPES.MELEE_ATTACK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defense types
|
||||||
|
if (externalType === "weapon-defense" || externalType === "monster-defense") {
|
||||||
|
return this.ROLL_TYPES.MELEE_DEFENSE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spell types
|
||||||
|
if (externalType === "spell-attack" || externalType === "spell" || externalType === "spell-power") {
|
||||||
|
return this.ROLL_TYPES.ARCANE_SPELL_ATTACK
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skill types
|
||||||
|
if (externalType === "skill" || externalType === "monster-skill" ||
|
||||||
|
externalType === "save" || externalType === "challenge") {
|
||||||
|
return this.ROLL_TYPES.SKILL_ROLLS
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no match, return null
|
||||||
|
console.warn(`D30Roll | Unknown external roll type: ${externalType}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère toutes les informations pour une valeur de dé donnée
|
||||||
|
* @param {number} diceValue La valeur du dé (1-30)
|
||||||
|
* @returns {Object|null} Tous les résultats pour cette valeur ou null
|
||||||
|
*/
|
||||||
|
static getAllResultsForValue(diceValue) {
|
||||||
|
if (!this.resultsTable) {
|
||||||
|
console.warn("D30Roll | Results table is not initialized.")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diceValue < 1 || diceValue > 30) {
|
||||||
|
console.warn(`D30Roll | Invalid dice value: ${diceValue}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.resultsTable[diceValue]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère la définition d'une condition spéciale
|
||||||
|
* @param {string} definitionKey La clé de la définition (ex: "flash_of_pain")
|
||||||
|
* @returns {string|null} La définition ou null
|
||||||
|
*/
|
||||||
|
static getDefinition(definitionKey) {
|
||||||
|
if (!this.definitions) {
|
||||||
|
console.warn("D30Roll | Definitions are not initialized.")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.definitions[definitionKey] || null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si un résultat est vide
|
||||||
|
* @param {string} result Le résultat à vérifier
|
||||||
|
* @returns {boolean} True si le résultat est vide
|
||||||
|
*/
|
||||||
|
static isEmptyResult(result) {
|
||||||
|
return !result || result === "empty"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère un résultat formaté pour l'affichage
|
||||||
|
* @param {number} diceValue La valeur du dé (1-30)
|
||||||
|
* @param {string} rollType Le type de jet externe
|
||||||
|
* @param {Object} weapon L'arme ou l'objet utilisé (optionnel)
|
||||||
|
* @returns {Object} Un objet avec le résultat et des informations de formatage
|
||||||
|
*/
|
||||||
|
static getFormattedResult(diceValue, rollType, weapon = null) {
|
||||||
|
const result = this.getResult(diceValue, rollType, weapon)
|
||||||
|
const internalType = this.convertToInternalType(rollType, weapon)
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: diceValue,
|
||||||
|
rollType: rollType,
|
||||||
|
internalType: internalType,
|
||||||
|
result: result,
|
||||||
|
isEmpty: this.isEmptyResult(result),
|
||||||
|
hasResult: !this.isEmptyResult(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la table est chargée
|
||||||
|
* @returns {boolean} True si la table est chargée
|
||||||
|
*/
|
||||||
|
static isInitialized() {
|
||||||
|
return this.resultsTable !== null && this.definitions !== null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { SYSTEM } from "../config/system.mjs"
|
import { SYSTEM } from "../config/system.mjs"
|
||||||
import LethalFantasyUtils from "../utils.mjs"
|
import LethalFantasyUtils from "../utils.mjs"
|
||||||
|
import D30Roll from "./d30-roll.mjs"
|
||||||
|
|
||||||
export default class LethalFantasyRoll extends Roll {
|
export default class LethalFantasyRoll extends Roll {
|
||||||
/**
|
/**
|
||||||
@@ -92,10 +93,22 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
return this.options.D30result
|
return this.options.D30result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get D30message() {
|
||||||
|
return this.options.D30message
|
||||||
|
}
|
||||||
|
|
||||||
get badResult() {
|
get badResult() {
|
||||||
return this.options.badResult
|
return this.options.badResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rollData() {
|
||||||
|
return this.options.rollData
|
||||||
|
}
|
||||||
|
|
||||||
|
get defenderId() {
|
||||||
|
return this.options.defenderId
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompt the user with a dialog to configure and execute a roll.
|
* Prompt the user with a dialog to configure and execute a roll.
|
||||||
*
|
*
|
||||||
@@ -124,21 +137,24 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
let hasFavor = false
|
let hasFavor = false
|
||||||
let hasMaxValue = true
|
let hasMaxValue = true
|
||||||
let hasGrantedDice = false
|
let hasGrantedDice = false
|
||||||
|
let pointBlank = false
|
||||||
|
let letItFly = false
|
||||||
|
let saveSpell = false
|
||||||
|
let beyondSkill = false
|
||||||
let hasStaticModifier = false
|
let hasStaticModifier = false
|
||||||
let hasExplode = true
|
let hasExplode = true
|
||||||
|
let actor = game.actors.get(options.actorId)
|
||||||
|
|
||||||
if (options.rollType === "challenge" || options.rollType === "save") {
|
if (options.rollType === "challenge" || options.rollType === "save") {
|
||||||
options.rollName = game.i18n.localize(`LETHALFANTASY.Label.${options.rollTarget.rollKey}`)
|
options.rollName = game.i18n.localize(`LETHALFANTASY.Label.${options.rollTarget.rollKey}`)
|
||||||
hasD30 = options.rollType === "save"
|
hasD30 = options.rollType === "save"
|
||||||
if (options.rollTarget.rollKey === "dying") {
|
if (options.rollTarget.rollKey === "dying") {
|
||||||
dice = options.rollTarget.value
|
dice = options.rollTarget.value
|
||||||
maxValue = Number(options.rollTarget.value.match(/\d+/)[0])
|
|
||||||
hasModifier = false
|
hasModifier = false
|
||||||
hasChangeDice = true
|
hasChangeDice = true
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
} else {
|
} else {
|
||||||
dice = "1D20"
|
dice = "1D20"
|
||||||
maxValue = 20
|
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +164,6 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
dice = options.rollTarget.formula
|
dice = options.rollTarget.formula
|
||||||
baseFormula = options.rollTarget.formula
|
baseFormula = options.rollTarget.formula
|
||||||
hasModifier = false
|
hasModifier = false
|
||||||
maxValue = 100
|
|
||||||
hasMaxValue = false
|
hasMaxValue = false
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
hasFavor = false
|
hasFavor = false
|
||||||
@@ -158,7 +173,6 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
dice = "1D20"
|
dice = "1D20"
|
||||||
baseFormula = "D20"
|
baseFormula = "D20"
|
||||||
maxValue = 20
|
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
@@ -172,29 +186,27 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
|
|
||||||
} else if (options.rollType === "monster-skill") {
|
} else if (options.rollType === "monster-skill") {
|
||||||
options.rollName = game.i18n.localize(`LETHALFANTASY.Label.${options.rollTarget.rollKey}`)
|
options.rollName = game.i18n.localize(`LETHALFANTASY.Label.${options.rollTarget.rollKey}`)
|
||||||
dice = "1D100"
|
dice = "1D20"
|
||||||
baseFormula = "D100"
|
baseFormula = "D20"
|
||||||
maxValue = 100
|
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
|
|
||||||
} else if (options.rollType === "skill") {
|
} else if (options.rollType === "skill") {
|
||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
dice = "1D100"
|
hasD30 = true
|
||||||
baseFormula = "D100"
|
dice = "1D20"
|
||||||
maxValue = 100
|
baseFormula = "D20"
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
options.rollTarget.value = options.rollTarget.system.skillTotal
|
options.rollTarget.value = Math.floor(options.rollTarget.system.skillTotal / 10)
|
||||||
|
|
||||||
} else if (options.rollType === "weapon-attack" || options.rollType === "weapon-defense") {
|
} else if (options.rollType === "weapon-attack" || options.rollType === "weapon-defense") {
|
||||||
hasD30 = true
|
hasD30 = true
|
||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
dice = "1D20"
|
dice = "1D20"
|
||||||
baseFormula = "D20"
|
baseFormula = "D20"
|
||||||
maxValue = 20
|
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
hasFavor = true
|
hasFavor = true
|
||||||
@@ -207,7 +219,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
options.rollTarget.charModifier = options.rollTarget.combat.rangedAttackModifier
|
options.rollTarget.charModifier = options.rollTarget.combat.rangedAttackModifier
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
options.rollTarget.value = options.rollTarget.combat.defenseModifier + options.rollTarget.weaponSkillModifier + options.rollTarget.weapon.system.bonuses.defenseBonus
|
options.rollTarget.value = options.rollTarget.combat.defenseModifier + options.rollTarget.weaponSkillModifier + options.rollTarget.weapon.system.bonuses.defenseBonus + options.rollTarget.armorDefense
|
||||||
options.rollTarget.charModifier = options.rollTarget.combat.defenseModifier
|
options.rollTarget.charModifier = options.rollTarget.combat.defenseModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +228,6 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
dice = "1D20"
|
dice = "1D20"
|
||||||
baseFormula = "D20"
|
baseFormula = "D20"
|
||||||
maxValue = 20
|
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
options.rollTarget.value = options.rollTarget.actorModifiers.levelSpellModifier + options.rollTarget.actorModifiers.intSpellModifier
|
options.rollTarget.value = options.rollTarget.actorModifiers.levelSpellModifier + options.rollTarget.actorModifiers.intSpellModifier
|
||||||
@@ -234,7 +245,6 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
dice = "1D20"
|
dice = "1D20"
|
||||||
baseFormula = "D20"
|
baseFormula = "D20"
|
||||||
maxValue = 20
|
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
options.rollTarget.value = options.rollTarget.actorModifiers.levelMiracleModifier + options.rollTarget.actorModifiers.chaMiracleModifier
|
options.rollTarget.value = options.rollTarget.actorModifiers.levelMiracleModifier + options.rollTarget.actorModifiers.chaMiracleModifier
|
||||||
options.rollTarget.charModifier = options.rollTarget.actorModifiers.chaMiracleModifier
|
options.rollTarget.charModifier = options.rollTarget.actorModifiers.chaMiracleModifier
|
||||||
@@ -259,22 +269,25 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
|
|
||||||
} else if (options.rollType.includes("weapon-damage")) {
|
} else if (options.rollType.includes("weapon-damage")) {
|
||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
|
options.isDamage = true
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
let damageBonus = (options.rollTarget.weapon.system.applyStrengthDamageBonus) ? options.rollTarget.combat.damageModifier : 0
|
let damageBonus = (options.rollTarget.weapon.system.applyStrengthDamageBonus) ? options.rollTarget.combat.damageModifier : 0
|
||||||
options.rollTarget.value = damageBonus + options.rollTarget.weaponSkillModifier + options.rollTarget.weapon.system.bonuses.damageBonus
|
options.rollTarget.value = damageBonus + options.rollTarget.weaponSkillModifier + options.rollTarget.weapon.system.bonuses.damageBonus
|
||||||
options.rollTarget.charModifier = damageBonus
|
options.rollTarget.charModifier = damageBonus
|
||||||
if (options.rollType.includes("small")) {
|
if (options.rollType.includes("small")) {
|
||||||
|
options.damageSmall = true
|
||||||
dice = options.rollTarget.weapon.system.damage.damageS
|
dice = options.rollTarget.weapon.system.damage.damageS
|
||||||
} else {
|
} else {
|
||||||
|
options.damageMedium = true
|
||||||
dice = options.rollTarget.weapon.system.damage.damageM
|
dice = options.rollTarget.weapon.system.damage.damageM
|
||||||
}
|
}
|
||||||
dice = dice.replace("E", "")
|
dice = dice.replace("E", "")
|
||||||
baseFormula = dice
|
baseFormula = dice
|
||||||
maxValue = 20
|
|
||||||
|
|
||||||
} else if (options.rollType.includes("monster-damage")) {
|
} else if (options.rollType.includes("monster-damage")) {
|
||||||
options.rollName = options.rollTarget.name
|
options.rollName = options.rollTarget.name
|
||||||
|
options.isDamage = true
|
||||||
hasModifier = true
|
hasModifier = true
|
||||||
hasChangeDice = false
|
hasChangeDice = false
|
||||||
options.rollTarget.value = options.rollTarget.damageModifier
|
options.rollTarget.value = options.rollTarget.damageModifier
|
||||||
@@ -282,7 +295,6 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
dice = options.rollTarget.damageDice
|
dice = options.rollTarget.damageDice
|
||||||
dice = dice.replace("E", "")
|
dice = dice.replace("E", "")
|
||||||
baseFormula = dice
|
baseFormula = dice
|
||||||
maxValue = 20
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -292,7 +304,9 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
hasModifier = false
|
hasModifier = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); // v12 : Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||||
|
console.log("Roll mode", rollModes)
|
||||||
|
|
||||||
const fieldRollMode = new foundry.data.fields.StringField({
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
choices: rollModes,
|
choices: rollModes,
|
||||||
blank: false,
|
blank: false,
|
||||||
@@ -315,7 +329,10 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
hasModifier,
|
hasModifier,
|
||||||
hasFavor,
|
hasFavor,
|
||||||
hasChangeDice,
|
hasChangeDice,
|
||||||
|
pointBlank,
|
||||||
baseValue: options.rollTarget.value,
|
baseValue: options.rollTarget.value,
|
||||||
|
attackerAimChoices: SYSTEM.ATTACKER_AIM_CHOICES,
|
||||||
|
attackerAim: "0",
|
||||||
changeDice: `${dice}`,
|
changeDice: `${dice}`,
|
||||||
fieldRollMode,
|
fieldRollMode,
|
||||||
choiceModifier,
|
choiceModifier,
|
||||||
@@ -329,7 +346,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
favor: "none",
|
favor: "none",
|
||||||
targetName
|
targetName
|
||||||
}
|
}
|
||||||
const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/roll-dialog.hbs", dialogContext)
|
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/roll-dialog.hbs", dialogContext)
|
||||||
|
|
||||||
let position = game.user.getFlag(SYSTEM.id, "roll-dialog-pos") || { top: -1, left: -1 }
|
let position = game.user.getFlag(SYSTEM.id, "roll-dialog-pos") || { top: -1, left: -1 }
|
||||||
const label = game.i18n.localize("LETHALFANTASY.Roll.roll")
|
const label = game.i18n.localize("LETHALFANTASY.Roll.roll")
|
||||||
@@ -342,7 +359,8 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
{
|
{
|
||||||
label: label,
|
label: label,
|
||||||
callback: (event, button, dialog) => {
|
callback: (event, button, dialog) => {
|
||||||
let position = $(dialog).position()
|
console.log("Roll context", event, button, dialog)
|
||||||
|
let position = dialog.position
|
||||||
game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position))
|
game.user.setFlag(SYSTEM.id, "roll-dialog-pos", foundry.utils.duplicate(position))
|
||||||
const output = Array.from(button.form.elements).reduce((obj, input) => {
|
const output = Array.from(button.form.elements).reduce((obj, input) => {
|
||||||
if (input.name) obj[input.name] = input.value
|
if (input.name) obj[input.name] = input.value
|
||||||
@@ -354,9 +372,21 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
],
|
],
|
||||||
actions: {
|
actions: {
|
||||||
"selectGranted": (event, button, dialog) => {
|
"selectGranted": (event, button, dialog) => {
|
||||||
hasGrantedDice = true
|
hasGrantedDice = event.target.checked
|
||||||
},
|
},
|
||||||
"gotoToken" : (event, button, dialog) => {
|
"selectBeyondSkill": (event, button, dialog) => {
|
||||||
|
beyondSkill = button.checked
|
||||||
|
},
|
||||||
|
"selectPointBlank": (event, button, dialog) => {
|
||||||
|
pointBlank = button.checked
|
||||||
|
},
|
||||||
|
"selectLetItFly": (event, button, dialog) => {
|
||||||
|
letItFly = button.checked
|
||||||
|
},
|
||||||
|
"saveSpellCheck": (event, button, dialog) => {
|
||||||
|
saveSpell = button.checked
|
||||||
|
},
|
||||||
|
"gotoToken": (event, button, dialog) => {
|
||||||
let tokenId = $(button).data("tokenId")
|
let tokenId = $(button).data("tokenId")
|
||||||
let token = canvas.tokens?.get(tokenId)
|
let token = canvas.tokens?.get(tokenId)
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -372,6 +402,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
// If the user cancels the dialog, exit
|
// If the user cancels the dialog, exit
|
||||||
if (rollContext === null) return
|
if (rollContext === null) return
|
||||||
console.log("rollContext", rollContext, hasGrantedDice)
|
console.log("rollContext", rollContext, hasGrantedDice)
|
||||||
|
rollContext.saveSpell = saveSpell // Update fucking flag
|
||||||
|
|
||||||
let fullModifier = 0
|
let fullModifier = 0
|
||||||
let titleFormula = ""
|
let titleFormula = ""
|
||||||
@@ -380,21 +411,19 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
let bonus = Number(options.rollTarget.value)
|
let bonus = Number(options.rollTarget.value)
|
||||||
fullModifier = rollContext.modifier === "" ? 0 : parseInt(rollContext.modifier, 10) + bonus
|
fullModifier = rollContext.modifier === "" ? 0 : parseInt(rollContext.modifier, 10) + bonus
|
||||||
fullModifier += (rollContext.saveSpell) ? options.rollTarget.actorModifiers.saveModifier : 0
|
fullModifier += (rollContext.saveSpell) ? options.rollTarget.actorModifiers.saveModifier : 0
|
||||||
|
if (Number(rollContext.attackerAim) > 0) {
|
||||||
|
fullModifier += Number(rollContext.attackerAim)
|
||||||
|
}
|
||||||
|
|
||||||
if (fullModifier === 0) {
|
if (fullModifier === 0) {
|
||||||
modifierFormula = "0"
|
modifierFormula = "0"
|
||||||
} else {
|
} else {
|
||||||
if (options.rollType === "skill" || options.rollType === "monster-skill") {
|
let modAbs = Math.abs(fullModifier)
|
||||||
modifierFormula = `${fullModifier}`
|
modifierFormula = `D${modAbs + 1} - 1`
|
||||||
} else {
|
|
||||||
let modAbs = Math.abs(fullModifier)
|
|
||||||
modifierFormula = `D${modAbs + 1} - 1`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hasStaticModifier) {
|
if (hasStaticModifier) {
|
||||||
modifierFormula += ` + ${options.rollTarget.staticModifier}`
|
modifierFormula += ` + ${options.rollTarget.staticModifier}`
|
||||||
}
|
}
|
||||||
// modifierFormula += ` + ${options.rollTarget.charModifier}`
|
|
||||||
let sign = fullModifier < 0 ? "-" : "+"
|
let sign = fullModifier < 0 ? "-" : "+"
|
||||||
if (hasExplode) {
|
if (hasExplode) {
|
||||||
titleFormula = `${dice}E ${sign} ${modifierFormula}`
|
titleFormula = `${dice}E ${sign} ${modifierFormula}`
|
||||||
@@ -412,6 +441,14 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Latest addition : favor choice at point blank range
|
||||||
|
if (pointBlank) {
|
||||||
|
rollContext.favor = "favor"
|
||||||
|
}
|
||||||
|
if (beyondSkill) {
|
||||||
|
rollContext.favor = "disfavor"
|
||||||
|
}
|
||||||
|
|
||||||
// Specific pain case
|
// Specific pain case
|
||||||
if (options.rollType === "save" && options.rollTarget.rollKey === "pain" || options.rollTarget.rollKey === "paincourage") {
|
if (options.rollType === "save" && options.rollTarget.rollKey === "pain" || options.rollTarget.rollKey === "paincourage") {
|
||||||
baseFormula = options.rollTarget.rollDice
|
baseFormula = options.rollTarget.rollDice
|
||||||
@@ -421,8 +458,21 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Specific pain/poison/contagion case
|
// Specific pain/poison/contagion case
|
||||||
if (options.rollType === "save" && (options.rollTarget.rollKey === "pain" || options.rollTarget.rollKey === "paincourage" || options.rollTarget.rollKey === "poison" || options.rollTarget.rollKey === "contagion")) {
|
if (options.rollType === "save" && (options.rollTarget.rollKey === "poison" || options.rollTarget.rollKey === "contagion")) {
|
||||||
hasD30 = false
|
hasD30 = false
|
||||||
|
hasStaticModifier = true
|
||||||
|
modifierFormula = ` + ${Math.abs(fullModifier)}`
|
||||||
|
titleFormula = `${dice}E + ${Math.abs(fullModifier)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (letItFly) {
|
||||||
|
baseFormula = "1D20"
|
||||||
|
titleFormula = `1D20E`
|
||||||
|
modifierFormula = "0"
|
||||||
|
fullModifier = 0
|
||||||
|
hasFavor = false
|
||||||
|
hasExplode = true
|
||||||
|
rollContext.favor = "none"
|
||||||
}
|
}
|
||||||
|
|
||||||
maxValue = Number(baseFormula.match(/\d+$/)[0]) // Update the max value agains
|
maxValue = Number(baseFormula.match(/\d+$/)[0]) // Update the max value agains
|
||||||
@@ -437,6 +487,12 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
actorImage: options.actorImage,
|
actorImage: options.actorImage,
|
||||||
rollMode: rollContext.visibility,
|
rollMode: rollContext.visibility,
|
||||||
hasTarget: options.hasTarget,
|
hasTarget: options.hasTarget,
|
||||||
|
isDamage: options.isDamage,
|
||||||
|
damageSmall: options.damageSmall,
|
||||||
|
damageMedium: options.damageMedium,
|
||||||
|
pointBlank,
|
||||||
|
beyondSkill,
|
||||||
|
letItFly,
|
||||||
hasGrantedDice,
|
hasGrantedDice,
|
||||||
titleFormula,
|
titleFormula,
|
||||||
targetName,
|
targetName,
|
||||||
@@ -463,15 +519,17 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
if (rollContext.favor === "favor") {
|
if (rollContext.favor === "favor") {
|
||||||
rollFavor = new this(baseFormula, options.data, rollData)
|
rollFavor = new this(baseFormula, options.data, rollData)
|
||||||
await rollFavor.evaluate()
|
await rollFavor.evaluate()
|
||||||
|
console.log("Rolling with favor", rollFavor)
|
||||||
if (game?.dice3d) {
|
if (game?.dice3d) {
|
||||||
game.dice3d.showForRoll(rollFavor, game.user, true)
|
game.dice3d.showForRoll(rollFavor, game.user, true)
|
||||||
}
|
}
|
||||||
if (rollFavor.result > rollBase.result) {
|
if (Number(rollFavor.result) > Number(rollBase.result)) {
|
||||||
badResult = rollBase.result
|
badResult = rollBase.result
|
||||||
rollBase = rollFavor
|
rollBase = rollFavor
|
||||||
} else {
|
} else {
|
||||||
badResult = rollFavor.result
|
badResult = rollFavor.result
|
||||||
}
|
}
|
||||||
|
rollFavor = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rollContext.favor === "disfavor") {
|
if (rollContext.favor === "disfavor") {
|
||||||
@@ -480,12 +538,13 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
if (game?.dice3d) {
|
if (game?.dice3d) {
|
||||||
game.dice3d.showForRoll(rollFavor, game.user, true)
|
game.dice3d.showForRoll(rollFavor, game.user, true)
|
||||||
}
|
}
|
||||||
if (rollFavor.result < rollBase.result) {
|
if (Number(rollFavor.result) < Number(rollBase.result)) {
|
||||||
badResult = rollBase.result
|
badResult = rollBase.result
|
||||||
rollBase = rollFavor
|
rollBase = rollFavor
|
||||||
} else {
|
} else {
|
||||||
badResult = rollFavor.result
|
badResult = rollFavor.result
|
||||||
}
|
}
|
||||||
|
rollFavor = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasD30) {
|
if (hasD30) {
|
||||||
@@ -494,9 +553,17 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
game.dice3d.showForRoll(rollD30, game.user, true)
|
game.dice3d.showForRoll(rollD30, game.user, true)
|
||||||
}
|
}
|
||||||
options.D30result = rollD30.total
|
options.D30result = rollD30.total
|
||||||
|
|
||||||
|
// Récupérer le message D30 correspondant
|
||||||
|
const d30Message = D30Roll.getResult(
|
||||||
|
rollD30.total,
|
||||||
|
options.rollType,
|
||||||
|
options.rollTarget?.weapon
|
||||||
|
)
|
||||||
|
options.D30message = d30Message
|
||||||
}
|
}
|
||||||
|
|
||||||
let rollTotal = -1
|
let rollTotal = 0
|
||||||
let diceResults = []
|
let diceResults = []
|
||||||
let resultType
|
let resultType
|
||||||
let diceSum = 0
|
let diceSum = 0
|
||||||
@@ -521,7 +588,8 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasGrantedDice) {
|
if (hasGrantedDice && options.rollTarget.grantedDice && options.rollTarget.grantedDice !== "") {
|
||||||
|
titleFormula += ` + ${options.rollTarget.grantedDice.toUpperCase()}`
|
||||||
let grantedRoll = new Roll(options.rollTarget.grantedDice)
|
let grantedRoll = new Roll(options.rollTarget.grantedDice)
|
||||||
await grantedRoll.evaluate()
|
await grantedRoll.evaluate()
|
||||||
if (game?.dice3d) {
|
if (game?.dice3d) {
|
||||||
@@ -534,12 +602,12 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
if (fullModifier !== 0) {
|
if (fullModifier !== 0) {
|
||||||
diceResults.push({ dice: `${rollModifier.formula.toUpperCase()}`, value: rollModifier.total })
|
diceResults.push({ dice: `${rollModifier.formula.toUpperCase()}`, value: rollModifier.total })
|
||||||
if (fullModifier < 0) {
|
if (fullModifier < 0) {
|
||||||
rollTotal = Math.max(diceSum - rollModifier.total, 0)
|
rollTotal += Math.max(diceSum - rollModifier.total, 0)
|
||||||
} else {
|
} else {
|
||||||
rollTotal = diceSum + rollModifier.total
|
rollTotal += diceSum + rollModifier.total
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rollTotal = diceSum
|
rollTotal += diceSum
|
||||||
}
|
}
|
||||||
|
|
||||||
rollBase.options.resultType = resultType
|
rollBase.options.resultType = resultType
|
||||||
@@ -548,7 +616,10 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
rollBase.options.rollTarget = options.rollTarget
|
rollBase.options.rollTarget = options.rollTarget
|
||||||
rollBase.options.titleFormula = titleFormula
|
rollBase.options.titleFormula = titleFormula
|
||||||
rollBase.options.D30result = options.D30result
|
rollBase.options.D30result = options.D30result
|
||||||
|
rollBase.options.D30message = options.D30message
|
||||||
rollBase.options.badResult = badResult
|
rollBase.options.badResult = badResult
|
||||||
|
rollBase.options.rollData = foundry.utils.duplicate(rollData)
|
||||||
|
rollBase.options.defenderId = options.defenderId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook event that fires after the roll has been made.
|
* A hook event that fires after the roll has been made.
|
||||||
@@ -566,7 +637,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
|
|
||||||
/* ***********************************************************/
|
/* ***********************************************************/
|
||||||
static async promptInitiative(options = {}) {
|
static async promptInitiative(options = {}) {
|
||||||
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); // v12 : Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||||
const fieldRollMode = new foundry.data.fields.StringField({
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
choices: rollModes,
|
choices: rollModes,
|
||||||
blank: false,
|
blank: false,
|
||||||
@@ -587,9 +658,8 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
fieldRollMode,
|
fieldRollMode,
|
||||||
rollModes
|
rollModes
|
||||||
}
|
}
|
||||||
console.log("CTX", dialogContext)
|
|
||||||
|
|
||||||
const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/roll-initiative-dialog.hbs", dialogContext)
|
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/roll-initiative-dialog.hbs", dialogContext)
|
||||||
|
|
||||||
const label = game.i18n.localize("LETHALFANTASY.Label.initiative")
|
const label = game.i18n.localize("LETHALFANTASY.Label.initiative")
|
||||||
const rollContext = await foundry.applications.api.DialogV2.wait({
|
const rollContext = await foundry.applications.api.DialogV2.wait({
|
||||||
@@ -622,13 +692,12 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
let combat = game.combats.get(options.combatId)
|
let combat = game.combats.get(options.combatId)
|
||||||
combat.updateEmbeddedDocuments("Combatant", [{ _id: options.combatantId, initiative: initRoll.total, 'system.progressionCount': 0 }]);
|
combat.updateEmbeddedDocuments("Combatant", [{ _id: options.combatantId, initiative: initRoll.total, 'system.progressionCount': 0 }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ***********************************************************/
|
/* ***********************************************************/
|
||||||
static async promptCombatAction(options = {}) {
|
static async promptCombatAction(options = {}) {
|
||||||
|
|
||||||
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); // v12 : Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
||||||
const fieldRollMode = new foundry.data.fields.StringField({
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
choices: rollModes,
|
choices: rollModes,
|
||||||
blank: false,
|
blank: false,
|
||||||
@@ -652,7 +721,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/combat-action-dialog.hbs", dialogContext)
|
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/combat-action-dialog.hbs", dialogContext)
|
||||||
|
|
||||||
let buttons = []
|
let buttons = []
|
||||||
if (currentAction) {
|
if (currentAction) {
|
||||||
@@ -766,7 +835,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
await combatant.setFlag(SYSTEM.id, "currentAction", actionItem)
|
await combatant.setFlag(SYSTEM.id, "currentAction", actionItem)
|
||||||
let message = `${combatant.name} action : ${selectedItem.name}, start rolling progression dice or casting time`
|
let message = `${combatant.name} action : ${selectedItem.name}, start rolling progression dice or casting time`
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
||||||
rollContext = (actionItem.type == "weapon") ? "rollProgressionDice" : "rollLethargyDice" // Set the roll context to rollProgressionDice
|
rollContext = (actionItem.type === "weapon") ? "rollProgressionDice" : "rollLethargyDice" // Set the roll context to rollProgressionDice
|
||||||
currentAction = actionItem
|
currentAction = actionItem
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,8 +881,17 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
let toCompare = Math.min(currentAction.progressionCount, max)
|
let toCompare = Math.min(currentAction.progressionCount, max)
|
||||||
if (roll.total <= toCompare) {
|
if (roll.total <= toCompare) {
|
||||||
// Notify that the player can act now with a chat message
|
// Notify that the player can act now with a chat message
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageLethargyOK", { name: combatant.actor.name, spellName: currentAction.name, roll: roll.total })
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
actorName: combatant.actor.name,
|
||||||
|
weaponName: currentAction.name,
|
||||||
|
rollResult: roll.total,
|
||||||
|
isLethargy: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
||||||
// Update the combatant progression count
|
// Update the combatant progression count
|
||||||
await combatant.setFlag(SYSTEM.id, "currentAction", "")
|
await combatant.setFlag(SYSTEM.id, "currentAction", "")
|
||||||
// Display the action selection window again
|
// Display the action selection window again
|
||||||
@@ -822,8 +900,18 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
// Notify that the player cannot act now with a chat message
|
// Notify that the player cannot act now with a chat message
|
||||||
currentAction.progressionCount += 1
|
currentAction.progressionCount += 1
|
||||||
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
|
await combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageLethargyKO", { name: combatant.actor.name, spellName: currentAction.name, roll: roll.total })
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
actorName: combatant.actor.name,
|
||||||
|
weaponName: currentAction.name,
|
||||||
|
rollResult: roll.total,
|
||||||
|
progressionCount: currentAction.progressionCount,
|
||||||
|
isLethargy: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -869,25 +957,42 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
|
|
||||||
if (roll.total <= max) {
|
if (roll.total <= max) {
|
||||||
// Notify that the player can act now with a chat message
|
// Notify that the player can act now with a chat message
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionOK", { isMonster, name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
actorName: combatant.actor.name,
|
||||||
|
weaponName: currentAction.name,
|
||||||
|
rollResult: roll.total
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
||||||
await combatant.setFlag(SYSTEM.id, "currentAction", "")
|
await combatant.setFlag(SYSTEM.id, "currentAction", "")
|
||||||
combatant.actor.prepareRoll(currentAction.type === "weapon" ? "weapon-attack" : "spell-attack", currentAction._id)
|
combatant.actor.prepareRoll(currentAction.type === "weapon" ? "weapon-attack" : "spell-attack", currentAction._id)
|
||||||
} else {
|
} else {
|
||||||
// Notify that the player cannot act now with a chat message
|
// Notify that the player cannot act now with a chat message
|
||||||
currentAction.progressionCount += 1
|
currentAction.progressionCount += 1
|
||||||
combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
|
combatant.setFlag(SYSTEM.id, "currentAction", foundry.utils.duplicate(currentAction))
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionKO", { isMonster, name: combatant.actor.name, weapon: currentAction.name, roll: roll.total })
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
actorName: combatant.actor.name,
|
||||||
|
weaponName: currentAction.name,
|
||||||
|
rollResult: roll.total,
|
||||||
|
progressionCount: currentAction.progressionCount
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: combatant.actor }) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ***********************************************************/
|
/* ***********************************************************/
|
||||||
static async promptRangedDefense(rollTarget) {
|
static async promptRangedDefense(options = {}) {
|
||||||
|
|
||||||
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes);
|
||||||
const fieldRollMode = new foundry.data.fields.StringField({
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
choices: rollModes,
|
choices: rollModes,
|
||||||
blank: false,
|
blank: false,
|
||||||
@@ -902,15 +1007,14 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
attackerAimChoices: SYSTEM.ATTACKER_AIM_CHOICES,
|
attackerAimChoices: SYSTEM.ATTACKER_AIM_CHOICES,
|
||||||
movement: "none",
|
movement: "none",
|
||||||
moveDirection: "none",
|
moveDirection: "none",
|
||||||
size: "medium",
|
size: "+5",
|
||||||
range: "short",
|
range: "short",
|
||||||
attackerAim: "simple",
|
attackerAim: "simple",
|
||||||
fieldRollMode,
|
fieldRollMode,
|
||||||
rollModes
|
rollModes
|
||||||
}
|
}
|
||||||
console.log("CTX", dialogContext)
|
|
||||||
|
|
||||||
const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/range-defense-dialog.hbs", dialogContext)
|
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/range-defense-dialog.hbs", dialogContext)
|
||||||
|
|
||||||
const label = game.i18n.localize("LETHALFANTASY.Label.rangeDefenseRoll")
|
const label = game.i18n.localize("LETHALFANTASY.Label.rangeDefenseRoll")
|
||||||
const rollContext = await foundry.applications.api.DialogV2.wait({
|
const rollContext = await foundry.applications.api.DialogV2.wait({
|
||||||
@@ -932,27 +1036,41 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
rejectClose: false // Click on Close button will not launch an error
|
rejectClose: false // Click on Close button will not launch an error
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// If the user cancels the dialog, exit
|
||||||
|
if (rollContext === null) return
|
||||||
|
|
||||||
console.log("RollContext", rollContext)
|
console.log("RollContext", rollContext)
|
||||||
|
// Add disfavor/favor option if point blank range
|
||||||
|
if (rollContext.range === "pointblank") {
|
||||||
|
rollContext.movement = rollContext.movement.replace("kh", "")
|
||||||
|
rollContext.movement = rollContext.movement.replace("kl", "")
|
||||||
|
rollContext.movement += "kl" // Add the kl to the movement (disfavor for point blank range)
|
||||||
|
rollContext.range = "0"
|
||||||
|
}
|
||||||
|
if (rollContext.range === "beyondskill") {
|
||||||
|
rollContext.movement = rollContext.movement.replace("kh", "")
|
||||||
|
rollContext.movement = rollContext.movement.replace("kl", "")
|
||||||
|
rollContext.movement += "kh" // Add the kl to the movement (favor for point blank range)
|
||||||
|
rollContext.range = "+11"
|
||||||
|
}
|
||||||
|
|
||||||
// Build the final modifier
|
// Build the final modifier
|
||||||
let fullModifier = Number(rollContext.moveDirection) +
|
let fullModifier = Number(rollContext.moveDirection) +
|
||||||
Number(rollContext.size) +
|
Number(rollContext.size) +
|
||||||
Number(rollContext.range) +
|
Number(rollContext.range) +
|
||||||
Number(rollContext.attackerAim)
|
Number(rollContext?.attackerAim || 0)
|
||||||
console.log("Modifier", fullModifier)
|
|
||||||
|
|
||||||
let modifierFormula
|
let modifierFormula
|
||||||
if (fullModifier === 0) {
|
if (fullModifier === 0) {
|
||||||
modifierFormula = "0"
|
modifierFormula = "0"
|
||||||
} else {
|
} else {
|
||||||
let modAbs = Math.abs(fullModifier)
|
let modAbs = Math.abs(fullModifier)
|
||||||
modifierFormula = `${modAbs}`
|
modifierFormula = `D${modAbs + 1} -1`
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user cancels the dialog, exit
|
|
||||||
if (rollContext === null) return
|
|
||||||
|
|
||||||
let rollData = { ...rollContext }
|
let rollData = { ...rollContext }
|
||||||
let options = { ...rollContext }
|
// Merge rollContext object into options object
|
||||||
|
options = { ...options, ...rollContext }
|
||||||
options.rollName = "Ranged Defense"
|
options.rollName = "Ranged Defense"
|
||||||
|
|
||||||
const rollBase = new this(rollContext.movement, options.data, rollData)
|
const rollBase = new this(rollContext.movement, options.data, rollData)
|
||||||
@@ -962,8 +1080,17 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
let rollD30 = await new Roll("1D30").evaluate()
|
let rollD30 = await new Roll("1D30").evaluate()
|
||||||
options.D30result = rollD30.total
|
options.D30result = rollD30.total
|
||||||
|
|
||||||
|
let badResult = 0
|
||||||
|
if (rollContext.movement.includes("kh")) {
|
||||||
|
rollData.favor = "favor"
|
||||||
|
badResult = Math.min(rollBase.terms[0].results[0].result, rollBase.terms[0].results[1]?.result || 20)
|
||||||
|
}
|
||||||
|
if (rollContext.movement.includes("kl")) {
|
||||||
|
rollData.favor = "disfavor"
|
||||||
|
badResult = Math.max(rollBase.terms[0].results[0].result, rollBase.terms[0].results[1]?.result || 1)
|
||||||
|
}
|
||||||
let dice = rollContext.movement
|
let dice = rollContext.movement
|
||||||
let maxValue = Number(dice.match(/\d+$/)[0]) // Update the max value agains
|
let maxValue = 20 // As per latest changes (was : Number(dice.match(/\d+$/)[0])
|
||||||
let rollTotal = -1
|
let rollTotal = -1
|
||||||
let diceResults = []
|
let diceResults = []
|
||||||
let resultType
|
let resultType
|
||||||
@@ -987,15 +1114,16 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
} else {
|
} else {
|
||||||
rollTotal = diceSum
|
rollTotal = diceSum
|
||||||
}
|
}
|
||||||
|
rollBase.options = { ...rollBase.options, ...options }
|
||||||
rollBase.options.resultType = resultType
|
rollBase.options.resultType = resultType
|
||||||
rollBase.options.rollTotal = rollTotal
|
rollBase.options.rollTotal = rollTotal
|
||||||
rollBase.options.diceResults = diceResults
|
rollBase.options.diceResults = diceResults
|
||||||
rollBase.options.rollTarget = options.rollTarget
|
rollBase.options.rollTarget = options.rollTarget
|
||||||
rollBase.options.titleFormula = `${dice}E + ${modifierFormula}`
|
rollBase.options.titleFormula = `1D20E + ${modifierFormula}`
|
||||||
rollBase.options.D30result = options.D30result
|
rollBase.options.D30result = options.D30result
|
||||||
rollBase.options.rollName = "Ranged Defense"
|
rollBase.options.rollName = "Ranged Defense"
|
||||||
|
rollBase.options.badResult = badResult
|
||||||
|
rollBase.options.rollData = foundry.utils.duplicate(rollData)
|
||||||
/**
|
/**
|
||||||
* A hook event that fires after the roll has been made.
|
* A hook event that fires after the roll has been made.
|
||||||
* @function
|
* @function
|
||||||
@@ -1050,13 +1178,64 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
async render(chatOptions = {}) {
|
async render(chatOptions = {}) {
|
||||||
let chatData = await this._getChatCardData(chatOptions.isPrivate)
|
let chatData = await this._getChatCardData(chatOptions.isPrivate)
|
||||||
console.log("ChatData", chatData)
|
console.log("ChatData", chatData)
|
||||||
return await renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
|
return await foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generates the data required for rendering a roll chat card.
|
* Generates the data required for rendering a roll chat card.
|
||||||
*/
|
*/
|
||||||
async _getChatCardData(isPrivate) {
|
async _getChatCardData(isPrivate) {
|
||||||
|
// Générer la liste des combatants de la scène
|
||||||
|
let combatants = []
|
||||||
|
let isAttack = this.type === "weapon-attack" || this.type === "monster-attack" || this.type === "spell-attack" || this.type === "miracle-attack"
|
||||||
|
if (this.rollData?.isDamage || isAttack) {
|
||||||
|
// D'abord, ajouter les combattants du combat actif
|
||||||
|
if (game?.combat?.combatants) {
|
||||||
|
for (let c of game.combat.combatants) {
|
||||||
|
if (c.actorId !== this.actorId) {
|
||||||
|
combatants.push({ id: c.id, name: c.name, tokenId: c.token.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensuite, ajouter tous les tokens de la scène active qui ne sont pas déjà dans la liste
|
||||||
|
if (canvas?.scene?.tokens) {
|
||||||
|
const existingTokenIds = new Set(combatants.map(c => c.tokenId))
|
||||||
|
for (let token of canvas.scene.tokens) {
|
||||||
|
if (token.actorId !== this.actorId && !existingTokenIds.has(token.id)) {
|
||||||
|
combatants.push({
|
||||||
|
id: token.id,
|
||||||
|
name: token.name,
|
||||||
|
tokenId: token.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer les informations de l'arme pour les attaques réussies
|
||||||
|
let weaponDamageOptions = null
|
||||||
|
console.log("Roll type:", this.type, "rollTarget:", this.rollTarget, "Has weapon:", !!this.rollTarget?.weapon)
|
||||||
|
if (this.type === "weapon-attack" && this.rollTarget?.weapon) {
|
||||||
|
const weapon = this.rollTarget.weapon
|
||||||
|
weaponDamageOptions = {
|
||||||
|
weaponId: weapon._id || weapon.id,
|
||||||
|
weaponName: weapon.name,
|
||||||
|
damageS: weapon.system?.damage?.damageS,
|
||||||
|
damageM: weapon.system?.damage?.damageM
|
||||||
|
}
|
||||||
|
console.log("Weapon damage options:", weaponDamageOptions)
|
||||||
|
} else if (this.type === "monster-attack" && this.rollTarget) {
|
||||||
|
weaponDamageOptions = {
|
||||||
|
weaponId: this.rollTarget.rollKey,
|
||||||
|
weaponName: this.rollTarget.name,
|
||||||
|
damageFormula: this.rollTarget.damageDice,
|
||||||
|
damageModifier: this.rollTarget.damageModifier,
|
||||||
|
isMonster: true
|
||||||
|
}
|
||||||
|
console.log("Monster damage options:", weaponDamageOptions)
|
||||||
|
}
|
||||||
|
|
||||||
const cardData = {
|
const cardData = {
|
||||||
css: [SYSTEM.id, "dice-roll"],
|
css: [SYSTEM.id, "dice-roll"],
|
||||||
data: this.data,
|
data: this.data,
|
||||||
@@ -1078,8 +1257,16 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
targetName: this.targetName,
|
targetName: this.targetName,
|
||||||
targetArmor: this.targetArmor,
|
targetArmor: this.targetArmor,
|
||||||
D30result: this.D30result,
|
D30result: this.D30result,
|
||||||
|
D30message: this.D30message,
|
||||||
badResult: this.badResult,
|
badResult: this.badResult,
|
||||||
isPrivate: isPrivate
|
rollData: this.rollData,
|
||||||
|
isPrivate: isPrivate,
|
||||||
|
combatants: combatants,
|
||||||
|
weaponDamageOptions: weaponDamageOptions,
|
||||||
|
isAttack: isAttack,
|
||||||
|
defenderId: this.defenderId,
|
||||||
|
// Vérifier si l'utilisateur peut sélectionner une cible (est GM ou possède l'acteur)
|
||||||
|
canSelectTarget: game.user.isGM || game.actors.get(this.actorId)?.testUserPermission(game.user, "OWNER")
|
||||||
}
|
}
|
||||||
cardData.cssClass = cardData.css.join(" ")
|
cardData.cssClass = cardData.css.join(" ")
|
||||||
cardData.tooltip = isPrivate ? "" : await this.getTooltip()
|
cardData.tooltip = isPrivate ? "" : await this.getTooltip()
|
||||||
@@ -1110,6 +1297,7 @@ export default class LethalFantasyRoll extends Roll {
|
|||||||
targetArmor: this.targetArmor,
|
targetArmor: this.targetArmor,
|
||||||
targetMalus: this.targetMalus,
|
targetMalus: this.targetMalus,
|
||||||
realDamage: this.realDamage,
|
realDamage: this.realDamage,
|
||||||
|
rollData: this.rollData,
|
||||||
...messageData,
|
...messageData,
|
||||||
},
|
},
|
||||||
{ rollMode: rollMode },
|
{ rollMode: rollMode },
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
current: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
current: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||||
})
|
})
|
||||||
schema.granted = new fields.SchemaField({
|
schema.granted = new fields.SchemaField({
|
||||||
attackDice: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
attackDice: new fields.StringField({ required: true, nullable: false, initial: "0", choices: SYSTEM.GRANTED_DICE_CHOICES }),
|
||||||
defenseDice: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
defenseDice: new fields.StringField({ required: true, nullable: false, initial: "0", choices: SYSTEM.GRANTED_DICE_CHOICES }),
|
||||||
damageDice: new fields.StringField({ required: true, nullable: false, initial: "" })
|
damageDice: new fields.StringField({ required: true, nullable: false, initial: "0", choices: SYSTEM.GRANTED_DICE_CHOICES })
|
||||||
})
|
})
|
||||||
|
|
||||||
schema.movement = new fields.SchemaField({
|
schema.movement = new fields.SchemaField({
|
||||||
@@ -120,6 +120,8 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
magicUser: new fields.BooleanField({ initial: false }),
|
magicUser: new fields.BooleanField({ initial: false }),
|
||||||
clericUser: new fields.BooleanField({ initial: false }),
|
clericUser: new fields.BooleanField({ initial: false }),
|
||||||
hpPerLevel: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
hpPerLevel: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
|
naturalDR: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
magicDR: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
})
|
})
|
||||||
|
|
||||||
schema.modifiers = new fields.SchemaField({
|
schema.modifiers = new fields.SchemaField({
|
||||||
@@ -174,6 +176,31 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
/** @override */
|
/** @override */
|
||||||
static LOCALIZATION_PREFIXES = ["LETHALFANTASY.Character"]
|
static LOCALIZATION_PREFIXES = ["LETHALFANTASY.Character"]
|
||||||
|
|
||||||
|
static migrateData(data) {
|
||||||
|
if (data?.biodata?.mortal) {
|
||||||
|
if (!SYSTEM.MORTAL_CHOICES[data.biodata.mortal]) {
|
||||||
|
for (let key in SYSTEM.MORTAL_CHOICES) {
|
||||||
|
let mortal = SYSTEM.MORTAL_CHOICES[key]
|
||||||
|
if (mortal.label.toLowerCase() === data.biodata.mortal.toLowerCase()) {
|
||||||
|
data.biodata.mortal = mortal.id
|
||||||
|
}
|
||||||
|
if (data.biodata.mortal.toLowerCase().includes("shire")) {
|
||||||
|
data.biodata.mortal = "halflings"
|
||||||
|
}
|
||||||
|
if (data.biodata.mortal.toLowerCase().includes("human")) {
|
||||||
|
data.biodata.mortal = "mankind"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!SYSTEM.MORTAL_CHOICES[data.biodata.mortal]) {
|
||||||
|
console.warn("Lethal Fantasy | Migrate data: Mortal not found, forced to mankind", data.biodata.mortal)
|
||||||
|
data.biodata.mortal = "mankind"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.migrateData(data)
|
||||||
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
super.prepareDerivedData();
|
super.prepareDerivedData();
|
||||||
let grit = 0
|
let grit = 0
|
||||||
@@ -210,8 +237,8 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
this.saves.toughness.value = conDef.toughness_save + this.modifiers.saveModifier
|
this.saves.toughness.value = conDef.toughness_save + this.modifiers.saveModifier
|
||||||
this.challenges.dying.value = conDef.stabilization_dice
|
this.challenges.dying.value = conDef.stabilization_dice
|
||||||
|
|
||||||
this.saves.contagion.value = this.characteristics.con.value + this.modifiers.saveModifier
|
this.saves.contagion.value = this.characteristics.con.value;// + this.modifiers.saveModifier
|
||||||
this.saves.poison.value = this.characteristics.con.value + this.modifiers.saveModifier
|
this.saves.poison.value = this.characteristics.con.value; // + this.modifiers.saveModifier
|
||||||
|
|
||||||
this.combat.attackModifier = 0
|
this.combat.attackModifier = 0
|
||||||
for (let chaKey of SYSTEM.CHARACTERISTIC_ATTACK) {
|
for (let chaKey of SYSTEM.CHARACTERISTIC_ATTACK) {
|
||||||
@@ -246,7 +273,7 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
||||||
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||||
*/
|
*/
|
||||||
async roll(rollType, rollTarget) {
|
async roll(rollType, rollTarget, defenderId) {
|
||||||
const hasTarget = false
|
const hasTarget = false
|
||||||
let roll = await LethalFantasyRoll.prompt({
|
let roll = await LethalFantasyRoll.prompt({
|
||||||
rollType,
|
rollType,
|
||||||
@@ -255,7 +282,8 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
actorName: this.parent.name,
|
actorName: this.parent.name,
|
||||||
actorImage: this.parent.img,
|
actorImage: this.parent.img,
|
||||||
hasTarget,
|
hasTarget,
|
||||||
target: false
|
target: false,
|
||||||
|
defenderId
|
||||||
})
|
})
|
||||||
if (!roll) return null
|
if (!roll) return null
|
||||||
|
|
||||||
@@ -268,14 +296,13 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
|
|
||||||
let wisDef = SYSTEM.CHARACTERISTICS_TABLES.wis.find((c) => c.value === this.characteristics.wis.value)
|
let wisDef = SYSTEM.CHARACTERISTICS_TABLES.wis.find((c) => c.value === this.characteristics.wis.value)
|
||||||
let maxInit = Number(wisDef.init_cap) || 1000
|
let maxInit = Number(wisDef.init_cap) || 1000
|
||||||
console.log("Rolling initiative for", this)
|
|
||||||
|
|
||||||
let roll = await LethalFantasyRoll.promptInitiative({
|
let roll = await LethalFantasyRoll.promptInitiative({
|
||||||
actorId: this.parent.id,
|
actorId: this.parent.id,
|
||||||
actorName: this.parent.name,
|
actorName: this.parent.name,
|
||||||
actorImage: this.parent.img,
|
actorImage: this.parent.img,
|
||||||
combatId,
|
combatId,
|
||||||
combatantId ,
|
combatantId,
|
||||||
actorClass,
|
actorClass,
|
||||||
maxInit,
|
maxInit,
|
||||||
})
|
})
|
||||||
@@ -285,6 +312,13 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
}
|
}
|
||||||
|
|
||||||
async rollProgressionDice(combatId, combatantId, rollProgressionCount) {
|
async rollProgressionDice(combatId, combatantId, rollProgressionCount) {
|
||||||
|
let combatant = game.combats.get(combatId)?.combatants?.get(combatantId)
|
||||||
|
|
||||||
|
// Don't roll if the combatant is defeated
|
||||||
|
if (combatant?.isDefeated) {
|
||||||
|
ui.notifications.warn(`${this.parent.name} is defeated and cannot attack.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get all weapons from the actor
|
// Get all weapons from the actor
|
||||||
let weapons = this.parent.items.filter(i => i.type === "weapon" && i.system.weaponType === "melee")
|
let weapons = this.parent.items.filter(i => i.type === "weapon" && i.system.weaponType === "melee")
|
||||||
@@ -302,10 +336,10 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
|||||||
let formula = ""
|
let formula = ""
|
||||||
if (s.type === "spell") {
|
if (s.type === "spell") {
|
||||||
let dice = LethalFantasyUtils.getLethargyDice(s.system.level)
|
let dice = LethalFantasyUtils.getLethargyDice(s.system.level)
|
||||||
title = `${s.name} (Casting time: ${s.system.castingTime}, Lethargy: ${dice})`
|
title = `${s.name} (Casting time: ${s.system.castingTime}, Lethargy: ${dice})`
|
||||||
formula = `${s.system.castingTime}+${dice}`
|
formula = `${s.system.castingTime}+${dice}`
|
||||||
} else {
|
} else {
|
||||||
title = `${s.name} (Prayer time: ${s.system.prayerTime})`
|
title = `${s.name} (Prayer time: ${s.system.prayerTime})`
|
||||||
formula = `${s.system.prayerTime}`
|
formula = `${s.system.prayerTime}`
|
||||||
}
|
}
|
||||||
weaponsChoices.push({ id: s.id, name: title, combatProgressionDice: formula })
|
weaponsChoices.push({ id: s.id, name: title, combatProgressionDice: formula })
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
defenseModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
defenseModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
damageDice: new fields.StringField({ required: true, nullable: false, initial: "1D6" }),
|
damageDice: new fields.StringField({ required: true, nullable: false, initial: "1D6" }),
|
||||||
damageModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
damageModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
enabled: new fields.BooleanField({ initial: true, required: true, nullable: false }),
|
||||||
}
|
}
|
||||||
return new fields.SchemaField(schema, { label })
|
return new fields.SchemaField(schema, { label })
|
||||||
}
|
}
|
||||||
@@ -108,15 +109,22 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
schema.biodata = new fields.SchemaField({
|
schema.biodata = new fields.SchemaField({
|
||||||
alignment: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
alignment: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
vision: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
vision: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
height: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
height: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
length: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
length: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||||
weight: new fields.StringField({ required: true, nullable: false, initial: "" })
|
weight: new fields.StringField({ required: true, nullable: false, initial: "" })
|
||||||
})
|
})
|
||||||
schema.combat = new fields.SchemaField({
|
schema.combat = new fields.SchemaField({
|
||||||
attackModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
attackModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
defenseModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
defenseModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
damageModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
damageModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
armorHitPoints: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
armorHitPoints: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
damageReduction: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
shieldDamageReduction: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||||
|
shieldDefenseDice: new fields.StringField({ required: true, nullable: false, initial: "d4" })
|
||||||
|
})
|
||||||
|
schema.combatHTH = new fields.SchemaField({
|
||||||
|
attack1: attackField("1"),
|
||||||
|
attack2: attackField("2")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -133,7 +141,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
* @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=).
|
||||||
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||||
*/
|
*/
|
||||||
async roll(rollType, rollTarget) {
|
async roll(rollType, rollTarget, defenderId = undefined) {
|
||||||
const hasTarget = false
|
const hasTarget = false
|
||||||
let roll = await LethalFantasyRoll.prompt({
|
let roll = await LethalFantasyRoll.prompt({
|
||||||
rollType,
|
rollType,
|
||||||
@@ -142,14 +150,15 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
actorName: this.parent.name,
|
actorName: this.parent.name,
|
||||||
actorImage: this.parent.img,
|
actorImage: this.parent.img,
|
||||||
hasTarget,
|
hasTarget,
|
||||||
target: false
|
target: false,
|
||||||
|
defenderId
|
||||||
})
|
})
|
||||||
if (!roll) return null
|
if (!roll) return null
|
||||||
|
|
||||||
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
await roll.toMessage({}, { rollMode: roll.options.rollMode })
|
||||||
}
|
}
|
||||||
|
|
||||||
async prepareMonsterRoll(rollType, rollKey, rollDice = undefined, tokenId = undefined) {
|
async prepareMonsterRoll(rollType, rollKey, rollDice = undefined, tokenId = undefined, damageModifier = undefined, defenderId = undefined) {
|
||||||
let rollTarget
|
let rollTarget
|
||||||
switch (rollType) {
|
switch (rollType) {
|
||||||
case "monster-attack":
|
case "monster-attack":
|
||||||
@@ -157,6 +166,22 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
case "monster-damage":
|
case "monster-damage":
|
||||||
rollTarget = foundry.utils.duplicate(this.attacks[rollKey])
|
rollTarget = foundry.utils.duplicate(this.attacks[rollKey])
|
||||||
rollTarget.rollKey = rollKey
|
rollTarget.rollKey = rollKey
|
||||||
|
// Si damageModifier est fourni (depuis le chat), l'utiliser au lieu de celui de la fiche
|
||||||
|
if (damageModifier !== undefined && rollType === "monster-damage") {
|
||||||
|
rollTarget.damageModifier = damageModifier
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "monster-attack-hth":
|
||||||
|
case "monster-defense-hth":
|
||||||
|
case "monster-damage-hth":
|
||||||
|
rollTarget = foundry.utils.duplicate(this.combatHTH[rollKey])
|
||||||
|
rollTarget.rollKey = rollKey
|
||||||
|
// Si damageModifier est fourni (depuis le chat), l'utiliser au lieu de celui de la fiche
|
||||||
|
if (damageModifier !== undefined && rollType === "monster-damage-hth") {
|
||||||
|
rollTarget.damageModifier = damageModifier
|
||||||
|
}
|
||||||
|
// Convertir le type de roll pour utiliser les mêmes handlers que les attaques normales
|
||||||
|
rollType = rollType.replace("-hth", "")
|
||||||
break
|
break
|
||||||
case "monster-skill":
|
case "monster-skill":
|
||||||
rollTarget = foundry.utils.duplicate(this.resists[rollKey])
|
rollTarget = foundry.utils.duplicate(this.resists[rollKey])
|
||||||
@@ -167,10 +192,23 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
rollTarget.rollKey = rollKey
|
rollTarget.rollKey = rollKey
|
||||||
rollTarget.rollDice = rollDice
|
rollTarget.rollDice = rollDice
|
||||||
break
|
break
|
||||||
|
case "shield-defense": {
|
||||||
|
// Lance directement le dé de défense du bouclier
|
||||||
|
const formula = rollDice || this.combat.shieldDefenseDice
|
||||||
|
const roll = new Roll(formula)
|
||||||
|
await roll.evaluate()
|
||||||
|
|
||||||
|
const flavor = game.i18n.localize("LETHALFANTASY.Label.shieldDefenseDice")
|
||||||
|
await roll.toMessage({
|
||||||
|
flavor,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor: this.parent })
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
case "weapon-damage-small":
|
case "weapon-damage-small":
|
||||||
case "weapon-damage-medium":
|
case "weapon-damage-medium":
|
||||||
case "weapon-attack":
|
case "weapon-attack":
|
||||||
case "weapon-defense":
|
case "weapon-defense": {
|
||||||
let weapon = this.actor.items.find((i) => i.type === "weapon" && i.id === rollKey)
|
let weapon = this.actor.items.find((i) => i.type === "weapon" && i.id === rollKey)
|
||||||
let skill
|
let skill
|
||||||
let skills = this.actor.items.filter((i) => i.type === "skill" && i.name.toLowerCase() === weapon.name.toLowerCase())
|
let skills = this.actor.items.filter((i) => i.type === "skill" && i.name.toLowerCase() === weapon.name.toLowerCase())
|
||||||
@@ -205,16 +243,19 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
rollTarget.weaponSkillModifier = skill.weaponSkillModifier
|
rollTarget.weaponSkillModifier = skill.weaponSkillModifier
|
||||||
rollTarget.rollKey = rollKey
|
rollTarget.rollKey = rollKey
|
||||||
rollTarget.combat = foundry.utils.duplicate(this.combat)
|
rollTarget.combat = foundry.utils.duplicate(this.combat)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
|
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all cases
|
// In all cases
|
||||||
rollTarget.tokenId = tokenId
|
if (rollTarget) {
|
||||||
console.log(rollTarget)
|
rollTarget.tokenId = tokenId
|
||||||
await this.roll(rollType, rollTarget)
|
console.log(rollTarget)
|
||||||
|
await this.roll(rollType, rollTarget, defenderId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async rollInitiative(combatId = undefined, combatantId = undefined) {
|
async rollInitiative(combatId = undefined, combatantId = undefined) {
|
||||||
@@ -237,19 +278,25 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
async rollProgressionDice(combatId, combatantId) {
|
async rollProgressionDice(combatId, combatantId) {
|
||||||
|
let combatant = game.combats.get(combatId)?.combatants?.get(combatantId)
|
||||||
|
|
||||||
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
|
// Don't roll if the combatant is defeated
|
||||||
|
if (combatant?.isDefeated) {
|
||||||
|
ui.notifications.warn(`${this.parent.name} is defeated and cannot attack.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes)
|
||||||
const fieldRollMode = new foundry.data.fields.StringField({
|
const fieldRollMode = new foundry.data.fields.StringField({
|
||||||
choices: rollModes,
|
choices: rollModes,
|
||||||
blank: false,
|
blank: false,
|
||||||
default: "public",
|
default: "public",
|
||||||
})
|
})
|
||||||
|
|
||||||
let roll = new Roll("1D8")
|
let roll = new Roll("1D12")
|
||||||
await roll.evaluate()
|
await roll.evaluate()
|
||||||
let combatant = game.combats.get(combatId)?.combatants?.get(combatantId)
|
|
||||||
|
|
||||||
let msg = await roll.toMessage({ flavor: `Progression Roll for ${this.parent.name}` } )
|
let msg = await roll.toMessage({ flavor: `Progression Roll for ${this.parent.name}` })
|
||||||
if (game?.dice3d) {
|
if (game?.dice3d) {
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||||
}
|
}
|
||||||
@@ -257,22 +304,62 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
|||||||
let hasAttack = false
|
let hasAttack = false
|
||||||
for (let key in this.attacks) {
|
for (let key in this.attacks) {
|
||||||
let attack = this.attacks[key]
|
let attack = this.attacks[key]
|
||||||
if (attack.attackScore > 0 && attack.attackScore === roll.total) {
|
if (attack.enabled && attack.attackScore > 0 && attack.attackScore === roll.total) {
|
||||||
hasAttack = true
|
hasAttack = true
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionOKMonster", { isMonster: true, name: this.parent.name, weapon: attack.name, roll: roll.total })
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
actorName: this.parent.name,
|
||||||
|
weaponName: attack.name,
|
||||||
|
rollResult: roll.total
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
|
||||||
let token = combatant?.token
|
let token = combatant?.token
|
||||||
this.prepareMonsterRoll("monster-attack", key, undefined, token?.id)
|
this.prepareMonsterRoll("monster-attack", key, undefined, token?.id)
|
||||||
if ( token?.object ) {
|
if (token?.object) {
|
||||||
token.object?.control({releaseOthers: true});
|
token.object?.control({ releaseOthers: true });
|
||||||
return canvas.animatePan(token.object.center);
|
return canvas.animatePan(token.object.center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check Hand To Hand attacks as well
|
||||||
if (!hasAttack) {
|
if (!hasAttack) {
|
||||||
let message = game.i18n.format("LETHALFANTASY.Notifications.messageProgressionKOMonster", { isMonster: true, name: this.parent.name, roll: roll.total })
|
for (let key in this.combatHTH) {
|
||||||
ChatMessage.create({ content: message, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
|
let attack = this.combatHTH[key]
|
||||||
}
|
if (attack.enabled && attack.attackScore > 0 && attack.attackScore === roll.total) {
|
||||||
|
hasAttack = true
|
||||||
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: true,
|
||||||
|
actorName: this.parent.name,
|
||||||
|
weaponName: `${attack.name} (HTH)`,
|
||||||
|
rollResult: roll.total
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
|
||||||
|
let token = combatant?.token
|
||||||
|
this.prepareMonsterRoll("monster-attack-hth", key, undefined, token?.id)
|
||||||
|
if (token?.object) {
|
||||||
|
token.object?.control({ releaseOthers: true });
|
||||||
|
return canvas.animatePan(token.object.center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasAttack) {
|
||||||
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
"systems/fvtt-lethal-fantasy/templates/progression-message.hbs",
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
actorName: this.parent.name,
|
||||||
|
rollResult: roll.total
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ChatMessage.create({ content: messageContent, speaker: ChatMessage.getSpeaker({ actor: this.parent }) })
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ export default class LethalFantasyShield extends foundry.abstract.TypeDataModel
|
|||||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||||
|
|
||||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||||
schema.defense = new fields.StringField({required: true, initial: "d4", choices: SYSTEM.SHIELD_DEFENSE_DICE})
|
schema.defense = new fields.StringField({ required: true, initial: "d4", choices: SYSTEM.SHIELD_DEFENSE_DICE })
|
||||||
schema.movementreduction = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
schema.movementreduction = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||||
schema.hascover = new fields.BooleanField({ required: true, initial: false })
|
schema.hascover = new fields.BooleanField({ required: true, initial: false })
|
||||||
|
schema.damageReduction = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||||
|
|
||||||
schema.standing = new fields.SchemaField({
|
schema.standing = new fields.SchemaField({
|
||||||
min: new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }),
|
min: new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }),
|
||||||
|
|||||||
616
module/utils.mjs
616
module/utils.mjs
@@ -1,3 +1,9 @@
|
|||||||
|
import { SYSTEM } from "./config/system.mjs"
|
||||||
|
|
||||||
|
// Map temporaire pour stocker les données d'attaque en attente de défense
|
||||||
|
if (!globalThis.pendingDefenses) {
|
||||||
|
globalThis.pendingDefenses = new Map()
|
||||||
|
}
|
||||||
|
|
||||||
export default class LethalFantasyUtils {
|
export default class LethalFantasyUtils {
|
||||||
|
|
||||||
@@ -18,6 +24,51 @@ export default class LethalFantasyUtils {
|
|||||||
options.push({ name: "Reset Progression", condition: true, icon: '<i class="fas fa-rotate-right"></i>', callback: target => { game.combat.resetProgression(target.data('combatant-id')); } })
|
options.push({ name: "Reset Progression", condition: true, icon: '<i class="fas fa-rotate-right"></i>', callback: target => { game.combat.resetProgression(target.data('combatant-id')); } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static setHookListeners() {
|
||||||
|
|
||||||
|
Hooks.on('renderTokenHUD', async (hud, html, token) => {
|
||||||
|
const lossHPButton = await foundry.applications.handlebars.renderTemplate('systems/fvtt-lethal-fantasy/templates/loss-hp-hud.hbs', {})
|
||||||
|
$(html).find('div.left').append(lossHPButton);
|
||||||
|
$(html).find('img.lethal-hp-loss-hud').click((event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
let hpMenu = $(html).find('.hp-loss-wrap')[0]
|
||||||
|
if (hpMenu.classList.contains("hp-loss-hud-disabled")) {
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.add('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.remove('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.add('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.remove('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.add('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.remove('hp-loss-hud-disabled');
|
||||||
|
} else {
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.add('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.add('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.add('hp-loss-hud-disabled');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$(html).find('.loss-hp-hud-click').click((event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
let hpLoss = event.currentTarget.dataset.hpValue;
|
||||||
|
if (token) {
|
||||||
|
let tokenFull = canvas.tokens.placeables.find(t => t.id === token._id);
|
||||||
|
console.log(tokenFull, token)
|
||||||
|
let actor = tokenFull.actor;
|
||||||
|
actor.applyDamage(Number(hpLoss));
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[0].classList.add('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[1].classList.add('hp-loss-hud-disabled');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.remove('hp-loss-hud-active');
|
||||||
|
$(html).find('.hp-loss-wrap')[2].classList.add('hp-loss-hud-disabled');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
static handleSocketEvent(msg = {}) {
|
static handleSocketEvent(msg = {}) {
|
||||||
console.log(`handleSocketEvent !`, msg)
|
console.log(`handleSocketEvent !`, msg)
|
||||||
let actor
|
let actor
|
||||||
@@ -30,9 +81,468 @@ export default class LethalFantasyUtils {
|
|||||||
actor = game.actors.get(msg.actorId)
|
actor = game.actors.get(msg.actorId)
|
||||||
actor.system.rollProgressionDice(msg.combatId, msg.combatantId, msg.rollProgressionCount)
|
actor.system.rollProgressionDice(msg.combatId, msg.combatantId, msg.rollProgressionCount)
|
||||||
break
|
break
|
||||||
|
case "requestDefense":
|
||||||
|
// Vérifier si le message est destiné à cet utilisateur
|
||||||
|
if (msg.userId === game.user.id) {
|
||||||
|
LethalFantasyUtils.showDefenseRequest(msg)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "offerAttackerGrit":
|
||||||
|
// Vérifier si le message est destiné à cet utilisateur
|
||||||
|
if (msg.userId === game.user.id) {
|
||||||
|
LethalFantasyUtils.handleAttackerGritOffer(msg)
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async handleAttackerGritOffer(msg) {
|
||||||
|
const { attackerId, attackRoll, defenseRoll, attackerName, defenderName, attackWeaponId, attackRollType, attackRollKey, defenderId } = msg
|
||||||
|
|
||||||
|
const attacker = game.actors.get(attackerId)
|
||||||
|
if (!attacker) {
|
||||||
|
console.warn("Attacker not found:", attackerId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const attackBonus = await LethalFantasyUtils.offerAttackerGritBonus(
|
||||||
|
attacker,
|
||||||
|
attackRoll,
|
||||||
|
defenseRoll,
|
||||||
|
attackerName,
|
||||||
|
defenderName
|
||||||
|
)
|
||||||
|
|
||||||
|
const attackRollFinal = attackRoll + attackBonus
|
||||||
|
|
||||||
|
// Maintenant créer le message de comparaison
|
||||||
|
await LethalFantasyUtils.compareAttackDefense({
|
||||||
|
attackerName,
|
||||||
|
attackerId,
|
||||||
|
attackRoll: attackRollFinal,
|
||||||
|
attackWeaponId,
|
||||||
|
attackRollType,
|
||||||
|
attackRollKey,
|
||||||
|
defenderName,
|
||||||
|
defenderId,
|
||||||
|
defenseRoll
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async showDefenseRequest(msg) {
|
||||||
|
const attackerName = msg.attackerName
|
||||||
|
const attackerId = msg.attackerId
|
||||||
|
const defenderName = msg.defenderName
|
||||||
|
const weaponName = msg.weaponName || "attack"
|
||||||
|
const attackRoll = msg.attackRoll
|
||||||
|
const attackWeaponId = msg.attackWeaponId
|
||||||
|
const attackRollType = msg.attackRollType
|
||||||
|
const attackRollKey = msg.attackRollKey
|
||||||
|
const combatantId = msg.combatantId
|
||||||
|
const tokenId = msg.tokenId
|
||||||
|
|
||||||
|
// Récupérer le défenseur - essayer d'abord depuis le combat, puis depuis le token
|
||||||
|
let defender = null
|
||||||
|
|
||||||
|
if (game.combat && combatantId) {
|
||||||
|
const combatant = game.combat.combatants.get(combatantId)
|
||||||
|
if (combatant) {
|
||||||
|
defender = combatant.actor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas trouvé dans le combat, chercher le token directement
|
||||||
|
if (!defender && tokenId) {
|
||||||
|
const token = canvas.tokens.get(tokenId)
|
||||||
|
if (token) {
|
||||||
|
defender = token.actor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defender) {
|
||||||
|
ui.notifications.error("Defender actor not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMonster = defender.type === "monster"
|
||||||
|
|
||||||
|
// Pour les monstres, récupérer les attaques activées
|
||||||
|
if (isMonster) {
|
||||||
|
const enabledAttacks = Object.entries(defender.system.attacks).filter(([key, attack]) => attack.enabled)
|
||||||
|
|
||||||
|
if (enabledAttacks.length === 0) {
|
||||||
|
ui.notifications.warn("No enabled attacks available for defense")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer le contenu du dialogue pour monstre
|
||||||
|
let attacksHTML = enabledAttacks.map(([key, attack]) =>
|
||||||
|
`<option value="${key}">${attack.name}</option>`
|
||||||
|
).join("")
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
<div class="defense-request-dialog">
|
||||||
|
<div class="attack-info">
|
||||||
|
<p><strong>${attackerName}</strong> attacks <strong>${defenderName}</strong> with <strong>${weaponName}</strong>!</p>
|
||||||
|
<p>Attack roll: <strong>${attackRoll}</strong></p>
|
||||||
|
</div>
|
||||||
|
<div class="weapon-selection">
|
||||||
|
<label for="defense-attack">Choose your defense attack:</label>
|
||||||
|
<select id="defense-attack" name="attackKey" style="width: 100%; margin-top: 8px;">
|
||||||
|
${attacksHTML}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Afficher le dialogue
|
||||||
|
const result = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: "Defense Roll" },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
content,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: "Roll Defense",
|
||||||
|
icon: "fa-solid fa-shield",
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const attackKey = button.form.elements.attackKey.value
|
||||||
|
return attackKey
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rejectClose: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// Si l'utilisateur a validé, lancer le jet de défense
|
||||||
|
if (result) {
|
||||||
|
// Stocker temporairement les données pour le hook preCreateChatMessage
|
||||||
|
game.lethalFantasy = game.lethalFantasy || {}
|
||||||
|
game.lethalFantasy.nextDefenseData = {
|
||||||
|
attackerId,
|
||||||
|
attackRoll,
|
||||||
|
attackerName,
|
||||||
|
defenderName,
|
||||||
|
attackWeaponId,
|
||||||
|
attackRollType,
|
||||||
|
attackRollKey,
|
||||||
|
defenderId: defender.id
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Storing defense data for monster:", defender.id)
|
||||||
|
|
||||||
|
defender.system.prepareMonsterRoll("monster-defense", result)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour les personnages, récupérer les armes équipées
|
||||||
|
const equippedWeapons = defender.items.filter(i =>
|
||||||
|
i.type === "weapon" && i.system.equipped === true
|
||||||
|
)
|
||||||
|
|
||||||
|
if (equippedWeapons.length === 0) {
|
||||||
|
ui.notifications.warn("No equipped weapons for defense")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Créer le contenu du dialogue pour personnage
|
||||||
|
let weaponsHTML = equippedWeapons.map(w =>
|
||||||
|
`<option value="${w.id}">${w.name}</option>`
|
||||||
|
).join("")
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
<div class="defense-request-dialog">
|
||||||
|
<div class="attack-info">
|
||||||
|
<p><strong>${attackerName}</strong> attacks <strong>${defenderName}</strong> with <strong>${weaponName}</strong>!</p>
|
||||||
|
<p>Attack roll: <strong>${attackRoll}</strong></p>
|
||||||
|
</div>
|
||||||
|
<div class="weapon-selection">
|
||||||
|
<label for="defense-weapon">Choose your defense weapon:</label>
|
||||||
|
<select id="defense-weapon" name="weaponId" style="width: 100%; margin-top: 8px;">
|
||||||
|
${weaponsHTML}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Afficher le dialogue
|
||||||
|
const result = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: "Defense Roll" },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
content,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: "Roll Defense",
|
||||||
|
icon: "fa-solid fa-shield",
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
|
const weaponId = button.form.elements.weaponId.value
|
||||||
|
return weaponId
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rejectClose: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// Si l'utilisateur a validé, lancer le jet de défense
|
||||||
|
if (result) {
|
||||||
|
// Stocker temporairement les données pour le hook preCreateChatMessage
|
||||||
|
game.lethalFantasy = game.lethalFantasy || {}
|
||||||
|
game.lethalFantasy.nextDefenseData = {
|
||||||
|
attackerId,
|
||||||
|
attackRoll,
|
||||||
|
attackerName,
|
||||||
|
defenderName,
|
||||||
|
attackWeaponId,
|
||||||
|
attackRollType,
|
||||||
|
attackRollKey,
|
||||||
|
defenderId: defender.id
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Storing defense data for character:", defender.id)
|
||||||
|
|
||||||
|
defender.prepareRoll("weapon-defense", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async offerGritLuckBonus(defender, attackRoll, currentDefenseRoll, attackerName, defenderName) {
|
||||||
|
let totalBonus = 0
|
||||||
|
let keepOffering = true
|
||||||
|
|
||||||
|
while (keepOffering && currentDefenseRoll + totalBonus < attackRoll) {
|
||||||
|
const currentGrit = defender.system.grit.current
|
||||||
|
const currentLuck = defender.system.luck.current
|
||||||
|
|
||||||
|
// Si plus de points disponibles, sortir
|
||||||
|
if (currentGrit <= 0 && currentLuck <= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttons = []
|
||||||
|
|
||||||
|
if (currentGrit > 0) {
|
||||||
|
buttons.push({
|
||||||
|
action: "grit",
|
||||||
|
label: `Spend 1 Grit (+1D6) [${currentGrit} left]`,
|
||||||
|
icon: "fa-solid fa-fist-raised",
|
||||||
|
callback: () => "grit"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLuck > 0) {
|
||||||
|
buttons.push({
|
||||||
|
action: "luck",
|
||||||
|
label: `Spend 1 Luck (+1D6) [${currentLuck} left]`,
|
||||||
|
icon: "fa-solid fa-clover",
|
||||||
|
callback: () => "luck"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buttons.push({
|
||||||
|
action: "continue",
|
||||||
|
label: "Continue (no bonus)",
|
||||||
|
icon: "fa-solid fa-forward",
|
||||||
|
callback: () => "continue"
|
||||||
|
})
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
<div class="grit-luck-dialog">
|
||||||
|
<div class="combat-status">
|
||||||
|
<p><strong>${attackerName}</strong> rolled <strong>${attackRoll}</strong></p>
|
||||||
|
<p><strong>${defenderName}</strong> currently has <strong>${currentDefenseRoll + totalBonus}</strong></p>
|
||||||
|
${totalBonus > 0 ? `<p class="bonus-info">Bonus already added: +${totalBonus}</p>` : ''}
|
||||||
|
</div>
|
||||||
|
<p class="offer-text">You are losing! Spend Grit or Luck to add 1D6 to your defense?</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const choice = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: "Defend with Grit or Luck" },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
content,
|
||||||
|
buttons,
|
||||||
|
rejectClose: false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!choice || choice === "continue") {
|
||||||
|
keepOffering = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancer 1D6
|
||||||
|
const bonusRoll = new Roll("1d6")
|
||||||
|
await bonusRoll.evaluate()
|
||||||
|
|
||||||
|
if (game?.dice3d) {
|
||||||
|
await game.dice3d.showForRoll(bonusRoll, game.user, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalBonus += bonusRoll.total
|
||||||
|
|
||||||
|
// Déduire le point de Grit ou Luck
|
||||||
|
if (choice === "grit") {
|
||||||
|
await defender.update({ "system.grit.current": currentGrit - 1 })
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: `<p><strong>${defenderName}</strong> spends 1 Grit and rolls <strong>${bonusRoll.total}</strong>! (Total defense bonus: +${totalBonus})</p>`,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor: defender })
|
||||||
|
})
|
||||||
|
} else if (choice === "luck") {
|
||||||
|
await defender.update({ "system.luck.current": currentLuck - 1 })
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: `<p><strong>${defenderName}</strong> spends 1 Luck and rolls <strong>${bonusRoll.total}</strong>! (Total defense bonus: +${totalBonus})</p>`,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor: defender })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalBonus
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async offerAttackerGritBonus(attacker, currentAttackRoll, defenseRoll, attackerName, defenderName) {
|
||||||
|
let totalBonus = 0
|
||||||
|
let keepOffering = true
|
||||||
|
|
||||||
|
while (keepOffering && currentAttackRoll + totalBonus <= defenseRoll) {
|
||||||
|
const currentGrit = attacker.system.grit.current
|
||||||
|
|
||||||
|
// Si plus de points de Grit disponibles, sortir
|
||||||
|
if (currentGrit <= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
action: "grit",
|
||||||
|
label: `Spend 1 Grit (+1D6) [${currentGrit} left]`,
|
||||||
|
icon: "fa-solid fa-fist-raised",
|
||||||
|
callback: () => "grit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "continue",
|
||||||
|
label: "Continue (no bonus)",
|
||||||
|
icon: "fa-solid fa-forward",
|
||||||
|
callback: () => "continue"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const content = `
|
||||||
|
<div class="grit-luck-dialog">
|
||||||
|
<div class="combat-status">
|
||||||
|
<p><strong>${attackerName}</strong> currently has <strong>${currentAttackRoll + totalBonus}</strong></p>
|
||||||
|
<p><strong>${defenderName}</strong> rolled <strong>${defenseRoll}</strong></p>
|
||||||
|
${totalBonus > 0 ? `<p class="bonus-info">Bonus already added: +${totalBonus}</p>` : ''}
|
||||||
|
</div>
|
||||||
|
<p class="offer-text">You are losing! Spend Grit to add 1D6 to your attack?</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
const choice = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: "Attack with Grit" },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
content,
|
||||||
|
buttons,
|
||||||
|
rejectClose: false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!choice || choice === "continue") {
|
||||||
|
keepOffering = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancer 1D6
|
||||||
|
const bonusRoll = new Roll("1d6")
|
||||||
|
await bonusRoll.evaluate()
|
||||||
|
|
||||||
|
if (game?.dice3d) {
|
||||||
|
await game.dice3d.showForRoll(bonusRoll, game.user, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalBonus += bonusRoll.total
|
||||||
|
|
||||||
|
// Déduire le point de Grit
|
||||||
|
await attacker.update({ "system.grit.current": currentGrit - 1 })
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: `<p><strong>${attackerName}</strong> spends 1 Grit and rolls <strong>${bonusRoll.total}</strong>! (Total attack bonus: +${totalBonus})</p>`,
|
||||||
|
speaker: ChatMessage.getSpeaker({ actor: attacker })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalBonus
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async compareAttackDefense(data) {
|
||||||
|
console.log("compareAttackDefense called with:", data)
|
||||||
|
const isAttackWin = data.attackRoll > data.defenseRoll
|
||||||
|
console.log("isAttackWin:", isAttackWin, "attackRoll:", data.attackRoll, "defenseRoll:", data.defenseRoll)
|
||||||
|
|
||||||
|
let damageButton = ""
|
||||||
|
if (isAttackWin && (data.attackWeaponId || data.attackRollKey)) {
|
||||||
|
console.log("Creating damage button. defenderId:", data.defenderId)
|
||||||
|
// Déterminer le type de dégâts à lancer
|
||||||
|
if (data.attackRollType === "weapon-attack") {
|
||||||
|
damageButton = `
|
||||||
|
<div class="attack-result-damage">
|
||||||
|
<button class="roll-damage-btn" data-attacker-id="${data.attackerId}" data-defender-id="${data.defenderId}" data-weapon-id="${data.attackWeaponId}" data-damage-type="small">
|
||||||
|
<i class="fa-solid fa-dice-d6"></i> Damage (Small)
|
||||||
|
</button>
|
||||||
|
<button class="roll-damage-btn" data-attacker-id="${data.attackerId}" data-defender-id="${data.defenderId}" data-weapon-id="${data.attackWeaponId}" data-damage-type="medium">
|
||||||
|
<i class="fa-solid fa-dice-d20"></i> Damage (Medium)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
} else if (data.attackRollType === "monster-attack") {
|
||||||
|
damageButton = `
|
||||||
|
<div class="attack-result-damage">
|
||||||
|
<button class="roll-damage-btn" data-attacker-id="${data.attackerId}" data-defender-id="${data.defenderId}" data-attack-key="${data.attackRollKey}" data-damage-type="monster">
|
||||||
|
<i class="fa-solid fa-burst"></i> Damage
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultMessage = `
|
||||||
|
<div class="attack-result ${isAttackWin ? 'attack-success' : 'attack-failure'}">
|
||||||
|
<h3><i class="fa-solid ${isAttackWin ? 'fa-sword' : 'fa-shield'}"></i> Combat Result</h3>
|
||||||
|
<div class="combat-comparison">
|
||||||
|
<div class="combat-side attacker ${isAttackWin ? 'winner' : 'loser'}">
|
||||||
|
<div class="side-label">Attacker</div>
|
||||||
|
<div class="side-info">
|
||||||
|
<div class="side-name">${data.attackerName}</div>
|
||||||
|
<div class="side-roll">${data.attackRoll}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="combat-vs">VS</div>
|
||||||
|
<div class="combat-side defender ${isAttackWin ? 'loser' : 'winner'}">
|
||||||
|
<div class="side-label">Defender</div>
|
||||||
|
<div class="side-info">
|
||||||
|
<div class="side-name">${data.defenderName}</div>
|
||||||
|
<div class="side-roll">${data.defenseRoll}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="combat-result-text">
|
||||||
|
${isAttackWin ?
|
||||||
|
`<i class="fa-solid fa-circle-check"></i> <strong>${data.attackerName}</strong> hits <strong>${data.defenderName}</strong>!` :
|
||||||
|
`<i class="fa-solid fa-shield-halved"></i> <strong>${data.defenderName}</strong> parries the attack!`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
${damageButton}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
console.log("Creating combat result message...")
|
||||||
|
await ChatMessage.create({
|
||||||
|
content: resultMessage,
|
||||||
|
speaker: { alias: "Combat System" }
|
||||||
|
})
|
||||||
|
console.log("Combat result message created!")
|
||||||
|
}
|
||||||
|
|
||||||
static registerHandlebarsHelpers() {
|
static registerHandlebarsHelpers() {
|
||||||
|
|
||||||
Handlebars.registerHelper('isNull', function (val) {
|
Handlebars.registerHelper('isNull', function (val) {
|
||||||
@@ -201,4 +711,110 @@ export default class LethalFantasyUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async applyDamage(message, event) {
|
||||||
|
// Récupérer les données du message
|
||||||
|
let combatantId = event.currentTarget.dataset.combatantId
|
||||||
|
if (!combatantId || !game.combat) {
|
||||||
|
ui.notifications.error("No combatant selected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let combatant = game.combat.combatants.get(combatantId)
|
||||||
|
if (!combatant) {
|
||||||
|
ui.notifications.error("Combatant not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetActor = combatant.token?.actor || game.actors.get(combatant.actorId)
|
||||||
|
if (!targetActor) {
|
||||||
|
ui.notifications.error("Target actor not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer les données de dégâts du message
|
||||||
|
let damageTotal = message.rolls[0]?.total || 0
|
||||||
|
let weaponName = message.rolls[0]?.options?.rollName || "Unknown Weapon"
|
||||||
|
|
||||||
|
// Calculer les DR
|
||||||
|
let armorDR = targetActor.computeDamageReduction() || 0
|
||||||
|
let shieldDR = targetActor.getShieldDR() || 0
|
||||||
|
let totalDR = armorDR + shieldDR
|
||||||
|
|
||||||
|
// Créer le dialogue
|
||||||
|
const content = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
"systems/fvtt-lethal-fantasy/templates/apply-damage-dialog.hbs",
|
||||||
|
{
|
||||||
|
targetName: targetActor.name,
|
||||||
|
weaponName: weaponName,
|
||||||
|
damageTotal: damageTotal,
|
||||||
|
armorDR: armorDR,
|
||||||
|
shieldDR: shieldDR,
|
||||||
|
totalDR: totalDR,
|
||||||
|
damageNoDR: damageTotal,
|
||||||
|
damageWithArmor: Math.max(0, damageTotal - armorDR),
|
||||||
|
damageWithAll: Math.max(0, damageTotal - totalDR)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const result = await foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: "Apply Damage" },
|
||||||
|
classes: ["lethalfantasy"],
|
||||||
|
position: { width: 280 },
|
||||||
|
content,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
action: "noDR",
|
||||||
|
label: "No DR",
|
||||||
|
callback: () => ({ drType: "none", damage: damageTotal })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "armorDR",
|
||||||
|
label: "With Armor DR",
|
||||||
|
callback: () => ({ drType: "armor", damage: Math.max(0, damageTotal - armorDR) })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "allDR",
|
||||||
|
label: "With Armor + Shield DR",
|
||||||
|
callback: () => ({ drType: "all", damage: Math.max(0, damageTotal - totalDR) })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: "cancel",
|
||||||
|
label: "Cancel",
|
||||||
|
callback: () => null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rejectClose: false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result && result.damage !== undefined) {
|
||||||
|
await targetActor.applyDamage(-result.damage)
|
||||||
|
|
||||||
|
// Message de confirmation
|
||||||
|
let drText = ""
|
||||||
|
if (result.drType === "armor") {
|
||||||
|
drText = `Armor DR: ${armorDR}`
|
||||||
|
} else if (result.drType === "all") {
|
||||||
|
drText = `Total DR: ${totalDR}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageContent = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
"systems/fvtt-lethal-fantasy/templates/damage-applied-message.hbs",
|
||||||
|
{
|
||||||
|
targetName: targetActor.name,
|
||||||
|
damage: result.damage,
|
||||||
|
drText: drText,
|
||||||
|
weaponName: weaponName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
speaker: { alias: targetActor.name },
|
||||||
|
rollMode: "gmroll",
|
||||||
|
content: messageContent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
BIN
packs-system/lf-equipment/000502.ldb
Normal file
BIN
packs-system/lf-equipment/000502.ldb
Normal file
Binary file not shown.
0
packs-system/lf-equipment/000529.log
Normal file
0
packs-system/lf-equipment/000529.log
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000261
|
MANIFEST-000527
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:22:26.619523 7fa7f51fa6c0 Recovering log #259
|
2026/01/19-20:32:07.348929 7f14d8ff96c0 Recovering log #525
|
||||||
2025/04/25-21:22:26.629405 7fa7f51fa6c0 Delete type=3 #257
|
2026/01/19-20:32:07.358983 7f14d8ff96c0 Delete type=3 #523
|
||||||
2025/04/25-21:22:26.629471 7fa7f51fa6c0 Delete type=0 #259
|
2026/01/19-20:32:07.359059 7f14d8ff96c0 Delete type=0 #525
|
||||||
2025/04/25-21:28:11.794720 7fa7eebff6c0 Level-0 table #264: started
|
2026/01/19-22:34:04.043006 7f1243fff6c0 Level-0 table #530: started
|
||||||
2025/04/25-21:28:11.794743 7fa7eebff6c0 Level-0 table #264: 0 bytes OK
|
2026/01/19-22:34:04.043050 7f1243fff6c0 Level-0 table #530: 0 bytes OK
|
||||||
2025/04/25-21:28:11.828838 7fa7eebff6c0 Delete type=0 #262
|
2026/01/19-22:34:04.052889 7f1243fff6c0 Delete type=0 #528
|
||||||
2025/04/25-21:28:11.872804 7fa7eebff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.082744 7f1243fff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:28:11.872877 7fa7eebff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.092309 7f1243fff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:12:25.063567 7fa7f49f96c0 Recovering log #255
|
2026/01/19-20:23:50.466717 7f14da7fc6c0 Recovering log #521
|
||||||
2025/04/25-21:12:25.123483 7fa7f49f96c0 Delete type=3 #253
|
2026/01/19-20:23:50.476745 7f14da7fc6c0 Delete type=3 #519
|
||||||
2025/04/25-21:12:25.123549 7fa7f49f96c0 Delete type=0 #255
|
2026/01/19-20:23:50.476798 7f14da7fc6c0 Delete type=0 #521
|
||||||
2025/04/25-21:21:41.663813 7fa7eebff6c0 Level-0 table #260: started
|
2026/01/19-20:32:02.937243 7f1243fff6c0 Level-0 table #526: started
|
||||||
2025/04/25-21:21:41.663837 7fa7eebff6c0 Level-0 table #260: 0 bytes OK
|
2026/01/19-20:32:02.937265 7f1243fff6c0 Level-0 table #526: 0 bytes OK
|
||||||
2025/04/25-21:21:41.670063 7fa7eebff6c0 Delete type=0 #258
|
2026/01/19-20:32:02.943907 7f1243fff6c0 Delete type=0 #524
|
||||||
2025/04/25-21:21:41.683068 7fa7eebff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956456 7f1243fff6c0 Manual compaction at level-0 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:21:41.683094 7fa7eebff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!znm6T1ef4qQI8BX7' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956498 7f1243fff6c0 Manual compaction at level-1 from '!folders!ATr9wZhg5uTVTksM' @ 72057594037927935 : 1 .. '!items!zw9RQocTdz3HRjZK' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs-system/lf-equipment/MANIFEST-000527
Normal file
BIN
packs-system/lf-equipment/MANIFEST-000527
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs-system/lf-gifts/000411.ldb
Normal file
BIN
packs-system/lf-gifts/000411.ldb
Normal file
Binary file not shown.
BIN
packs-system/lf-gifts/000447.ldb
Normal file
BIN
packs-system/lf-gifts/000447.ldb
Normal file
Binary file not shown.
0
packs-system/lf-gifts/000526.log
Normal file
0
packs-system/lf-gifts/000526.log
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000260
|
MANIFEST-000524
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:22:26.632055 7fa7ef7fe6c0 Recovering log #258
|
2026/01/19-20:32:07.362345 7f14d9ffb6c0 Recovering log #522
|
||||||
2025/04/25-21:22:26.642442 7fa7ef7fe6c0 Delete type=3 #256
|
2026/01/19-20:32:07.372537 7f14d9ffb6c0 Delete type=3 #520
|
||||||
2025/04/25-21:22:26.642504 7fa7ef7fe6c0 Delete type=0 #258
|
2026/01/19-20:32:07.372596 7f14d9ffb6c0 Delete type=0 #522
|
||||||
2025/04/25-21:28:11.762447 7fa7eebff6c0 Level-0 table #263: started
|
2026/01/19-22:34:04.165591 7f1243fff6c0 Level-0 table #527: started
|
||||||
2025/04/25-21:28:11.762488 7fa7eebff6c0 Level-0 table #263: 0 bytes OK
|
2026/01/19-22:34:04.165637 7f1243fff6c0 Level-0 table #527: 0 bytes OK
|
||||||
2025/04/25-21:28:11.794608 7fa7eebff6c0 Delete type=0 #261
|
2026/01/19-22:34:04.175509 7f1243fff6c0 Delete type=0 #525
|
||||||
2025/04/25-21:28:11.872774 7fa7eebff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.175734 7f1243fff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:28:11.872860 7fa7eebff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.175767 7f1243fff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:12:25.126076 7fa7ef7fe6c0 Recovering log #254
|
2026/01/19-20:23:50.482057 7f14d8ff96c0 Recovering log #518
|
||||||
2025/04/25-21:12:25.194012 7fa7ef7fe6c0 Delete type=3 #252
|
2026/01/19-20:23:50.491682 7f14d8ff96c0 Delete type=3 #516
|
||||||
2025/04/25-21:12:25.194129 7fa7ef7fe6c0 Delete type=0 #254
|
2026/01/19-20:23:50.491756 7f14d8ff96c0 Delete type=0 #518
|
||||||
2025/04/25-21:21:41.677033 7fa7eebff6c0 Level-0 table #259: started
|
2026/01/19-20:32:02.944004 7f1243fff6c0 Level-0 table #523: started
|
||||||
2025/04/25-21:21:41.677055 7fa7eebff6c0 Level-0 table #259: 0 bytes OK
|
2026/01/19-20:32:02.944026 7f1243fff6c0 Level-0 table #523: 0 bytes OK
|
||||||
2025/04/25-21:21:41.682956 7fa7eebff6c0 Delete type=0 #257
|
2026/01/19-20:32:02.950204 7f1243fff6c0 Delete type=0 #521
|
||||||
2025/04/25-21:21:41.683087 7fa7eebff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956469 7f1243fff6c0 Manual compaction at level-0 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:21:41.683125 7fa7eebff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!zjvGljrLk5SshC9D' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956510 7f1243fff6c0 Manual compaction at level-1 from '!folders!yPWGvxHJbDNHVSnY' @ 72057594037927935 : 1 .. '!items!x5gLtqlW4sdDmHTd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs-system/lf-gifts/MANIFEST-000524
Normal file
BIN
packs-system/lf-gifts/MANIFEST-000524
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs-system/lf-skills/000508.ldb
Normal file
BIN
packs-system/lf-skills/000508.ldb
Normal file
Binary file not shown.
0
packs-system/lf-skills/000531.log
Normal file
0
packs-system/lf-skills/000531.log
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000260
|
MANIFEST-000529
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:22:26.603891 7fa7f49f96c0 Recovering log #258
|
2026/01/19-20:32:07.335896 7f14d97fa6c0 Recovering log #527
|
||||||
2025/04/25-21:22:26.613982 7fa7f49f96c0 Delete type=3 #256
|
2026/01/19-20:32:07.346053 7f14d97fa6c0 Delete type=3 #525
|
||||||
2025/04/25-21:22:26.614103 7fa7f49f96c0 Delete type=0 #258
|
2026/01/19-20:32:07.346120 7f14d97fa6c0 Delete type=0 #527
|
||||||
2025/04/25-21:28:11.828962 7fa7eebff6c0 Level-0 table #263: started
|
2026/01/19-22:34:04.092377 7f1243fff6c0 Level-0 table #532: started
|
||||||
2025/04/25-21:28:11.828987 7fa7eebff6c0 Level-0 table #263: 0 bytes OK
|
2026/01/19-22:34:04.092412 7f1243fff6c0 Level-0 table #532: 0 bytes OK
|
||||||
2025/04/25-21:28:11.872564 7fa7eebff6c0 Delete type=0 #261
|
2026/01/19-22:34:04.101864 7f1243fff6c0 Delete type=0 #530
|
||||||
2025/04/25-21:28:11.872823 7fa7eebff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.133480 7f1243fff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:28:11.872896 7fa7eebff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.133550 7f1243fff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:12:25.004274 7fa7f51fa6c0 Recovering log #254
|
2026/01/19-20:23:50.451679 7f14d9ffb6c0 Recovering log #523
|
||||||
2025/04/25-21:12:25.060536 7fa7f51fa6c0 Delete type=3 #252
|
2026/01/19-20:23:50.462356 7f14d9ffb6c0 Delete type=3 #521
|
||||||
2025/04/25-21:12:25.060709 7fa7f51fa6c0 Delete type=0 #254
|
2026/01/19-20:23:50.462416 7f14d9ffb6c0 Delete type=0 #523
|
||||||
2025/04/25-21:21:41.670183 7fa7eebff6c0 Level-0 table #259: started
|
2026/01/19-20:32:02.930994 7f1243fff6c0 Level-0 table #528: started
|
||||||
2025/04/25-21:21:41.670208 7fa7eebff6c0 Level-0 table #259: 0 bytes OK
|
2026/01/19-20:32:02.931037 7f1243fff6c0 Level-0 table #528: 0 bytes OK
|
||||||
2025/04/25-21:21:41.676916 7fa7eebff6c0 Delete type=0 #257
|
2026/01/19-20:32:02.937118 7f1243fff6c0 Delete type=0 #526
|
||||||
2025/04/25-21:21:41.683078 7fa7eebff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956440 7f1243fff6c0 Manual compaction at level-0 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:21:41.683166 7fa7eebff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956479 7f1243fff6c0 Manual compaction at level-1 from '!folders!7j8H7DbmBb9Uza2X' @ 72057594037927935 : 1 .. '!items!zt8s7564ep1La4XQ' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs-system/lf-skills/MANIFEST-000529
Normal file
BIN
packs-system/lf-skills/MANIFEST-000529
Normal file
Binary file not shown.
BIN
packs-system/lf-spells-miracles/000111.ldb
Normal file
BIN
packs-system/lf-spells-miracles/000111.ldb
Normal file
Binary file not shown.
0
packs-system/lf-spells-miracles/000226.log
Normal file
0
packs-system/lf-spells-miracles/000226.log
Normal file
1
packs-system/lf-spells-miracles/CURRENT
Normal file
1
packs-system/lf-spells-miracles/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000224
|
||||||
0
packs-system/lf-spells-miracles/LOCK
Normal file
0
packs-system/lf-spells-miracles/LOCK
Normal file
8
packs-system/lf-spells-miracles/LOG
Normal file
8
packs-system/lf-spells-miracles/LOG
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
2026/01/19-20:32:07.386680 7f14d97fa6c0 Recovering log #222
|
||||||
|
2026/01/19-20:32:07.397058 7f14d97fa6c0 Delete type=3 #220
|
||||||
|
2026/01/19-20:32:07.397159 7f14d97fa6c0 Delete type=0 #222
|
||||||
|
2026/01/19-22:34:04.082756 7f1243fff6c0 Level-0 table #227: started
|
||||||
|
2026/01/19-22:34:04.082796 7f1243fff6c0 Level-0 table #227: 0 bytes OK
|
||||||
|
2026/01/19-22:34:04.092156 7f1243fff6c0 Delete type=0 #225
|
||||||
|
2026/01/19-22:34:04.092321 7f1243fff6c0 Manual compaction at level-0 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
|
||||||
|
2026/01/19-22:34:04.092355 7f1243fff6c0 Manual compaction at level-1 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
|
||||||
8
packs-system/lf-spells-miracles/LOG.old
Normal file
8
packs-system/lf-spells-miracles/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
2026/01/19-20:23:50.510934 7f14d97fa6c0 Recovering log #218
|
||||||
|
2026/01/19-20:23:50.520501 7f14d97fa6c0 Delete type=3 #216
|
||||||
|
2026/01/19-20:23:50.520578 7f14d97fa6c0 Delete type=0 #218
|
||||||
|
2026/01/19-20:32:02.976313 7f1243fff6c0 Level-0 table #223: started
|
||||||
|
2026/01/19-20:32:02.976359 7f1243fff6c0 Level-0 table #223: 0 bytes OK
|
||||||
|
2026/01/19-20:32:02.982272 7f1243fff6c0 Delete type=0 #221
|
||||||
|
2026/01/19-20:32:02.982509 7f1243fff6c0 Manual compaction at level-0 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
|
||||||
|
2026/01/19-20:32:02.982604 7f1243fff6c0 Manual compaction at level-1 from '!folders!37mu4dxsSuftlnmP' @ 72057594037927935 : 1 .. '!items!zKOpU34oLziGJW6y' @ 0 : 0; will stop at (end)
|
||||||
BIN
packs-system/lf-spells-miracles/MANIFEST-000224
Normal file
BIN
packs-system/lf-spells-miracles/MANIFEST-000224
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs-system/lf-vulnerabilities/000322.ldb
Normal file
BIN
packs-system/lf-vulnerabilities/000322.ldb
Normal file
Binary file not shown.
0
packs-system/lf-vulnerabilities/000525.log
Normal file
0
packs-system/lf-vulnerabilities/000525.log
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000260
|
MANIFEST-000523
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:22:26.644388 7fa7effff6c0 Recovering log #258
|
2026/01/19-20:32:07.374730 7f14d8ff96c0 Recovering log #521
|
||||||
2025/04/25-21:22:26.654206 7fa7effff6c0 Delete type=3 #256
|
2026/01/19-20:32:07.384387 7f14d8ff96c0 Delete type=3 #519
|
||||||
2025/04/25-21:22:26.654257 7fa7effff6c0 Delete type=0 #258
|
2026/01/19-20:32:07.384466 7f14d8ff96c0 Delete type=0 #521
|
||||||
2025/04/25-21:28:11.724988 7fa7eebff6c0 Level-0 table #263: started
|
2026/01/19-22:34:04.031975 7f1243fff6c0 Level-0 table #526: started
|
||||||
2025/04/25-21:28:11.725025 7fa7eebff6c0 Level-0 table #263: 0 bytes OK
|
2026/01/19-22:34:04.032019 7f1243fff6c0 Level-0 table #526: 0 bytes OK
|
||||||
2025/04/25-21:28:11.762266 7fa7eebff6c0 Delete type=0 #261
|
2026/01/19-22:34:04.042831 7f1243fff6c0 Delete type=0 #524
|
||||||
2025/04/25-21:28:11.872740 7fa7eebff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.082725 7f1243fff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:28:11.872841 7fa7eebff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
2026/01/19-22:34:04.092294 7f1243fff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/04/25-21:12:25.197251 7fa7effff6c0 Recovering log #254
|
2026/01/19-20:23:50.495445 7f14d9ffb6c0 Recovering log #517
|
||||||
2025/04/25-21:12:25.252610 7fa7effff6c0 Delete type=3 #252
|
2026/01/19-20:23:50.506507 7f14d9ffb6c0 Delete type=3 #515
|
||||||
2025/04/25-21:12:25.252672 7fa7effff6c0 Delete type=0 #254
|
2026/01/19-20:23:50.506583 7f14d9ffb6c0 Delete type=0 #517
|
||||||
2025/04/25-21:21:41.657695 7fa7eebff6c0 Level-0 table #259: started
|
2026/01/19-20:32:02.950374 7f1243fff6c0 Level-0 table #522: started
|
||||||
2025/04/25-21:21:41.657740 7fa7eebff6c0 Level-0 table #259: 0 bytes OK
|
2026/01/19-20:32:02.950415 7f1243fff6c0 Level-0 table #522: 0 bytes OK
|
||||||
2025/04/25-21:21:41.663703 7fa7eebff6c0 Delete type=0 #257
|
2026/01/19-20:32:02.956303 7f1243fff6c0 Delete type=0 #520
|
||||||
2025/04/25-21:21:41.683056 7fa7eebff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956488 7f1243fff6c0 Manual compaction at level-0 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
||||||
2025/04/25-21:21:41.683109 7fa7eebff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
2026/01/19-20:32:02.956546 7f1243fff6c0 Manual compaction at level-1 from '!folders!mnO9OzE7BEE2KDfh' @ 72057594037927935 : 1 .. '!items!zkK6ixtCsCw3RH9X' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs-system/lf-vulnerabilities/MANIFEST-000523
Normal file
BIN
packs-system/lf-vulnerabilities/MANIFEST-000523
Normal file
Binary file not shown.
@@ -1,21 +0,0 @@
|
|||||||
#lethalfantasy-application-manager {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
font-family: var(--font-primary);
|
|
||||||
font-size: calc(var(--font-size-standard) * 1);
|
|
||||||
color: var(--color-dark-1);
|
|
||||||
background-image: var(--background-image-base);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
|
|
||||||
.lethalfantasy-table {
|
|
||||||
margin: 1rem;
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
.player {
|
|
||||||
font-size: calc(var(--font-size-standard) * 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
min-width: 2.2rem;
|
min-width: 2.2rem;
|
||||||
max-width: 2.2rem;
|
max-width: 2.2rem;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
.character-hp-max {
|
.character-hp-max {
|
||||||
clear: both;
|
clear: both;
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
input {
|
input {
|
||||||
width: 3.2rem;
|
width: 3.2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +93,10 @@
|
|||||||
.character-characteristic {
|
.character-characteristic {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
span {
|
||||||
|
min-width: 2.2rem;
|
||||||
|
max-width: 2.2rem;
|
||||||
|
}
|
||||||
.rollable:hover,
|
.rollable:hover,
|
||||||
.rollable:focus {
|
.rollable:focus {
|
||||||
text-shadow: 0 0 8px var(--color-shadow-primary);
|
text-shadow: 0 0 8px var(--color-shadow-primary);
|
||||||
@@ -218,7 +222,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-biography {
|
.tab.character-biography .main-div {
|
||||||
.biodata {
|
.biodata {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
@@ -248,7 +252,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-skills {
|
.tab.character-skills .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
@@ -310,7 +314,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-equipment {
|
.tab.character-equipment .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
@@ -349,7 +353,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-combat {
|
.tab.character-combat .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
@@ -371,6 +375,9 @@
|
|||||||
min-width: 2.5rem;
|
min-width: 2.5rem;
|
||||||
max-width: 2.5rem;
|
max-width: 2.5rem;
|
||||||
}
|
}
|
||||||
|
.ranged-attack-button {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
button {
|
button {
|
||||||
min-width: 9rem;
|
min-width: 9rem;
|
||||||
}
|
}
|
||||||
@@ -469,7 +476,7 @@
|
|||||||
min-width: 12rem;
|
min-width: 12rem;
|
||||||
}
|
}
|
||||||
.item-detail {
|
.item-detail {
|
||||||
min-width:2rem;
|
min-width: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.shields {
|
.shields {
|
||||||
@@ -488,16 +495,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.item-detail {
|
.item-detail {
|
||||||
min-width:2.5rem;
|
min-width: 2.5rem;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
min-width: 12rem;
|
min-width: 12rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-spells {
|
.tab.character-spells .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
@@ -530,7 +536,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.spells {
|
.spells {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
@@ -541,7 +546,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
.item-img {
|
.item-img {
|
||||||
width: 24px;
|
min-width: 24px;
|
||||||
|
max-width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
@@ -558,7 +564,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.character-miracles {
|
.tab.character-miracles .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
|
|||||||
332
styles/chat.less
332
styles/chat.less
@@ -1,33 +1,34 @@
|
|||||||
&.fortune {
|
&.fortune {
|
||||||
img {
|
img {
|
||||||
border: 0px;
|
border: 0px;
|
||||||
}
|
}
|
||||||
.intro-chat {
|
.intro-chat {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
.intro-img {
|
.intro-img {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
width: 80px;
|
width: 80px;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.intro-right {
|
.intro-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.introText {
|
.introText {
|
||||||
font-family: var(--font-secondary);
|
font-family: var(--font-secondary);
|
||||||
font-size: calc(var(--font-size-standard) * 1.2);
|
font-size: calc(var(--font-size-standard) * 1.2);
|
||||||
width: 210px;
|
width: 210px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.button.control, .fortune-accepted {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: calc(var(--font-size-standard) * 1.3);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button.control,
|
||||||
|
.fortune-accepted {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ask-roll {
|
&.ask-roll {
|
||||||
@@ -38,3 +39,278 @@
|
|||||||
font-family: var(--font-secondary);
|
font-family: var(--font-secondary);
|
||||||
font-size: calc(var(--font-size-standard) * 1.2);
|
font-size: calc(var(--font-size-standard) * 1.2);
|
||||||
}
|
}
|
||||||
|
.defense-request {
|
||||||
|
padding: 12px;
|
||||||
|
background: linear-gradient(to bottom, #3a3930 0%, #2a2920 100%);
|
||||||
|
border: 2px solid #d4af37;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
color: #d4af37;
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.1);
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 8px 0;
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.95);
|
||||||
|
line-height: 1.4;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.defense-prompt {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 8px;
|
||||||
|
background: rgba(212, 175, 55, 0.1);
|
||||||
|
border-left: 3px solid #d4af37;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #d4af37;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.defense-request-dialog {
|
||||||
|
.attack-info {
|
||||||
|
padding: 12px;
|
||||||
|
background: linear-gradient(to bottom, rgba(42, 41, 32, 0.8) 0%, rgba(26, 25, 16, 0.9) 100%);
|
||||||
|
border: 1px solid rgba(212, 175, 55, 0.5);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 6px 0;
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.95);
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.weapon-selection {
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: #3a3930 !important;
|
||||||
|
border: 1px solid #d4af37;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.95);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #f0e6d2;
|
||||||
|
box-shadow: 0 0 0 2px rgba(212, 175, 55, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
background: #3a3930 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
padding: 6px;
|
||||||
|
|
||||||
|
&:checked,
|
||||||
|
&:hover {
|
||||||
|
background: #4a4940 !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grit-luck-dialog {
|
||||||
|
.combat-status {
|
||||||
|
padding: 12px;
|
||||||
|
background: linear-gradient(to bottom, rgba(42, 41, 32, 0.8) 0%, rgba(26, 25, 16, 0.9) 100%);
|
||||||
|
border: 1px solid rgba(212, 175, 55, 0.5);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 6px 0;
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.95);
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bonus-info {
|
||||||
|
color: #90EE90;
|
||||||
|
font-style: italic;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.offer-text {
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.attack-result {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
|
||||||
|
margin: 8px 0;
|
||||||
|
|
||||||
|
&.attack-success {
|
||||||
|
background: linear-gradient(to bottom, rgba(139, 0, 0, 0.2) 0%, rgba(100, 0, 0, 0.3) 100%);
|
||||||
|
border: 2px solid rgba(220, 20, 60, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.attack-failure {
|
||||||
|
background: linear-gradient(to bottom, rgba(0, 100, 139, 0.2) 0%, rgba(0, 70, 100, 0.3) 100%);
|
||||||
|
border: 2px solid rgba(70, 130, 180, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
color: #d4af37;
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.2);
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-comparison {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
.combat-side {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&.winner {
|
||||||
|
background: rgba(0, 255, 0, 0.1);
|
||||||
|
border: 2px solid rgba(0, 255, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loser {
|
||||||
|
background: rgba(255, 0, 0, 0.1);
|
||||||
|
border: 2px solid rgba(255, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-label {
|
||||||
|
font-size: calc(var(--font-size-standard) * 0.8);
|
||||||
|
color: #aaa;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-name {
|
||||||
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-roll {
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.5);
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-vs {
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.2);
|
||||||
|
color: #d4af37;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.combat-result-text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: calc(var(--font-size-standard) * 1.1);
|
||||||
|
color: #f0e6d2;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #d4af37;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.attack-result-damage {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.roll-damage-btn {
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: linear-gradient(to bottom, #8b0000 0%, #660000 100%);
|
||||||
|
border: 1px solid #ff0000;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #f0e6d2;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(to bottom, #a00000 0%, #7b0000 100%);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,5 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "BaskervilleBold";
|
font-family: "BaskervilleBold";
|
||||||
src: url("../fonts/baskerville-bold.ttf") format("truetype");
|
src: url("../assets/fonts/baskerville-bold.ttf") format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,4 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@import "roll.less";
|
@import "roll.less";
|
||||||
@import "application-manager.less";
|
@import "hud.less";
|
||||||
|
|||||||
@@ -6,6 +6,17 @@
|
|||||||
--logo-standard: url("../assets/ui/lf_logo_small_02.webp");
|
--logo-standard: url("../assets/ui/lf_logo_small_02.webp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.initiative-area {
|
||||||
|
min-width: 8rem;
|
||||||
|
max-width: 8rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
input {
|
||||||
|
min-width: 3rem;
|
||||||
|
max-width: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#logo {
|
#logo {
|
||||||
content: var(--logo-standard);
|
content: var(--logo-standard);
|
||||||
width: 50px;
|
width: 50px;
|
||||||
@@ -36,7 +47,7 @@ i.lethalfantasy {
|
|||||||
|
|
||||||
.application.dialog.lethalfantasy {
|
.application.dialog.lethalfantasy {
|
||||||
font-family: var(--font-primary);
|
font-family: var(--font-primary);
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
background-image: var(--background-image-base);
|
background-image: var(--background-image-base);
|
||||||
button:hover {
|
button:hover {
|
||||||
background: var(--color-dark-6);
|
background: var(--color-dark-6);
|
||||||
@@ -59,12 +70,12 @@ i.lethalfantasy {
|
|||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.combat-sidebar li.combatant .token-initiative .initiative{
|
.combat-sidebar li.combatant .token-initiative .initiative {
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.combat-sidebar li.combatant .token-initiative {
|
.combat-sidebar li.combatant .token-initiative {
|
||||||
flex:none;
|
flex: none;
|
||||||
}
|
}
|
||||||
.initiative-minus {
|
.initiative-minus {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
|||||||
44
styles/hud.less
Normal file
44
styles/hud.less
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#token-hud .hp-loss-wrap {
|
||||||
|
position: absolute;
|
||||||
|
left: 75px;
|
||||||
|
display: none;
|
||||||
|
top: 50%;
|
||||||
|
width: 48px;
|
||||||
|
text-align: start;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-wrap-col1 {
|
||||||
|
transform: translate(-200%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-wrap-col2 {
|
||||||
|
transform: translate(-300%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-wrap-col3 {
|
||||||
|
transform: translate(-400%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-hud-active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-hud-disabled {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hud-loss-hp-button-select {
|
||||||
|
max-width: 40px;
|
||||||
|
background-image: var(--background-image-base);
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
width: max-content;
|
||||||
|
margin: 0;
|
||||||
|
color:#252424;
|
||||||
|
}
|
||||||
|
|
||||||
|
#token-hud .hp-loss-wrap .hud-loss-hp-button-select {
|
||||||
|
padding-left: 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
@@ -6,6 +6,14 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
|
|
||||||
|
nav.tabs [data-tab] {
|
||||||
|
color: #636060;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.tabs [data-tab].active {
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
|
||||||
input:disabled,
|
input:disabled,
|
||||||
select:disabled {
|
select:disabled {
|
||||||
background-color: rgba(0, 0, 0, 0.2);
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
@@ -39,11 +47,11 @@
|
|||||||
input,
|
input,
|
||||||
select {
|
select {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
font-family: var(--font-secondary);
|
font-family: var(--font-secondary);
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +75,33 @@
|
|||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
label {
|
||||||
|
align-content: center;
|
||||||
|
min-width: 10rem;
|
||||||
|
max-width: 10rem;
|
||||||
|
}
|
||||||
|
select,
|
||||||
|
input {
|
||||||
|
text-align: left;
|
||||||
|
min-width: 12rem;
|
||||||
|
max-width: 12rem;
|
||||||
|
}
|
||||||
|
input[type="checkbox"] {
|
||||||
|
min-width: 1.2rem;
|
||||||
|
max-width: 1.2rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-family: var(--font-secondary);
|
font-family: var(--font-secondary);
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
flex: 50%;
|
flex: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +109,6 @@
|
|||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
margin-right: 0.2rem;
|
margin-right: 0.2rem;
|
||||||
/*border-color: black;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 2%;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shift-right {
|
.shift-right {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
|
||||||
.monster-hp {
|
.monster-hp {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
@@ -46,7 +45,7 @@
|
|||||||
min-width: 2.2rem;
|
min-width: 2.2rem;
|
||||||
max-width: 2.2rem;
|
max-width: 2.2rem;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
.character-hp-max {
|
.character-hp-max {
|
||||||
clear: both;
|
clear: both;
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
input {
|
input {
|
||||||
width: 3.2rem;
|
width: 3.2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: calc(var(--font-size-standard) * 1.0);
|
font-size: calc(var(--font-size-standard) * 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,6 +98,10 @@
|
|||||||
text-shadow: 0 0 8px var(--color-shadow-primary);
|
text-shadow: 0 0 8px var(--color-shadow-primary);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
span {
|
||||||
|
min-width: 2.2rem;
|
||||||
|
max-width: 2.2rem;
|
||||||
|
}
|
||||||
.form-group {
|
.form-group {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
@@ -117,9 +120,11 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
.monster-skill {
|
.monster-skill {
|
||||||
display: flex;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, auto 2.5rem);
|
||||||
|
gap: 0.5rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 0.5rem;
|
|
||||||
.rollable:hover,
|
.rollable:hover,
|
||||||
.rollable:focus {
|
.rollable:focus {
|
||||||
text-shadow: 0 0 8px var(--color-shadow-primary);
|
text-shadow: 0 0 8px var(--color-shadow-primary);
|
||||||
@@ -130,12 +135,9 @@
|
|||||||
max-width: 2.5rem;
|
max-width: 2.5rem;
|
||||||
}
|
}
|
||||||
.name {
|
.name {
|
||||||
flex: 1;
|
|
||||||
min-width: 3.2rem;
|
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
.form-group {
|
.form-group {
|
||||||
flex: 1;
|
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
.form-fields {
|
.form-fields {
|
||||||
flex: none;
|
flex: none;
|
||||||
@@ -153,8 +155,9 @@
|
|||||||
|
|
||||||
.monster-movement {
|
.monster-movement {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
margin-right: 0.5rem;
|
gap: 4px;
|
||||||
|
|
||||||
.rollable:hover,
|
.rollable:hover,
|
||||||
.rollable:focus {
|
.rollable:focus {
|
||||||
text-shadow: 0 0 8px var(--color-shadow-primary);
|
text-shadow: 0 0 8px var(--color-shadow-primary);
|
||||||
@@ -223,7 +226,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.monster-biography {
|
.tab.monster-biography .main-div {
|
||||||
.biodata {
|
.biodata {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
@@ -248,7 +251,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.monster-skills {
|
.tab.monster-skills .main-div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
legend {
|
legend {
|
||||||
@@ -462,4 +465,3 @@
|
|||||||
min-height: 150px;
|
min-height: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1224
styles/roll.less
1224
styles/roll.less
File diff suppressed because it is too large
Load Diff
14
system.json
14
system.json
@@ -6,7 +6,7 @@
|
|||||||
"download": "#{DOWNLOAD}#",
|
"download": "#{DOWNLOAD}#",
|
||||||
"url": "#{URL}#",
|
"url": "#{URL}#",
|
||||||
"license": "LICENSE",
|
"license": "LICENSE",
|
||||||
"version": "12.0.35",
|
"version": "13.0.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Uberwald",
|
"name": "Uberwald",
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "12",
|
"minimum": "13",
|
||||||
"verified": "12"
|
"verified": "13"
|
||||||
},
|
},
|
||||||
"esmodules": ["lethal-fantasy.mjs"],
|
"esmodules": ["lethal-fantasy.mjs"],
|
||||||
"styles": ["css/fvtt-lethal-fantasy.css"],
|
"styles": ["css/fvtt-lethal-fantasy.css"],
|
||||||
@@ -82,6 +82,14 @@
|
|||||||
"system": "fvtt-lethal-fantasy",
|
"system": "fvtt-lethal-fantasy",
|
||||||
"path": "packs-system/lf-vulnerabilities",
|
"path": "packs-system/lf-vulnerabilities",
|
||||||
"type": "Item"
|
"type": "Item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lf-spells-miracles",
|
||||||
|
"banner": "",
|
||||||
|
"label": "Spells & Miracles",
|
||||||
|
"system": "fvtt-lethal-fantasy",
|
||||||
|
"path": "packs-system/lf-spells-miracles",
|
||||||
|
"type": "Item"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"flags": {
|
"flags": {
|
||||||
|
|||||||
37
templates/apply-damage-dialog.hbs
Normal file
37
templates/apply-damage-dialog.hbs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<div class="apply-damage-dialog">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<div class="header">
|
||||||
|
<strong>{{targetName}}</strong>
|
||||||
|
-
|
||||||
|
{{weaponName}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="damage-summary">
|
||||||
|
<span class="label">{{localize
|
||||||
|
"LETHALFANTASY.Dialog.totalDamage"
|
||||||
|
}}:</span>
|
||||||
|
<span class="damage-value">{{damageTotal}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dr-summary">
|
||||||
|
<span>{{localize "LETHALFANTASY.Dialog.armorDR"}}: {{armorDR}}</span>
|
||||||
|
<span>{{localize "LETHALFANTASY.Dialog.shieldDR"}}: {{shieldDR}}</span>
|
||||||
|
<span class="total">DR: <strong>{{totalDR}}</strong></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="damage-options">
|
||||||
|
<div class="option-line">
|
||||||
|
<span>{{localize "LETHALFANTASY.Dialog.noDR"}}</span>
|
||||||
|
<strong>{{damageNoDR}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="option-line">
|
||||||
|
<span>{{localize "LETHALFANTASY.Dialog.withArmor"}}</span>
|
||||||
|
<strong>{{damageWithArmor}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="option-line">
|
||||||
|
<span>{{localize "LETHALFANTASY.Dialog.withAll"}}</span>
|
||||||
|
<strong>{{damageWithAll}}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,96 +1,180 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section
|
||||||
|
class="tab character-{{tab.id}} {{tab.cssClass}}"
|
||||||
|
data-tab="{{tab.id}}"
|
||||||
|
data-group="{{tab.group}}"
|
||||||
|
>
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.biodata"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.biodata"}}</legend>
|
||||||
<div class="biodata">
|
<div class="biodata">
|
||||||
<div class="biodata-elem">
|
<div class="biodata-elem">
|
||||||
<span class="name">Class</span>
|
<span class="name">Class</span>
|
||||||
{{formInput systemFields.biodata.fields.class value=system.biodata.class }}
|
{{formInput
|
||||||
</div>
|
systemFields.biodata.fields.class
|
||||||
<div class="biodata-elem">
|
value=system.biodata.class
|
||||||
<span class="name">Level</span>
|
}}
|
||||||
{{formInput systemFields.biodata.fields.level value=system.biodata.level }}
|
</div>
|
||||||
</div>
|
<div class="biodata-elem">
|
||||||
<div class="biodata-elem">
|
<span class="name">Level</span>
|
||||||
<span class="name">Mortal</span>
|
{{formInput
|
||||||
{{formInput systemFields.biodata.fields.mortal value=system.biodata.mortal }}
|
systemFields.biodata.fields.level
|
||||||
</div>
|
value=system.biodata.level
|
||||||
<div class="biodata-elem">
|
}}
|
||||||
<span class="name">Alignment</span>
|
</div>
|
||||||
{{formInput systemFields.biodata.fields.alignment value=system.biodata.alignment }}
|
<div class="biodata-elem">
|
||||||
</div>
|
<span class="name">Mortal</span>
|
||||||
<div class="biodata-elem">
|
{{formInput
|
||||||
<span class="name">Age</span>
|
systemFields.biodata.fields.mortal
|
||||||
{{formInput systemFields.biodata.fields.age value=system.biodata.age }}
|
value=system.biodata.mortal
|
||||||
</div>
|
}}
|
||||||
<div class="biodata-elem">
|
</div>
|
||||||
<span class="name">Height</span>
|
<div class="biodata-elem">
|
||||||
{{formInput systemFields.biodata.fields.height value=system.biodata.height }}
|
<span class="name">Alignment</span>
|
||||||
</div>
|
{{formInput
|
||||||
<div class="biodata-elem">
|
systemFields.biodata.fields.alignment
|
||||||
<span class="name">Weight</span>
|
value=system.biodata.alignment
|
||||||
{{formInput systemFields.biodata.fields.weight value=system.biodata.weight }}
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="biodata-elem">
|
<div class="biodata-elem">
|
||||||
<span class="name">Eyes</span>
|
<span class="name">Age</span>
|
||||||
{{formInput systemFields.biodata.fields.eyes value=system.biodata.eyes }}
|
{{formInput systemFields.biodata.fields.age value=system.biodata.age}}
|
||||||
</div>
|
</div>
|
||||||
<div class="biodata-elem">
|
<div class="biodata-elem">
|
||||||
<span class="name">Hair</span>
|
<span class="name">Height</span>
|
||||||
{{formInput systemFields.biodata.fields.hair value=system.biodata.hair }}
|
{{formInput
|
||||||
</div>
|
systemFields.biodata.fields.height
|
||||||
<div class="biodata-elem">
|
value=system.biodata.height
|
||||||
<span class="name">Dev. Points (Total)</span>
|
}}
|
||||||
{{formInput systemFields.developmentPoints.fields.total value=system.developmentPoints.total }}
|
</div>
|
||||||
</div>
|
<div class="biodata-elem">
|
||||||
<div class="biodata-elem">
|
<span class="name">Weight</span>
|
||||||
<span class="name">Dev. Points (Rem.)</span>
|
{{formInput
|
||||||
{{formInput systemFields.developmentPoints.fields.remaining value=system.developmentPoints.remaining }}
|
systemFields.biodata.fields.weight
|
||||||
</div>
|
value=system.biodata.weight
|
||||||
<div class="biodata-elem">
|
}}
|
||||||
<span class="name">Magic User</span>
|
</div>
|
||||||
{{formInput systemFields.biodata.fields.magicUser value=system.biodata.magicUser }}
|
<div class="biodata-elem">
|
||||||
</div>
|
<span class="name">Eyes</span>
|
||||||
<div class="biodata-elem">
|
{{formInput
|
||||||
<span class="name">Cleric User</span>
|
systemFields.biodata.fields.eyes
|
||||||
{{formInput systemFields.biodata.fields.clericUser value=system.biodata.clericUser }}
|
value=system.biodata.eyes
|
||||||
</div>
|
}}
|
||||||
<div class="biodata-elem">
|
</div>
|
||||||
<span class="name">Save bonus (1/5levels)</span>
|
<div class="biodata-elem">
|
||||||
{{formInput systemFields.modifiers.fields.saveModifier value=system.modifiers.saveModifier disabled=true}}
|
<span class="name">Hair</span>
|
||||||
</div>
|
{{formInput
|
||||||
|
systemFields.biodata.fields.hair
|
||||||
|
value=system.biodata.hair
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Dev. Points (Total)</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.developmentPoints.fields.total
|
||||||
|
value=system.developmentPoints.total
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Dev. Points (Rem.)</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.developmentPoints.fields.remaining
|
||||||
|
value=system.developmentPoints.remaining
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Magic User</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.biodata.fields.magicUser
|
||||||
|
value=system.biodata.magicUser
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Cleric User</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.biodata.fields.clericUser
|
||||||
|
value=system.biodata.clericUser
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Save bonus (1/5levels)</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.modifiers.fields.saveModifier
|
||||||
|
value=system.modifiers.saveModifier
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if system.biodata.magicUser}}
|
{{#if system.biodata.magicUser}}
|
||||||
<div class="biodata-elem">
|
<div class="biodata-elem">
|
||||||
<span class="name">Spell bonus (1/5levels)</span>
|
<span class="name">Spell bonus (1/5levels)</span>
|
||||||
{{formInput systemFields.modifiers.fields.levelSpellModifier value=system.modifiers.levelSpellModifier disabled=true}}
|
{{formInput
|
||||||
</div>
|
systemFields.modifiers.fields.levelSpellModifier
|
||||||
{{/if}}
|
value=system.modifiers.levelSpellModifier
|
||||||
{{#if system.biodata.clericUser}}
|
disabled=true
|
||||||
<div class="biodata-elem">
|
}}
|
||||||
<span class="name">Miracle bonus (1/5levels)</span>
|
</div>
|
||||||
{{formInput systemFields.modifiers.fields.levelMiracleModifier value=system.modifiers.levelMiracleModifier disabled=true}}
|
{{/if}}
|
||||||
</div>
|
{{#if system.biodata.clericUser}}
|
||||||
{{/if}}
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Miracle bonus (1/5levels)</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.modifiers.fields.levelMiracleModifier
|
||||||
|
value=system.modifiers.levelMiracleModifier
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div class="biodata-elem">
|
<div class="biodata-elem">
|
||||||
<span class="name">Last HD roll</span>
|
<span class="name">Last HD roll</span>
|
||||||
{{formInput systemFields.biodata.fields.hpPerLevel value=system.biodata.hpPerLevel disabled=true}}
|
{{formInput
|
||||||
</div>
|
systemFields.biodata.fields.hpPerLevel
|
||||||
|
value=system.biodata.hpPerLevel
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="biodata-elem">
|
||||||
|
<span class="name">Natural DR</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.biodata.fields.naturalDR
|
||||||
|
value=system.biodata.naturalDR
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="biodata-elem">
|
||||||
</fieldset>
|
<span class="name">Magical DR</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.biodata.fields.magicDR
|
||||||
|
value=system.biodata.magicDR
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<fieldset>
|
</fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.description"}}</legend>
|
|
||||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description"
|
|
||||||
toggled=true}}
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.notes"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.description"}}</legend>
|
||||||
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
|
{{formInput
|
||||||
</fieldset>
|
systemFields.description
|
||||||
|
enriched=enrichedDescription
|
||||||
|
value=system.description
|
||||||
|
name="system.description"
|
||||||
|
toggled=true
|
||||||
|
}}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{{localize "LETHALFANTASY.Label.notes"}}</legend>
|
||||||
|
{{formInput
|
||||||
|
systemFields.notes
|
||||||
|
enriched=enrichedNotes
|
||||||
|
value=system.notes
|
||||||
|
name="system.notes"
|
||||||
|
toggled=true
|
||||||
|
}}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -1,159 +1,165 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="combat" data-group="sheet">
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.combatDetails"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.combatDetails"}}</legend>
|
||||||
<div class="combat-details">
|
<div class="combat-details">
|
||||||
<div class="combat-detail">
|
<div class="combat-detail">
|
||||||
|
|
||||||
<button class="action" data-action="rangedAttackDefense">
|
<button class="action ranged-attack-button" data-action="rangedAttackDefense">
|
||||||
{{localize "LETHALFANTASY.Label.rangedAttackDefense"}}
|
{{localize "LETHALFANTASY.Label.rangedAttackDefense"}}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="action" data-action="rollInitiative">
|
<button class="action ranged-attack-button" data-action="rollInitiative">
|
||||||
{{localize "LETHALFANTASY.Label.rollInitiative"}}
|
{{localize "LETHALFANTASY.Label.rollInitiative"}}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<div class="flexrow armor-hp">
|
||||||
|
<span class="name">{{localize "LETHALFANTASY.Label.armorHitPoints"}}</span>
|
||||||
|
{{formInput systemFields.combat.fields.armorHitPoints value=system.combat.armorHitPoints localize=true }}
|
||||||
|
<a data-action="armorHitPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
||||||
|
<a data-action="armorHitPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flexrow granted">
|
||||||
|
<span class="">{{localize
|
||||||
|
"LETHALFANTASY.Label.grantedAttackDice"}}</a></span>
|
||||||
|
{{formInput systemFields.granted.fields.attackDice value=system.granted.attackDice disabled=isPlayMode }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flexrow granted ">
|
||||||
|
<span class="">{{localize
|
||||||
|
"LETHALFANTASY.Label.grantedDefenseDice"}}</a></span>
|
||||||
|
{{formInput systemFields.granted.fields.defenseDice value=system.granted.defenseDice disabled=isPlayMode }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flexrow granted">
|
||||||
|
<span class="">{{localize
|
||||||
|
"LETHALFANTASY.Label.grantedDamageDice"}}</a></span>
|
||||||
|
{{formInput systemFields.granted.fields.damageDice value=system.granted.damageDice disabled=isPlayMode }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flexrow armor-hp">
|
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.armorHitPoints"}}</span>
|
|
||||||
{{formInput systemFields.combat.fields.armorHitPoints value=system.combat.armorHitPoints localize=true }}
|
|
||||||
<a data-action="armorHitPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
|
||||||
<a data-action="armorHitPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flexrow granted">
|
|
||||||
<span class=""><a class="rollable" data-roll-type="granted" data-roll-key="attackDice"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.grantedAttackDice"}}</a></span>
|
|
||||||
{{formInput systemFields.granted.fields.attackDice value=system.granted.attackDice disabled=isPlayMode }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flexrow granted ">
|
|
||||||
<span class=""><a class="rollable" data-roll-type="granted" data-roll-key="defenseDice"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.grantedDefenseDice"}}</a></span>
|
|
||||||
{{formInput systemFields.granted.fields.defenseDice value=system.granted.defenseDice disabled=isPlayMode }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flexrow granted">
|
|
||||||
<span class=""><a class="rollable" data-roll-type="granted" data-roll-key="damageDice"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.grantedDamageDice"}}</a></span>
|
|
||||||
{{formInput systemFields.granted.fields.damageDice value=system.granted.damageDice disabled=isPlayMode }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.wounds"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.wounds"}}</legend>
|
||||||
<div class="wounds">
|
<div class="wounds">
|
||||||
{{#each system.hp.wounds as |wound idx|}}
|
{{#each system.hp.wounds as |wound idx|}}
|
||||||
<div class="wound">
|
<div class="wound">
|
||||||
Name:<input class="wound-description wound-data" type="text" data-type="String" data-index="{{@index}}" value="{{wound.description}}" data-name="description" >
|
Name:<input class="wound-description wound-data" type="text" data-type="String" data-index="{{@index}}"
|
||||||
Duration:<input class="wound-duration wound-data" type="text" data-type="Number" data-index="{{@index}}" value="{{wound.duration}}" data-name="duration" >
|
value="{{wound.description}}" data-name="description">
|
||||||
HP:<input class="wound-value wound-data" type="text" data-type="Number" data-index="{{@index}}" value="{{wound.value}}" data-name="value" >
|
Duration:<input class="wound-duration wound-data" type="text" data-type="Number" data-index="{{@index}}"
|
||||||
|
value="{{wound.duration}}" data-name="duration">
|
||||||
|
HP:<input class="wound-value wound-data" type="text" data-type="Number" data-index="{{@index}}"
|
||||||
|
value="{{wound.value}}" data-name="value">
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>{{localize "LETHALFANTASY.Label.weapons"}}</legend>
|
|
||||||
<div class="weapons">
|
|
||||||
{{#each weapons as |item|}}
|
|
||||||
<div class="weapon" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"
|
|
||||||
data-drag-type="damage">
|
|
||||||
{{#if (ne item.img "icons/svg/item-bag.svg")}}
|
|
||||||
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
|
||||||
{{/if}}
|
|
||||||
<div class="name">
|
|
||||||
{{item.name}}
|
|
||||||
</div>
|
|
||||||
<div class="attack-icons">
|
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="weapon-attack" data-roll-key="{{item.id}}" data-tooltip="Roll Attack">
|
|
||||||
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="weapon-attack" data-roll-key="{{item.id}}"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="weapon-defense" data-roll-key="{{item.id}}" data-tooltip="Roll Defense">
|
|
||||||
<i class="fa-solid fa-shield-halved" data-roll-type="weapon-defense" data-roll-key="{{item.id}}"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="weapon-damage-small" data-roll-key="{{item.id}}"
|
|
||||||
data-tooltip="Roll Damage (Small)">
|
|
||||||
<i class="fa-regular fa-face-head-bandage" data-roll-type="weapon-damage-small"
|
|
||||||
data-roll-key="{{item.id}}"></i>S
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="weapon-damage-medium" data-roll-key="{{item.id}}"
|
|
||||||
data-tooltip="Roll Damage (Medium)">
|
|
||||||
<i class="fa-regular fa-face-head-bandage" data-roll-type="weapon-damage-medium"
|
|
||||||
data-roll-key="{{item.id}}"></i>M
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.armors"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.weapons"}}</legend>
|
||||||
<div class="armors">
|
<div class="weapons">
|
||||||
{{#each armors as |item|}}
|
{{#each weapons as |item|}}
|
||||||
<div class="armor" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
|
<div class="weapon" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"
|
||||||
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
data-drag-type="damage">
|
||||||
<div class="name" data-tooltip="{{{item.system.description}}}">
|
{{#if (ne item.img "icons/svg/item-bag.svg")}}
|
||||||
{{item.name}}
|
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
||||||
</div>
|
{{/if}}
|
||||||
<div class="item-detail" data-tooltip="Defense">{{item.system.defense}}</div>
|
<div class="name" data-tooltip="{{item.system.description}}">
|
||||||
<div class="item-detail" data-tooltip="Maximum movement">{{item.system.maximumMovement}}</div>
|
{{item.name}}
|
||||||
<div class="item-detail" data-tooltip="HP">{{item.system.hp}}</div>
|
</div>
|
||||||
<div class="item-detail" data-tooltip="Damage Reduction">{{item.system.damageReduction}}</div>
|
<div class="attack-icons">
|
||||||
<div class="controls">
|
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
<a class="rollable" data-roll-type="weapon-attack" data-roll-key="{{item.id}}" data-tooltip="Roll Attack">
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="weapon-attack"
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
data-roll-key="{{item.id}}"></i>
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
</a>
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="weapon-defense" data-roll-key="{{item.id}}" data-tooltip="Roll Defense">
|
||||||
|
<i class="fa-solid fa-shield-halved" data-roll-type="weapon-defense" data-roll-key="{{item.id}}"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="weapon-damage-small" data-roll-key="{{item.id}}"
|
||||||
|
data-tooltip="Roll Damage (Small)">
|
||||||
|
<i class="fa-regular fa-face-head-bandage" data-roll-type="weapon-damage-small"
|
||||||
|
data-roll-key="{{item.id}}"></i>S
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="weapon-damage-medium" data-roll-key="{{item.id}}"
|
||||||
|
data-tooltip="Roll Damage (Medium)">
|
||||||
|
<i class="fa-regular fa-face-head-bandage" data-roll-type="weapon-damage-medium"
|
||||||
|
data-roll-key="{{item.id}}"></i>M
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<a data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
||||||
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.shields"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.armors"}}</legend>
|
||||||
<div class="shields">
|
<div class="armors">
|
||||||
{{#each shields as |item|}}
|
{{#each armors as |item|}}
|
||||||
<div class="shield" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
|
<div class="armor" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
|
||||||
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
||||||
<div class="name" data-tooltip="{{{item.system.description}}}">
|
<div class="name" data-tooltip="{{item.system.description}}">
|
||||||
{{item.name}}
|
{{item.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="item-detail" data-tooltip="Defense">
|
<div class="item-detail" data-tooltip="Defense">{{item.system.defense}}</div>
|
||||||
<a class="rollable" data-roll-type="shield-roll" data-roll-key="{{item.id}}" data-tooltip="Shield Defense">
|
<div class="item-detail" data-tooltip="Maximum movement">{{item.system.maximumMovement}}</div>
|
||||||
<i class="lf-roll-small fa-solid fa-shield" data-roll-type="shield-roll" data-roll-key="{{item.id}}"></i>
|
<div class="item-detail" data-tooltip="HP">{{item.system.hp}}</div>
|
||||||
{{upperFirst item.system.defense}}
|
<div class="item-detail" data-tooltip="Damage Reduction">{{item.system.damageReduction}}</div>
|
||||||
</a>
|
<div class="item-detail" data-tooltip={{#if item.system.equipped}}"Equipped"{{else}}"Not Equipped"{{/if}}>{{#if item.system.equipped}}<i class="fas fa-check"></i>{{else}}<i class="fas fa-times"></i>{{/if}}</div>
|
||||||
|
<div class="controls">
|
||||||
</div>
|
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
||||||
<div class="item-detail" data-tooltip="Movement reduction">{{item.system.movementreduction}}</div>
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
||||||
<div class="item-detail" data-tooltip="Has cover">{{#if item.system.hascover}}Cover{{/if}}</div>
|
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
||||||
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
||||||
<div class="controls">
|
</div>
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>{{localize "LETHALFANTASY.Label.shields"}}</legend>
|
||||||
|
<div class="shields">
|
||||||
|
{{#each shields as |item|}}
|
||||||
|
<div class="shield" 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="item-detail" data-tooltip="Defense">
|
||||||
|
<a class="rollable" data-roll-type="shield-roll" data-roll-key="{{item.id}}" data-tooltip="Shield Defense">
|
||||||
|
<i class="lf-roll-small fa-solid fa-shield" data-roll-type="shield-roll" data-roll-key="{{item.id}}"></i>
|
||||||
|
{{upperFirst item.system.defense}}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="item-detail" data-tooltip="Movement reduction">{{item.system.movementreduction}}</div>
|
||||||
|
<div class="item-detail" data-tooltip="Has cover">{{#if item.system.hascover}}Cover{{/if}}</div>
|
||||||
|
<div class="item-detail" data-tooltip={{#if item.system.equipped}}"Equipped"{{else}}"Not Equipped"{{/if}}>{{#if item.system.equipped}}<i class="fas fa-check"></i>{{else}}<i class="fas fa-times"></i>{{/if}}</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.money"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.money"}}</legend>
|
||||||
@@ -31,5 +32,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
<section class="character-main character-main-{{ifThen isPlayMode 'play' 'edit'}}">
|
<section
|
||||||
|
class="character-main character-main-{{ifThen isPlayMode 'play' 'edit'}}"
|
||||||
|
>
|
||||||
{{log "character-main" this}}
|
{{log "character-main" this}}
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@@ -6,163 +8,333 @@
|
|||||||
<div class="character-pc character-pc-{{ifThen isPlayMode 'play' 'edit'}}">
|
<div class="character-pc character-pc-{{ifThen isPlayMode 'play' 'edit'}}">
|
||||||
<div class="character-left">
|
<div class="character-left">
|
||||||
<div class="character-left-image">
|
<div class="character-left-image">
|
||||||
<img class="character-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
|
<img
|
||||||
data-tooltip="{{actor.name}}" />
|
class="character-img"
|
||||||
|
src="{{actor.img}}"
|
||||||
|
data-edit="img"
|
||||||
|
data-action="editImage"
|
||||||
|
data-tooltip="{{actor.name}}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="">
|
<fieldset class="">
|
||||||
<div class="flexrow character-hp">
|
<div class="flexrow character-hp">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.HP"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.HP"}}</span>
|
||||||
{{formInput systemFields.hp.fields.value value=system.hp.value disabled=isPlayMode classes="character-hp-value"}}
|
{{formInput
|
||||||
|
systemFields.hp.fields.value
|
||||||
|
value=system.hp.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp-value"
|
||||||
|
}}
|
||||||
/
|
/
|
||||||
{{formInput systemFields.hp.fields.max value=system.hp.max disabled=isPlayMode classes="character-hp-value"}}
|
{{formInput
|
||||||
|
systemFields.hp.fields.max
|
||||||
|
value=system.hp.max
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp-value"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="flexrow character-hp">
|
<div class="flexrow character-hp">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.grit"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.grit"}}</span>
|
||||||
{{formInput systemFields.grit.fields.current value=system.grit.current disabled=isPlayMode
|
{{formInput
|
||||||
classes="character-hp"}}
|
systemFields.grit.fields.current
|
||||||
|
value=system.grit.current
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp"
|
||||||
|
}}
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.earned"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.earned"}}</span>
|
||||||
{{formInput systemFields.grit.fields.earned value=system.grit.earned disabled=isPlayMode
|
{{formInput
|
||||||
classes="character-hp"}}
|
systemFields.grit.fields.earned
|
||||||
|
value=system.grit.earned
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="flexrow character-hp">
|
<div class="flexrow character-hp">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.luck"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.luck"}}</span>
|
||||||
{{formInput systemFields.luck.fields.current value=system.luck.current disabled=isPlayMode
|
{{formInput
|
||||||
classes="character-hp"}}
|
systemFields.luck.fields.current
|
||||||
|
value=system.luck.current
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp"
|
||||||
|
}}
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.earned"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.earned"}}</span>
|
||||||
{{formInput systemFields.luck.fields.earned value=system.luck.earned disabled=isPlayMode
|
{{formInput
|
||||||
classes="character-hp"}}
|
systemFields.luck.fields.earned
|
||||||
|
value=system.luck.earned
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="character-hp"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flexrow ">
|
<div class="flexrow">
|
||||||
<span class="">{{localize "LETHALFANTASY.Label.damageResistanceShort"}}</span>
|
<span class="" data-tooltip="Damage reduction">{{localize
|
||||||
{{formInput systemFields.hp.fields.damageResistance value=system.hp.fields.damageResistance disabled=isPlayMode classes="character-hp"}}
|
"LETHALFANTASY.Label.damageResistanceShort"
|
||||||
</div>
|
}}
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="character-damage-reduction"
|
||||||
|
data-tooltip="DR (armor+natural+magical)"
|
||||||
|
disabled
|
||||||
|
value={{damageReduction}}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="character-damage-reduction"
|
||||||
|
data-tooltip="DR (shield)"
|
||||||
|
disabled
|
||||||
|
value={{damageReductionShield}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="character-right">
|
<div class="character-right">
|
||||||
<div class="character-name">
|
<div class="character-name">
|
||||||
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
|
{{formInput
|
||||||
<a class="control" data-action="toggleSheet" data-tooltip="LETHALFANTASY.ToggleSheet"
|
fields.name
|
||||||
data-tooltip-direction="UP">
|
value=source.name
|
||||||
|
rootId=partId
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<a
|
||||||
|
class="control"
|
||||||
|
data-action="toggleSheet"
|
||||||
|
data-tooltip="LETHALFANTASY.ToggleSheet"
|
||||||
|
data-tooltip-direction="UP"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
|
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="character-characteristics character-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="character-characteristics character-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.Saves"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.Saves"}}</legend>
|
||||||
<div class="character-saves">
|
<div class="character-saves">
|
||||||
<div class="character-save">
|
<div class="character-save">
|
||||||
<span class="name"><a class="rollable" data-roll-type="save" data-roll-key="will"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="will"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.will"}}
|
{{localize "LETHALFANTASY.Label.saves.will"}}
|
||||||
</a></span>
|
</a></span>
|
||||||
{{formField systemFields.saves.fields.will.fields.value value=system.saves.will.value disabled=true}}
|
{{formField
|
||||||
|
systemFields.saves.fields.will.fields.value
|
||||||
|
value=system.saves.will.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="dodge"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="dodge"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.dodge"}}
|
{{localize "LETHALFANTASY.Label.saves.dodge"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.dodge.fields.value value=system.saves.dodge.value
|
{{formField
|
||||||
disabled=true}}
|
systemFields.saves.fields.dodge.fields.value
|
||||||
|
value=system.saves.dodge.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="toughness"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="toughness"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.toughness"}}
|
{{localize "LETHALFANTASY.Label.saves.toughness"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.toughness.fields.value value=system.saves.toughness.value
|
{{formField
|
||||||
disabled=true}}
|
systemFields.saves.fields.toughness.fields.value
|
||||||
|
value=system.saves.toughness.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-save">
|
<div class="character-save">
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="contagion"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="contagion"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.contagion"}}
|
{{localize "LETHALFANTASY.Label.saves.contagion"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.contagion.fields.value value=system.saves.contagion.value
|
{{formField
|
||||||
disabled=true}}
|
systemFields.saves.fields.contagion.fields.value
|
||||||
|
value=system.saves.contagion.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
|
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="poison"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
{{localize "LETHALFANTASY.Label.saves.poison"}}
|
data-roll-type="save"
|
||||||
|
data-roll-key="poison"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
|
{{localize "LETHALFANTASY.Label.saves.poison"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.poison.fields.value value=system.saves.poison.value
|
{{formField
|
||||||
disabled=true }}
|
systemFields.saves.fields.poison.fields.value
|
||||||
|
value=system.saves.poison.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
|
|
||||||
|
<!--
|
||||||
<span class="name-pain">
|
<span class="name-pain">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="pain" data-roll-dice="D12"><i
|
<a class="rollable" data-roll-type="save" data-roll-key="pain" data-roll-dice="D12"><i
|
||||||
class="lf-roll-small fa-solid fa-dice-d12"></i>
|
class="lf-roll-small fa-solid fa-dice-d12"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.pain"}}
|
{{localize "LETHALFANTASY.Label.saves.pain"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span class="name-pain">
|
<span class="name-pain">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="pain" data-roll-dice="D20"><i
|
<a class="rollable" data-roll-type="save" data-roll-key="pain" data-roll-dice="D20"><i
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.pain"}}
|
{{localize "LETHALFANTASY.Label.saves.pain"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.pain.fields.value value=system.saves.pain.value disabled=true}}
|
{{formField systemFields.saves.fields.pain.fields.value value=system.saves.pain.value disabled=true}}
|
||||||
|
|
||||||
<span data-tooltip="Pain save if wound exceeds">
|
<span data-tooltip="Pain save if wound exceeds">
|
||||||
{{formField systemFields.hp.fields.painDamage value=system.hp.painDamage disabled=isPlayMode tooltip="Pain Damage"}}
|
{{formField systemFields.hp.fields.painDamage value=system.hp.painDamage disabled=isPlayMode
|
||||||
|
tooltip="Pain Damage"}}
|
||||||
</span>
|
</span>
|
||||||
|
-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="character-characteristics character-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="character-characteristics character-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.Challenges"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.Challenges"}}</legend>
|
||||||
<div class="character-challenges">
|
<div class="character-challenges">
|
||||||
<div class="character-challenge">
|
<div class="character-challenge">
|
||||||
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="str"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
class="rollable"
|
||||||
"LETHALFANTASY.Label.challenges.strength"}}</a></span>
|
data-roll-type="challenge"
|
||||||
{{formField systemFields.challenges.fields.str.fields.value value=system.challenges.str.value
|
data-roll-key="str"
|
||||||
disabled=true
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.challenges.strength"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.challenges.fields.str.fields.value
|
||||||
|
value=system.challenges.str.value
|
||||||
|
disabled=true
|
||||||
}}
|
}}
|
||||||
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="agility"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
class="rollable"
|
||||||
"LETHALFANTASY.Label.challenges.agility"}}</a></span>
|
data-roll-type="challenge"
|
||||||
{{formField systemFields.challenges.fields.agility.fields.value value=system.challenges.agility.value
|
data-roll-key="agility"
|
||||||
disabled=true
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.challenges.agility"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.challenges.fields.agility.fields.value
|
||||||
|
value=system.challenges.agility.value
|
||||||
|
disabled=true
|
||||||
|
}}
|
||||||
|
<span class="name"><a
|
||||||
|
class="rollable"
|
||||||
|
data-roll-type="challenge"
|
||||||
|
data-roll-key="dying"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.challenges.dying"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.challenges.fields.dying.fields.value
|
||||||
|
value=system.challenges.dying.value
|
||||||
|
disabled=true
|
||||||
}}
|
}}
|
||||||
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="dying"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
|
||||||
"LETHALFANTASY.Label.challenges.dying"}}</a></span>
|
|
||||||
{{formField systemFields.challenges.fields.dying.fields.value value=system.challenges.dying.value
|
|
||||||
disabled=true }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="character-characteristics character-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="character-characteristics character-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.Movement"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.Movement"}}</legend>
|
||||||
<div class="character-movements">
|
<div class="character-movements">
|
||||||
<div class="character-movement">
|
<div class="character-movement">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.walk"}}</span>
|
<span class="name">{{localize
|
||||||
{{formField systemFields.movement.fields.walk value=system.movement.walk disabled=isPlayMode}}
|
"LETHALFANTASY.Label.movement.walk"
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.jog"}}</span>
|
}}</span>
|
||||||
{{formField systemFields.movement.fields.jog value=system.movement.jog disabled=isPlayMode}}
|
{{formField
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.run"}}</span>
|
systemFields.movement.fields.walk
|
||||||
{{formField systemFields.movement.fields.run value=system.movement.run disabled=isPlayMode}}
|
value=system.movement.walk
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.sprint"}}</span>
|
disabled=isPlayMode
|
||||||
{{formField systemFields.movement.fields.sprint value=system.movement.sprint disabled=isPlayMode}}
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.jog"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.jog
|
||||||
|
value=system.movement.jog
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.run"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.run
|
||||||
|
value=system.movement.run
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.sprint"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.sprint
|
||||||
|
value=system.movement.sprint
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-movement">
|
<div class="character-movement">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.jumpBroad"}}</span>
|
<span class="name">{{localize
|
||||||
{{formField systemFields.jump.fields.broad value=system.jump.broad disabled=isPlayMode}}
|
"LETHALFANTASY.Label.movement.jumpBroad"
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.jumpRunning"}}</span>
|
}}</span>
|
||||||
{{formField systemFields.jump.fields.running value=system.jump.running disabled=isPlayMode}}
|
{{formField
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.jumpVertical"}}</span>
|
systemFields.jump.fields.broad
|
||||||
{{formField systemFields.jump.fields.vertical value=system.jump.vertical disabled=isPlayMode}}
|
value=system.jump.broad
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.jumpRunning"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.jump.fields.running
|
||||||
|
value=system.jump.running
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.jumpVertical"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.jump.fields.vertical
|
||||||
|
value=system.jump.vertical
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -171,70 +343,124 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="character-characteristics character-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="character-characteristics character-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.characteristics"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.characteristics"}}</legend>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.str"}}
|
<span>{{localize "LETHALFANTASY.Label.str"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="str" }}
|
systemFields.characteristics.fields.str.fields.value
|
||||||
{{formField systemFields.characteristics.fields.str.fields.percent value=system.characteristics.str.percent
|
value=system.characteristics.str.value
|
||||||
disabled=isPlayMode type="number"}}
|
disabled=isPlayMode
|
||||||
|
data-char-id="str"
|
||||||
|
}}
|
||||||
|
{{formField
|
||||||
|
systemFields.characteristics.fields.str.fields.percent
|
||||||
|
value=system.characteristics.str.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.int"}}
|
<span>{{localize "LETHALFANTASY.Label.int"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="int" }}
|
systemFields.characteristics.fields.int.fields.value
|
||||||
|
value=system.characteristics.int.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="int"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.int.fields.percent value=system.characteristics.int.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number" }}
|
systemFields.characteristics.fields.int.fields.percent
|
||||||
|
value=system.characteristics.int.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.wis"}}
|
<span>{{localize "LETHALFANTASY.Label.wis"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.wis.fields.value value=system.characteristics.wis.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="wis" }}
|
systemFields.characteristics.fields.wis.fields.value
|
||||||
|
value=system.characteristics.wis.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="wis"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.wis.fields.percent value=system.characteristics.wis.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number"}}
|
systemFields.characteristics.fields.wis.fields.percent
|
||||||
|
value=system.characteristics.wis.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.dex"}}
|
<span>{{localize "LETHALFANTASY.Label.dex"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="wis" }}
|
systemFields.characteristics.fields.dex.fields.value
|
||||||
|
value=system.characteristics.dex.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="wis"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.dex.fields.percent value=system.characteristics.dex.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number" }}
|
systemFields.characteristics.fields.dex.fields.percent
|
||||||
|
value=system.characteristics.dex.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.con"}}
|
<span>{{localize "LETHALFANTASY.Label.con"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="con" }}
|
systemFields.characteristics.fields.con.fields.value
|
||||||
|
value=system.characteristics.con.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="con"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.con.fields.percent value=system.characteristics.con.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number"}}
|
systemFields.characteristics.fields.con.fields.percent
|
||||||
|
value=system.characteristics.con.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.cha"}}
|
<span>{{localize "LETHALFANTASY.Label.cha"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.cha.fields.value value=system.characteristics.cha.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="cha" }}
|
systemFields.characteristics.fields.cha.fields.value
|
||||||
|
value=system.characteristics.cha.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="cha"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.cha.fields.percent value=system.characteristics.cha.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number"}}
|
systemFields.characteristics.fields.cha.fields.percent
|
||||||
|
value=system.characteristics.cha.percent
|
||||||
|
disabled=isPlayMode
|
||||||
|
type="number"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="character-characteristic">
|
<div class="character-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.luc"}}
|
<span>{{localize "LETHALFANTASY.Label.luc"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.luc.fields.value value=system.characteristics.luc.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="luc" }}
|
systemFields.characteristics.fields.luc.fields.value
|
||||||
|
value=system.characteristics.luc.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="luc"
|
||||||
|
}}
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.luc.fields.percent value=system.characteristics.luc.percent
|
{{formField
|
||||||
disabled=isPlayMode type="number"}}
|
systemFields.characteristics.fields.luc.fields.percent
|
||||||
</div>
|
value=system.characteristics.luc.percent
|
||||||
<div class="character-characteristic">
|
disabled=isPlayMode
|
||||||
{{localize "LETHALFANTASY.Label.app"}}
|
type="number"
|
||||||
{{formField systemFields.characteristics.fields.app.fields.value value=system.characteristics.app.value
|
}}
|
||||||
disabled=isPlayMode data-char-id="app" }}
|
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.app.fields.percent value=system.characteristics.app.percent
|
|
||||||
disabled=isPlayMode type="number"}}
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +1,52 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.divinityPoints"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.divinityPoints"}}</legend>
|
||||||
<div class="miracle-details">
|
<div class="miracle-details">
|
||||||
<div class="miracle-detail">
|
<div class="miracle-detail">
|
||||||
<span >Current</span>
|
<span>Current</span>
|
||||||
{{formField systemFields.divinityPoints.fields.value value=system.divinityPoints.value localize=true}}
|
{{formField systemFields.divinityPoints.fields.value value=system.divinityPoints.value localize=true}}
|
||||||
<a data-action="divinityPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
<a data-action="divinityPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
||||||
<a data-action="divinityPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
<a data-action="divinityPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
||||||
|
|
||||||
<span >Max</span>
|
<span>Max</span>
|
||||||
{{formField systemFields.divinityPoints.fields.max value=system.divinityPoints.max localize=true disabled=isPlayMode}}
|
{{formField systemFields.divinityPoints.fields.max value=system.divinityPoints.max localize=true
|
||||||
|
disabled=isPlayMode}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.miracles"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "
|
<legend>{{localize "LETHALFANTASY.Label.miracles"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "
|
||||||
LETHALFANTASY.Tooltip.addMiracle"}}" data-tooltip-direction="UP"><i class="fas fa-plus"
|
LETHALFANTASY.Tooltip.addMiracle"}}" data-tooltip-direction="UP"><i class="fas fa-plus"
|
||||||
data-action="createMiracle"></i></a>{{/if}}</legend>
|
data-action="createMiracle"></i></a>{{/if}}</legend>
|
||||||
<div class="miracles">
|
<div class="miracles">
|
||||||
{{#each miracles as |item|}}
|
{{#each miracles as |item|}}
|
||||||
<div class="miracle" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true" >
|
<div class="miracle" 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 class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
||||||
<div class="name" >
|
<div class="name">
|
||||||
{{item.name}}
|
{{item.name}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="miracle-attack" data-roll-key="{{item.id}}" data-tooltip="Miracle Attack">
|
<a class="rollable" data-roll-type="miracle-attack" data-roll-key="{{item.id}}" data-tooltip="Miracle Attack">
|
||||||
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="miracle-attack" data-roll-key="{{item.id}}"></i>
|
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="miracle-attack" data-roll-key="{{item.id}}"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="miracle-power" data-roll-key="{{item.id}}" data-tooltip="Miracle Power">
|
<a class="rollable" data-roll-type="miracle-power" data-roll-key="{{item.id}}" data-tooltip="Miracle Power">
|
||||||
<i class="fa-duotone fa-solid fa-stars" data-roll-type="miracle-power" data-roll-key="{{item.id}}"></i>
|
<i class="fa-duotone fa-solid fa-stars" data-roll-type="miracle-power" data-roll-key="{{item.id}}"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
@@ -1,72 +1,145 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section
|
||||||
|
class="tab character-{{tab.id}} {{tab.cssClass}}"
|
||||||
|
data-tab="skills"
|
||||||
|
data-group="sheet"
|
||||||
|
>
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
{{#each skillsByCategory as |categoryData|}}
|
||||||
<legend data-tooltip="{{localize " LETHALFANTASY.Tooltip.skills"}}" data-tooltip-direction="UP">{{localize
|
<fieldset>
|
||||||
"LETHALFANTASY.Label.skills"}}</legend>
|
<legend
|
||||||
<div class="skills">
|
data-tooltip="{{localize ' LETHALFANTASY.Tooltip.skills'}}"
|
||||||
{{#each skills as |item|}}
|
data-tooltip-direction="UP"
|
||||||
<div class="skill " data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
|
>{{localize categoryData.label}}</legend>
|
||||||
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
<div class="skills">
|
||||||
<div class="name">
|
{{#each categoryData.skills as |item|}}
|
||||||
<a class="rollable" data-roll-type="skill" data-roll-key="{{item.id}}">
|
<div
|
||||||
<i class="lf-roll-small fa-duotone fa-solid fa-dice-d10"></i>
|
class="skill"
|
||||||
{{item.name}}
|
data-item-id="{{item.id}}"
|
||||||
</a>
|
data-item-uuid="{{item.uuid}}"
|
||||||
</div>
|
>
|
||||||
<div class="score">
|
<img
|
||||||
+{{item.system.skillTotal}}
|
class="item-img"
|
||||||
</div>
|
src="{{item.img}}"
|
||||||
<div class="controls">
|
data-tooltip="{{item.name}}"
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
/>
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
<div class="name">
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
<a
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
class="rollable"
|
||||||
|
data-roll-type="skill"
|
||||||
|
data-roll-key="{{item.id}}"
|
||||||
|
>
|
||||||
|
<i class="lf-roll-small fa-duotone fa-solid fa-dice-d10"></i>
|
||||||
|
{{item.name}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="score">
|
||||||
|
+{{item.system.skillTotal}}
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a
|
||||||
|
data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend
|
||||||
|
data-tooltip="{{localize ' LETHALFANTASY.Tooltip.gifts'}}"
|
||||||
|
data-tooltip-direction="UP"
|
||||||
|
>{{localize "LETHALFANTASY.Label.gifts"}}</legend>
|
||||||
|
<div class="gifts">
|
||||||
|
{{#each gifts as |item|}}
|
||||||
|
<div
|
||||||
|
class="gift"
|
||||||
|
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.description}}}<br><br>{{item.path}}"
|
||||||
|
data-tooltip-direction="UP"
|
||||||
|
>
|
||||||
|
{{item.name}}
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a
|
||||||
|
data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend data-tooltip="{{localize " LETHALFANTASY.Tooltip.gifts"}}" data-tooltip-direction="UP">{{localize
|
<legend
|
||||||
"LETHALFANTASY.Label.gifts"}}</legend>
|
data-tooltip="{{localize ' LETHALFANTASY.Tooltip.vulnerabilities'}}"
|
||||||
<div class="gifts">
|
data-tooltip-direction="UP"
|
||||||
{{#each gifts as |item|}}
|
>{{localize "LETHALFANTASY.Label.vulnerabilities"}}</legend>
|
||||||
<div class="gift " data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
|
<div class="vulnerabilities">
|
||||||
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
{{#each vulnerabilities as |item|}}
|
||||||
<div class="name" data-tooltip="{{{item.description}}}<br><br>{{item.path}}" data-tooltip-direction="UP">
|
<div
|
||||||
{{item.name}}
|
class="vulnerability"
|
||||||
</div>
|
data-item-id="{{item.id}}"
|
||||||
<div class="controls">
|
data-item-uuid="{{item.uuid}}"
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
>
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
<img
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
class="item-img"
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
src="{{item.img}}"
|
||||||
</div>
|
data-tooltip="{{item.name}}"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="name"
|
||||||
|
data-tooltip="{{{item.description}}}<br><br>{{item.path}}"
|
||||||
|
data-tooltip-direction="UP"
|
||||||
|
>
|
||||||
|
{{item.name}}
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<a
|
||||||
|
data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend data-tooltip="{{localize " LETHALFANTASY.Tooltip.vulnerabilities"}}" data-tooltip-direction="UP">{{localize
|
|
||||||
"LETHALFANTASY.Label.vulnerabilities"}}</legend>
|
|
||||||
<div class="vulnerabilities">
|
|
||||||
{{#each vulnerabilities as |item|}}
|
|
||||||
<div class="vulnerability " 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.description}}}<br><br>{{item.path}}" data-tooltip-direction="UP">
|
|
||||||
{{item.name}}
|
|
||||||
</div>
|
|
||||||
<div class="controls">
|
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.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 'LETHALFANTASY.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>
|
</section>
|
||||||
@@ -1,50 +1,51 @@
|
|||||||
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
|
||||||
|
<div class="main-div">
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.aetherPoints"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.aetherPoints"}}</legend>
|
||||||
<div class="spell-details">
|
<div class="spell-details">
|
||||||
<div class="spell-detail">
|
<div class="spell-detail">
|
||||||
<span >Current</span>
|
<span>Current</span>
|
||||||
{{formField systemFields.aetherPoints.fields.value value=system.aetherPoints.value localize=true}}
|
{{formField systemFields.aetherPoints.fields.value value=system.aetherPoints.value localize=true}}
|
||||||
<a data-action="aetherPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
<a data-action="aetherPointsPlus"><i class="fa-solid fa-hexagon-plus"></i></a>
|
||||||
<a data-action="aetherPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
<a data-action="aetherPointsMinus"><i class="fa-solid fa-hexagon-minus"></i></a>
|
||||||
|
|
||||||
<span >Max</span>
|
<span>Max</span>
|
||||||
{{formField systemFields.aetherPoints.fields.max value=system.aetherPoints.max localize=true disabled=isPlayMode}}
|
{{formField systemFields.aetherPoints.fields.max value=system.aetherPoints.max localize=true
|
||||||
|
disabled=isPlayMode}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.spells"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "
|
<legend>{{localize "LETHALFANTASY.Label.spells"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "
|
||||||
LETHALFANTASY.Tooltip.addSpell"}}" data-tooltip-direction="UP"><i class="fas fa-plus"
|
LETHALFANTASY.Tooltip.addSpell"}}" data-tooltip-direction="UP"><i class="fas fa-plus"
|
||||||
data-action="createSpell"></i></a>{{/if}}</legend>
|
data-action="createSpell"></i></a>{{/if}}</legend>
|
||||||
<div class="spells">
|
<div class="spells">
|
||||||
{{#each spells as |item|}}
|
{{#each spells as |item|}}
|
||||||
<div class="spell" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true" >
|
<div class="spell" 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 class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
|
||||||
<div class="name" >
|
<div class="name">
|
||||||
{{item.name}}
|
{{item.name}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="spell-attack" data-roll-key="{{item.id}}" data-tooltip="Spell Attack">
|
<a class="rollable" data-roll-type="spell-attack" data-roll-key="{{item.id}}" data-tooltip="Spell Attack">
|
||||||
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="spell-attack" data-roll-key="{{item.id}}"></i>
|
<i class="lf-roll-small fa-solid fa-swords" data-roll-type="spell-attack" data-roll-key="{{item.id}}"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="rollable" data-roll-type="spell-power" data-roll-key="{{item.id}}" data-tooltip="Spell Power">
|
<a class="rollable" data-roll-type="spell-power" data-roll-key="{{item.id}}" data-tooltip="Spell Power">
|
||||||
<i class="fa-duotone fa-solid fa-stars" data-roll-type="spell-power" data-roll-key="{{item.id}}"></i>
|
<i class="fa-duotone fa-solid fa-stars" data-roll-type="spell-power" data-roll-key="{{item.id}}"></i>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
|
||||||
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
|
||||||
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
@@ -1,72 +1,291 @@
|
|||||||
{{!log 'chat-message' this}}
|
{{!log 'chat-message' this}}
|
||||||
|
{{!log 'weaponDamageOptions' weaponDamageOptions}}
|
||||||
<div class="{{cssClass}}">
|
<div class="{{cssClass}}">
|
||||||
<div class="intro-chat">
|
<!-- Header with character info -->
|
||||||
<div class="intro-img">
|
<div class="chat-header">
|
||||||
<img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" />
|
<div class="character-info">
|
||||||
</div>
|
<div class="character-avatar">
|
||||||
|
<img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" />
|
||||||
<div class="intro-right">
|
</div>
|
||||||
<span>{{upperFirst rollName}}</span>
|
<div class="character-details">
|
||||||
|
<div class="character-name">{{actingCharName}}</div>
|
||||||
{{#if (match rollType "attack")}}
|
<div class="roll-type-badge">
|
||||||
<span>Attack roll !</span>
|
{{#if (match rollType "attack")}}
|
||||||
{{/if}}
|
<i class="fa-solid fa-swords"></i>
|
||||||
{{#if (match rollType "defense")}}
|
{{/if}}
|
||||||
<span>Defense roll !</span>
|
{{#if (match rollType "defense")}}
|
||||||
{{/if}}
|
<i class="fa-solid fa-shield"></i>
|
||||||
|
{{/if}}
|
||||||
{{#if badResult}}
|
{{#if rollData.isDamage}}
|
||||||
<span>{{localize "LETHALFANTASY.Label.otherResult"}} : {{badResult}}</span>
|
<i class="fa-solid fa-burst"></i>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if (eq rollType "skill")}}
|
||||||
{{#if rollTarget.weapon}}
|
<i class="fa-solid fa-hand-sparkles"></i>
|
||||||
<span>{{rollTarget.weapon.name}}</span>
|
{{/if}}
|
||||||
{{/if}}
|
{{upperFirst rollName}}
|
||||||
|
</div>
|
||||||
<span>Formula : {{titleFormula}}</span>
|
</div>
|
||||||
|
|
||||||
{{#each diceResults as |result|}}
|
|
||||||
<span>{{result.dice}} : {{result.value}}</span>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if isSave}}
|
|
||||||
<div class="result">
|
|
||||||
{{#if (eq resultType "success")}}
|
|
||||||
{{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.success"}}{{/if}}
|
|
||||||
{{else}}
|
|
||||||
{{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.failure"}}{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{#if isResource}}
|
|
||||||
<div class="result">
|
|
||||||
{{#if (eq resultType "success")}}
|
|
||||||
{{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.success"}}{{/if}}
|
|
||||||
{{else}}
|
|
||||||
{{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.failure"}}{{#if isFailure}} ({{localize
|
|
||||||
"LETHALFANTASY.Roll.resourceLost"}}){{/if}}{{/if}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{#if isDamage}}
|
|
||||||
<div>
|
|
||||||
{{#if (and isGM hasTarget)}}
|
|
||||||
{{{localize "LETHALFANTASY.Roll.displayArmor" targetName=targetName targetArmor=targetArmor realDamage=realDamage}}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
|
<!-- Roll details and modifiers -->
|
||||||
|
<div class="roll-details">
|
||||||
|
{{#if rollTarget.weapon}}
|
||||||
|
<div class="detail-item weapon-name">
|
||||||
|
<i class="fa-solid fa-sword"></i>
|
||||||
|
<span>{{rollTarget.weapon.name}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if (eq rollData.favor "favor")}}
|
||||||
|
<div class="detail-badge favor-badge">
|
||||||
|
<i class="fa-solid fa-sparkles"></i>
|
||||||
|
<span>Favor</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if (eq rollData.favor "disfavor")}}
|
||||||
|
<div class="detail-badge disfavor-badge">
|
||||||
|
<i class="fa-solid fa-skull"></i>
|
||||||
|
<span>Disfavor</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if rollData.letItFly}}
|
||||||
|
<div class="detail-badge special-badge">
|
||||||
|
<i class="fa-solid fa-bow-arrow"></i>
|
||||||
|
<span>Let It Fly!</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if rollData.pointBlank}}
|
||||||
|
<div class="detail-badge special-badge">
|
||||||
|
<i class="fa-solid fa-bullseye-arrow"></i>
|
||||||
|
<span>Point Blank</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if rollData.beyondSkill}}
|
||||||
|
<div class="detail-badge special-badge">
|
||||||
|
<i class="fa-solid fa-target-lock"></i>
|
||||||
|
<span>Beyond Skill</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if rollData.damageSmall}}
|
||||||
|
<div class="detail-badge damage-badge">
|
||||||
|
<i class="fa-solid fa-dice-d6"></i>
|
||||||
|
<span>{{localize "LETHALFANTASY.Label.weapon-damage-small"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if rollData.damageMedium}}
|
||||||
|
<div class="detail-badge damage-badge">
|
||||||
|
<i class="fa-solid fa-dice-d20"></i>
|
||||||
|
<span>{{localize "LETHALFANTASY.Label.weapon-damage-medium"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if badResult}}
|
||||||
|
<div class="detail-item other-result">
|
||||||
|
<strong>{{localize "LETHALFANTASY.Label.otherResult"}}</strong>: {{badResult}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Formula and dice results -->
|
||||||
|
<div class="formula-section">
|
||||||
|
<div class="formula-display">
|
||||||
|
<i class="fa-solid fa-dice-d20"></i>
|
||||||
|
<span class="formula-text">{{titleFormula}}</span>
|
||||||
|
</div>
|
||||||
|
{{#if diceResults}}
|
||||||
|
<div class="dice-breakdown">
|
||||||
|
{{#each diceResults as |result|}}
|
||||||
|
<div class="dice-item">
|
||||||
|
<span class="dice-type">{{result.dice}}</span>
|
||||||
|
<span class="dice-separator">→</span>
|
||||||
|
<span class="dice-value">{{result.value}}</span>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<!-- Result section -->
|
||||||
{{#unless isPrivate}}
|
{{#unless isPrivate}}
|
||||||
<div class="dice-result">
|
<div class="result-section">
|
||||||
<h4 class="dice-total">{{total}}</h4>
|
<div class="main-result">
|
||||||
</div>
|
<div class="result-label">Total</div>
|
||||||
{{#if D30result}}
|
<div class="result-value {{#if (eq resultType 'success')}}success{{else}}failure{{/if}}">
|
||||||
<div class="dice-result">
|
{{total}}
|
||||||
<h4 class="dice-total">D30 result: {{D30result}}</h4>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if D30result}}
|
||||||
|
<div class="d30-result">
|
||||||
|
<div class="d30-header">
|
||||||
|
<i class="fa-solid fa-dice-d20"></i>
|
||||||
|
<span class="d30-label">D30 Special</span>
|
||||||
|
<span class="d30-value">{{D30result}}</span>
|
||||||
|
</div>
|
||||||
|
{{#if D30message}}
|
||||||
|
<div class="d30-message">
|
||||||
|
<i class="fa-solid fa-wand-magic-sparkles"></i>
|
||||||
|
<span>{{D30message}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if isSave}}
|
||||||
|
<div class="outcome-badge {{#if (eq resultType 'success')}}success-outcome{{else}}failure-outcome{{/if}}">
|
||||||
|
{{#if (eq resultType "success")}}
|
||||||
|
<i class="fa-solid fa-circle-check"></i>
|
||||||
|
{{localize "LETHALFANTASY.Roll.success"}}
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-circle-xmark"></i>
|
||||||
|
{{localize "LETHALFANTASY.Roll.failure"}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isResource}}
|
||||||
|
<div class="outcome-badge {{#if (eq resultType 'success')}}success-outcome{{else}}failure-outcome{{/if}}">
|
||||||
|
{{#if (eq resultType "success")}}
|
||||||
|
<i class="fa-solid fa-circle-check"></i>
|
||||||
|
{{localize "LETHALFANTASY.Roll.success"}}
|
||||||
|
{{else}}
|
||||||
|
<i class="fa-solid fa-circle-xmark"></i>
|
||||||
|
{{localize "LETHALFANTASY.Roll.failure"}}
|
||||||
|
{{#if isFailure}}
|
||||||
|
<span class="resource-lost">({{localize "LETHALFANTASY.Roll.resourceLost"}})</span>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isDamage}}
|
||||||
|
{{#if (and isGM hasTarget)}}
|
||||||
|
<div class="target-info">
|
||||||
|
<i class="fa-solid fa-crosshairs"></i>
|
||||||
|
{{{localize
|
||||||
|
"LETHALFANTASY.Roll.displayArmor"
|
||||||
|
targetName=targetName
|
||||||
|
targetArmor=targetArmor
|
||||||
|
realDamage=realDamage
|
||||||
|
}}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
<div class="private-result">
|
||||||
|
<i class="fa-solid fa-eye-slash"></i>
|
||||||
|
<span>Private Roll</span>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
{{#if weaponDamageOptions}}
|
||||||
|
{{#if canSelectTarget}}
|
||||||
|
<div class="damage-buttons">
|
||||||
|
<div class="damage-buttons-grid {{#if weaponDamageOptions.isMonster}}monster-damage{{/if}}">
|
||||||
|
{{#if weaponDamageOptions.isMonster}}
|
||||||
|
<button
|
||||||
|
class="damage-roll-btn"
|
||||||
|
data-weapon-id="{{weaponDamageOptions.weaponId}}"
|
||||||
|
data-damage-type="monster"
|
||||||
|
data-damage-formula="{{weaponDamageOptions.damageFormula}}"
|
||||||
|
data-damage-modifier="{{weaponDamageOptions.damageModifier}}"
|
||||||
|
data-is-monster="true"
|
||||||
|
title="{{localize 'LETHALFANTASY.Label.rollDamage'}} - {{weaponDamageOptions.weaponName}}"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-dice"></i>
|
||||||
|
Damage:
|
||||||
|
{{weaponDamageOptions.damageFormula}}{{#if
|
||||||
|
weaponDamageOptions.damageModifier
|
||||||
|
}}+{{weaponDamageOptions.damageModifier}}{{/if}}
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
{{#if weaponDamageOptions.damageS}}
|
||||||
|
<button
|
||||||
|
class="damage-roll-btn"
|
||||||
|
data-weapon-id="{{weaponDamageOptions.weaponId}}"
|
||||||
|
data-damage-type="small"
|
||||||
|
data-damage-formula="{{weaponDamageOptions.damageS}}"
|
||||||
|
data-is-monster="false"
|
||||||
|
title="{{localize 'LETHALFANTASY.Label.rollDamage'}}"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-dice-d6"></i>
|
||||||
|
Damage Small
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
{{#if weaponDamageOptions.damageM}}
|
||||||
|
<button
|
||||||
|
class="damage-roll-btn"
|
||||||
|
data-weapon-id="{{weaponDamageOptions.weaponId}}"
|
||||||
|
data-damage-type="medium"
|
||||||
|
data-damage-formula="{{weaponDamageOptions.damageM}}"
|
||||||
|
data-is-monster="false"
|
||||||
|
title="{{localize 'LETHALFANTASY.Label.rollDamage'}}"
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-dice-d20"></i>
|
||||||
|
Damage Medium
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if rollData.isDamage}}
|
||||||
|
{{#if defenderId}}
|
||||||
|
<div class="damage-result auto-applied">
|
||||||
|
<div class="auto-damage-notice">
|
||||||
|
<i class="fa-solid fa-check-circle"></i>
|
||||||
|
<span>Damage automatically applied to defender (with Armor DR)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="damage-result">
|
||||||
|
<ul>
|
||||||
|
<li class="li-apply-wounds">
|
||||||
|
<div>{{localize "LETHALFANTASY.Label.applyDamage"}}</div>
|
||||||
|
<div class="combatants-grid">
|
||||||
|
{{#each combatants}}
|
||||||
|
<button
|
||||||
|
class="apply-wounds-btn"
|
||||||
|
data-combatant-id="{{this.id}}"
|
||||||
|
title="{{this.name}}"
|
||||||
|
>
|
||||||
|
{{this.name}}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isAttack}}
|
||||||
|
{{#if canSelectTarget}}
|
||||||
|
<div class="attack-targets">
|
||||||
|
<ul>
|
||||||
|
<li class="li-select-target">
|
||||||
|
<div>{{localize "LETHALFANTASY.Label.selectTarget"}}</div>
|
||||||
|
<div class="combatants-grid">
|
||||||
|
{{#each combatants}}
|
||||||
|
<button
|
||||||
|
class="request-defense-btn"
|
||||||
|
data-combatant-id="{{this.id}}"
|
||||||
|
data-token-id="{{this.tokenId}}"
|
||||||
|
title="{{this.name}}"
|
||||||
|
>
|
||||||
|
{{this.name}}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{/unless}}
|
|
||||||
</div>
|
</div>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
<fieldSet>
|
<fieldSet>
|
||||||
<legend>{{localize "LETHALFANTASY.Roll.visibility"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Roll.visibility"}}</legend>
|
||||||
<select name="visibility">
|
<select name="visibility">
|
||||||
{{selectOptions rollModes selected=visibility}}
|
{{selectOptions rollModes selected=visibility localize=true}}
|
||||||
</select>
|
</select>
|
||||||
</fieldSet>
|
</fieldSet>
|
||||||
|
|
||||||
|
|||||||
39
templates/combat-tracker-footer-v2.hbs
Normal file
39
templates/combat-tracker-footer-v2.hbs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<nav class="combat-controls" data-tooltip-direction="UP">
|
||||||
|
{{~#if hasCombat~}}
|
||||||
|
|
||||||
|
{{!-- GM Controls --}}
|
||||||
|
{{#if user.isGM}}
|
||||||
|
{{#if combat.round}}
|
||||||
|
<!-- <button type="button" class="inline-control combat-control icon fa-solid fa-backward-step"
|
||||||
|
data-action="previousRound" data-tooltip aria-label="{{ localize "COMBAT.RoundPrev" }}"></button>
|
||||||
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-left" data-action="previousTurn"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.TurnPrev" }}"></button> -->
|
||||||
|
<button type="button" class="combat-control combat-control-lg" data-action="endCombat">
|
||||||
|
<i class="fa-solid fa-xmark" inert></i>
|
||||||
|
<span>{{ localize "COMBAT.End" }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- <button type="button" class="inline-control combat-control icon fa-solid fa-arrow-right" data-action="nextTurn"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.TurnNext" }}"></button> -->
|
||||||
|
<button type="button" class="inline-control combat-control icon fa-solid fa-forward-step" data-action="nextRound"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.RoundNext" }}"></button>
|
||||||
|
{{else}}
|
||||||
|
<button type="button" class="combat-control combat-control-lg" data-action="startCombat">
|
||||||
|
<i class="fa-solid fa-swords" inert></i>
|
||||||
|
<span>{{ localize "COMBAT.Begin" }}</span>
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Active Player Controls --}}
|
||||||
|
{{else if control}}
|
||||||
|
<!-- <button type="button" class="inline-control combat-control icon fa-solid fa-arrow-left" data-action="previousTurn"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.TurnPrev" }}"></button>
|
||||||
|
<button type="button" class="combat-control combat-control-lg" data-action="nextTurn">
|
||||||
|
<i class="fa-solid fa-check"></i>
|
||||||
|
<span>{{ localize "COMBAT.TurnEnd" }}</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="inline-control combat-control icon fa-solid fa-arrow-right" data-action="nextTurn"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.TurnNext" }}"></button> -->
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</nav>
|
||||||
92
templates/combat-tracker-header-v2.hbs
Normal file
92
templates/combat-tracker-header-v2.hbs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<header class="combat-tracker-header">
|
||||||
|
|
||||||
|
{{!-- Encounter Controls --}}
|
||||||
|
{{#if user.isGM}}
|
||||||
|
<nav class="encounters {{ css }}" aria-label="{{ localize "COMBAT.NavLabel" }}">
|
||||||
|
|
||||||
|
{{!-- Cycle Display --}}
|
||||||
|
{{#if displayCycle}}
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-plus" data-action="createCombat"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.Create" }}"></button>
|
||||||
|
|
||||||
|
<div class="cycle-combats">
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-caret-left" data-action="cycleCombat"
|
||||||
|
{{#if previousId}}data-combat-id="{{ previousId }}" {{else}}disabled{{/if}}
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.EncounterPrevious" }}"></button>
|
||||||
|
<div class="encounter-count">
|
||||||
|
<span class="value">{{ currentIndex }}</span>
|
||||||
|
<span class="separator">/</span>
|
||||||
|
<span class="max">{{ combats.length }}</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-caret-right" data-action="cycleCombat"
|
||||||
|
{{#if nextId}}data-combat-id="{{ nextId }}" {{else}}disabled{{/if}}
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.EncounterNext" }}"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-gear" data-action="trackerSettings"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.Settings" }}"></button>
|
||||||
|
|
||||||
|
{{!-- Tabbed Display --}}
|
||||||
|
{{else if combats.length}}
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-plus" data-action="createCombat"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.Create" }}"></button>
|
||||||
|
{{#each combats}}
|
||||||
|
<button type="button" class="inline-control {{#if active}}active{{/if}}" data-action="cycleCombat"
|
||||||
|
data-combat-id="{{ id }}">
|
||||||
|
{{ label }}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-gear" data-action="trackerSettings"
|
||||||
|
data-tooltip aria-label="{{ localize "COMBAT.Settings" }}"></button>
|
||||||
|
|
||||||
|
{{!-- No Combats --}}
|
||||||
|
{{else}}
|
||||||
|
<button type="button" class="combat-control-lg" data-action="createCombat">
|
||||||
|
<i class="fa-solid fa-plus" inert></i>
|
||||||
|
<span>{{ localize "COMBAT.Create" }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
</nav>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="encounter-controls {{#if hasCombat}}combat{{/if}}">
|
||||||
|
|
||||||
|
{{!-- Bulk Rolls --}}
|
||||||
|
<div class="control-buttons left flexrow">
|
||||||
|
{{#if user.isGM}}
|
||||||
|
<button type="button" class="inline-control combat-control icon fa-solid fa-users" data-action="rollAll"
|
||||||
|
{{#unless combat.turns.length}}disabled{{/unless}} data-tooltip="COMBAT.RollAll"
|
||||||
|
aria-label="{{ localize "COMBAT.RollAll" }}"></button>
|
||||||
|
<button type="button" class="inline-control combat-control icon fa-solid fa-users-cog" data-action="rollNPC"
|
||||||
|
{{#unless combat.turns.length}}disabled{{/unless}} data-tooltip="COMBAT.RollNPC"
|
||||||
|
aria-label="{{ localize "COMBAT.RollNPC" }}"></button>
|
||||||
|
{{else}}
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<div class="spacer"></div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Combat Status --}}
|
||||||
|
<strong class="encounter-title">
|
||||||
|
{{#if combats.length}}
|
||||||
|
{{#if combat.round}}
|
||||||
|
{{ localize "COMBAT.Round" round=combat.round }}
|
||||||
|
{{else}}
|
||||||
|
{{ localize "COMBAT.NotStarted" }}
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
{{ localize "COMBAT.None" }}
|
||||||
|
{{/if}}
|
||||||
|
</strong>
|
||||||
|
|
||||||
|
{{!-- Combat Controls --}}
|
||||||
|
<div class="control-buttons right flexrow">
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<button type="button" class="encounter-context-menu inline-control combat-control icon fa-solid fa-ellipsis-vertical"
|
||||||
|
{{#unless (and user.isGM hasCombat)}}disabled{{/unless}}></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</header>
|
||||||
81
templates/combat-tracker-v2.hbs
Normal file
81
templates/combat-tracker-v2.hbs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<ol class="combat-tracker plain">
|
||||||
|
{{#each turns}}
|
||||||
|
<li class="combatant {{ css }}" data-combatant-id="{{ id }}" data-action="activateCombatant">
|
||||||
|
{{!-- TODO: Targets --}}
|
||||||
|
|
||||||
|
{{!-- Image --}}
|
||||||
|
<img class="token-image" src="{{ img }}" alt="{{ name }}" loading="lazy">
|
||||||
|
|
||||||
|
{{!-- Name & Controls --}}
|
||||||
|
<div class="token-name">
|
||||||
|
<strong class="name">{{ name }}</strong>
|
||||||
|
<div class="combatant-controls">
|
||||||
|
{{#if @root.user.isGM}}
|
||||||
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-eye-slash {{#if hidden}}active{{/if}}"
|
||||||
|
data-action="toggleHidden" data-tooltip aria-label="{{ localize "COMBAT.ToggleVis" }}"></button>
|
||||||
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-skull {{#if isDefeated}}active{{/if}}"
|
||||||
|
data-action="toggleDefeated" data-tooltip
|
||||||
|
aria-label="{{ localize "COMBAT.ToggleDead" }}"></button>
|
||||||
|
{{/if}}
|
||||||
|
{{#if canPing}}
|
||||||
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-bullseye-arrow"
|
||||||
|
data-action="pingCombatant" data-tooltip
|
||||||
|
aria-label="{{ localize "COMBAT.PingCombatant" }}"></button>
|
||||||
|
{{/if}}
|
||||||
|
{{#unless @root.user.isGM}}
|
||||||
|
<button type="button" class="inline-control combatant-control icon fa-solid fa-arrows-to-eye"
|
||||||
|
data-action="panToCombatant" data-tooltip
|
||||||
|
aria-label="{{ localize "COMBAT.PanToCombatant" }}"></button>
|
||||||
|
{{/unless}}
|
||||||
|
{{!-- TODO: Target Control --}}
|
||||||
|
<div class="token-effects" data-tooltip-html="{{ effects.tooltip }}">
|
||||||
|
{{#each effects.icons}}
|
||||||
|
<img class="token-effect" src="{{ img }}" alt="{{ name }}">
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{!-- Resource --}}
|
||||||
|
{{#if resource includeZero=true}}
|
||||||
|
<div class="token-resource">
|
||||||
|
<span class="resource">{{ resource }}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Initiative --}}
|
||||||
|
<div class="token-initiative initiative-area">
|
||||||
|
{{#if initiative includeZero=true}}
|
||||||
|
|
||||||
|
{{!-- Decimal Initiative --}}
|
||||||
|
{{#if @root.hasDecimals}}
|
||||||
|
<span>{{ initiative }}</span>
|
||||||
|
|
||||||
|
{{!-- Simple Initiative --}}
|
||||||
|
{{else}}
|
||||||
|
<input type="text" class="initiative-input" inputmode="numeric" pattern="^[+=\-]?\d*" value="{{ initiative }}"
|
||||||
|
aria-label="{{ localize "COMBAT.InitiativeScore" }}" {{#unless @root.user.isGM}}readonly{{/unless}}>
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isOwner}}
|
||||||
|
<a data-action="initiativePlus" class="initiative-plus" data-combatant-id="{{this.id}}"><i class="fa-solid fa-hexagon-plus"></i></a>
|
||||||
|
<a data-action="initiativeMinus" class="initiative-minus" data-combatant-id="{{this.id}}"><i class="fa-solid fa-hexagon-minus"></i></a>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isMonster}}
|
||||||
|
<span class="initiative">-</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="initiative" data-tooltip="Current max. progression counter">{{progressionCount}}</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{!-- Roll Initiative --}}
|
||||||
|
{{else if isOwner}}
|
||||||
|
<button type="button" class="combatant-control roll" data-action="rollInitiative" data-tooltip
|
||||||
|
aria-label="{{ localize "COMBAT.InitiativeRoll" }}"
|
||||||
|
style="--initiative-icon: url('{{ @root.initiativeIcon.icon }}'); --initiative-icon-hover: url('{{ @root.initiativeIcon.hover }}');"></button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ol>
|
||||||
36
templates/damage-applied-message.hbs
Normal file
36
templates/damage-applied-message.hbs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<div class="fvtt-lethal-fantasy damage-applied-message">
|
||||||
|
<div class="damage-header">
|
||||||
|
<div class="damage-icon">
|
||||||
|
<i class="fa-solid fa-heart-crack"></i>
|
||||||
|
</div>
|
||||||
|
<div class="damage-info">
|
||||||
|
<div class="target-name">{{targetName}}</div>
|
||||||
|
<div class="damage-subtitle">{{localize "LETHALFANTASY.DamageApplied.subtitle"}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="damage-details">
|
||||||
|
<div class="damage-amount">
|
||||||
|
<span class="damage-label">{{localize "LETHALFANTASY.DamageApplied.damageDealt"}}</span>
|
||||||
|
<span class="damage-value">{{damage}}</span>
|
||||||
|
{{#if rawDamage}}
|
||||||
|
<span class="damage-raw">({{rawDamage}} raw)</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if drText}}
|
||||||
|
<div class="damage-reduction">
|
||||||
|
<i class="fa-solid fa-shield"></i>
|
||||||
|
<span>{{drText}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="damage-source">
|
||||||
|
<i class="fa-solid fa-crosshairs"></i>
|
||||||
|
<span>{{localize "LETHALFANTASY.DamageApplied.from"}}
|
||||||
|
{{#if attackerName}}<strong>{{attackerName}}</strong> with {{/if}}
|
||||||
|
<strong>{{weaponName}}</strong>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
29
templates/loss-hp-hud.hbs
Normal file
29
templates/loss-hp-hud.hbs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<div class="control-icon" data-action="lethal-loss-hp-hud">
|
||||||
|
<img class="lethal-hp-loss-hud" src="systems/fvtt-lethal-fantasy/assets/icons/broken-heart.svg"
|
||||||
|
width="36" height="36" title="Open token journal" />
|
||||||
|
|
||||||
|
<div class="hp-loss-wrap hp-loss-wrap-col1 hp-loss-hud-disabled">
|
||||||
|
{{#for -10 0 1}}
|
||||||
|
<button class="hud-loss-hp-button-select loss-hp-hud-click " data-hp-value="{{this}}" >
|
||||||
|
<span class="">{{this}}</span>
|
||||||
|
</button>
|
||||||
|
{{/for}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hp-loss-wrap hp-loss-wrap-col2 hp-loss-hud-disabled">
|
||||||
|
{{#for -20 -10 1}}
|
||||||
|
<button class="hud-loss-hp-button-select loss-hp-hud-click " data-hp-value="{{this}}" >
|
||||||
|
<span class="">{{this}}</span>
|
||||||
|
</button>
|
||||||
|
{{/for}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hp-loss-wrap hp-loss-wrap-col3 hp-loss-hud-disabled">
|
||||||
|
{{#for -30 -20 1}}
|
||||||
|
<button class="hud-loss-hp-button-select loss-hp-hud-click " data-hp-value="{{this}}" >
|
||||||
|
<span class="">{{this}}</span>
|
||||||
|
</button>
|
||||||
|
{{/for}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -21,6 +21,9 @@
|
|||||||
<div class="attacks">
|
<div class="attacks">
|
||||||
{{#each system.attacks as |item key|}}
|
{{#each system.attacks as |item key|}}
|
||||||
<div class="attack" data-attack-key="{{key}}" >
|
<div class="attack" data-attack-key="{{key}}" >
|
||||||
|
<div class="">
|
||||||
|
<input type="checkbox" name="system.attacks.{{item.key}}.enabled" {{checked item.enabled}} data-tooltip="Attack enabled/disabled" />
|
||||||
|
</div>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<input type="text" name="system.attacks.{{item.key}}.name" value="{{item.name}}" data-tooltip="Attack name" />
|
<input type="text" name="system.attacks.{{item.key}}.name" value="{{item.name}}" data-tooltip="Attack name" />
|
||||||
</div>
|
</div>
|
||||||
@@ -62,4 +65,54 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Hand To Hand Attacks</legend>
|
||||||
|
<div class="attacks">
|
||||||
|
{{#each system.combatHTH as |item key|}}
|
||||||
|
<div class="attack" data-attack-key="{{key}}" >
|
||||||
|
<div class="">
|
||||||
|
<input type="checkbox" name="system.combatHTH.{{item.key}}.enabled" {{checked item.enabled}} data-tooltip="HTH Attack enabled/disabled" />
|
||||||
|
</div>
|
||||||
|
<div class="name">
|
||||||
|
<input type="text" name="system.combatHTH.{{item.key}}.name" value="{{item.name}}" data-tooltip="HTH Attack name" />
|
||||||
|
</div>
|
||||||
|
<div class="numeric">
|
||||||
|
<input type="number" name="system.combatHTH.{{item.key}}.attackScore" value="{{item.attackScore}}" data-tooltip="Progression number" />
|
||||||
|
</div>
|
||||||
|
<div class="numeric">
|
||||||
|
<input type="number" name="system.combatHTH.{{item.key}}.attackModifier" value="{{item.attackModifier}}" data-tooltip="Attack modifier" />
|
||||||
|
</div>
|
||||||
|
<div class="numeric">
|
||||||
|
<input type="number" name="system.combatHTH.{{item.key}}.defenseModifier" value="{{item.defenseModifier}}" data-tooltip="Defense modifier"/>
|
||||||
|
</div>
|
||||||
|
<div class="damage-dice">
|
||||||
|
<input type="text" name="system.combatHTH.{{item.key}}.damageDice" value="{{item.damageDice}}" data-tooltip="Damage dice"/>
|
||||||
|
</div>
|
||||||
|
<div class="numeric">
|
||||||
|
<input type="number" name="system.combatHTH.{{item.key}}.damageModifier" value="{{item.damageModifier}}" data-tooltip="Damage modifier"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="attack-icons">
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="monster-attack-hth" data-roll-key="{{item.key}}" data-tooltip="Roll HTH Attack">
|
||||||
|
<i class="lf-roll-small fa-solid fa-hand-fist" data-roll-type="monster-attack-hth" data-roll-key="{{item.key}}"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="monster-defense-hth" data-roll-key="{{item.key}}" data-tooltip="Roll HTH Defense">
|
||||||
|
<i class="fa-solid fa-shield-halved" data-roll-type="monster-defense-hth" data-roll-key="{{item.key}}"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="rollable" data-roll-type="monster-damage-hth" data-roll-key="{{item.key}}"
|
||||||
|
data-tooltip="Roll HTH Damage">
|
||||||
|
<i class="fa-regular fa-face-head-bandage" data-roll-type="monster-damage-hth"
|
||||||
|
data-roll-key="{{item.key}}"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
</section>
|
</section>
|
||||||
@@ -6,79 +6,177 @@
|
|||||||
<div class="monster-pc monster-pc-{{ifThen isPlayMode 'play' 'edit'}}">
|
<div class="monster-pc monster-pc-{{ifThen isPlayMode 'play' 'edit'}}">
|
||||||
<div class="monster-left">
|
<div class="monster-left">
|
||||||
<div class="monster-left-image">
|
<div class="monster-left-image">
|
||||||
<img class="monster-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
|
<img
|
||||||
data-tooltip="{{actor.name}}" />
|
class="monster-img"
|
||||||
|
src="{{actor.img}}"
|
||||||
|
data-edit="img"
|
||||||
|
data-action="editImage"
|
||||||
|
data-tooltip="{{actor.name}}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="monster-characteristics monster-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="monster-characteristics monster-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<div class="flexrow monster-hp">
|
<div class="flexrow monster-hp">
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.HP"}}</span>
|
<span class="name">{{localize "LETHALFANTASY.Label.HP"}}</span>
|
||||||
{{formInput systemFields.hp.fields.value value=system.hp.value disabled=isPlayMode classes="monster-hp-value"}}
|
{{formInput
|
||||||
|
systemFields.hp.fields.value
|
||||||
|
value=system.hp.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="monster-hp-value"
|
||||||
|
}}
|
||||||
/
|
/
|
||||||
{{formInput systemFields.hp.fields.max value=system.hp.max disabled=isPlayMode classes="monster-hp-value"}}
|
{{formInput
|
||||||
|
systemFields.hp.fields.max
|
||||||
|
value=system.hp.max
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="monster-hp-value"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="flexrow monster-hp">
|
<div class="flexrow monster-hp">
|
||||||
<span class="damage-resistance">{{localize "LETHALFANTASY.Label.damageResistance"}}</span>
|
<span class="name">{{localize
|
||||||
{{formInput systemFields.hp.fields.damageResistance value=system.hp.damageResistance disabled=isPlayMode classes="monster-hp-value"}}
|
"LETHALFANTASY.Label.damageResistance"
|
||||||
|
}}</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.hp.fields.damageResistance
|
||||||
|
value=system.hp.damageResistance
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="monster-hp-value"
|
||||||
|
}}
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.shieldDamageReduction"
|
||||||
|
}}</span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.combat.fields.shieldDamageReduction
|
||||||
|
value=system.combat.shieldDamageReduction
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="monster-hp-value"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="flexrow monster-hp">
|
||||||
|
<span class="name"><a
|
||||||
|
class="rollable"
|
||||||
|
data-roll-type="shield-defense"
|
||||||
|
data-roll-dice={{system.combat.shieldDefenseDice}}
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.shieldDefenseDice"
|
||||||
|
}}</a></span>
|
||||||
|
{{formInput
|
||||||
|
systemFields.combat.fields.shieldDefenseDice
|
||||||
|
value=system.combat.shieldDefenseDice
|
||||||
|
disabled=isPlayMode
|
||||||
|
classes="monster-hp-value"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="monster-right">
|
<div class="monster-right">
|
||||||
<div class="monster-name">
|
<div class="monster-name">
|
||||||
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
|
{{formInput
|
||||||
<a class="control" data-action="toggleSheet" data-tooltip="LETHALFANTASY.ToggleSheet"
|
fields.name
|
||||||
data-tooltip-direction="UP">
|
value=source.name
|
||||||
|
rootId=partId
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<a
|
||||||
|
class="control"
|
||||||
|
data-action="toggleSheet"
|
||||||
|
data-tooltip="LETHALFANTASY.ToggleSheet"
|
||||||
|
data-tooltip-direction="UP"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
|
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="monster-characteristics monster-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="monster-characteristics monster-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.Saves"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.Saves"}}</legend>
|
||||||
<div class="monster-saves">
|
<div class="monster-saves">
|
||||||
<div class="monster-save">
|
<div class="monster-save">
|
||||||
<span class="name"><a class="rollable" data-roll-type="save" data-roll-key="will"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="will"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.will"}}
|
{{localize "LETHALFANTASY.Label.saves.will"}}
|
||||||
</a></span>
|
</a></span>
|
||||||
{{formField systemFields.saves.fields.will.fields.value value=system.saves.will.value disabled=isPlayMode }}
|
{{formField
|
||||||
|
systemFields.saves.fields.will.fields.value
|
||||||
|
value=system.saves.will.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="dodge"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="dodge"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.dodge"}}
|
{{localize "LETHALFANTASY.Label.saves.dodge"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.dodge.fields.value value=system.saves.dodge.value
|
{{formField
|
||||||
disabled=isPlayMode}}
|
systemFields.saves.fields.dodge.fields.value
|
||||||
|
value=system.saves.dodge.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="toughness"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="toughness"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.toughness"}}
|
{{localize "LETHALFANTASY.Label.saves.toughness"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.toughness.fields.value value=system.saves.toughness.value
|
{{formField
|
||||||
disabled=isPlayMode}}
|
systemFields.saves.fields.toughness.fields.value
|
||||||
|
value=system.saves.toughness.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="monster-save">
|
<div class="monster-save">
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="contagion"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
|
data-roll-type="save"
|
||||||
|
data-roll-key="contagion"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.contagion"}}
|
{{localize "LETHALFANTASY.Label.saves.contagion"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.contagion.fields.value value=system.saves.contagion.value
|
{{formField
|
||||||
disabled=isPlayMode}}
|
systemFields.saves.fields.contagion.fields.value
|
||||||
|
value=system.saves.contagion.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
|
||||||
<span class="name">
|
<span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="poison"><i
|
<a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="rollable"
|
||||||
{{localize "LETHALFANTASY.Label.saves.poison"}}
|
data-roll-type="save"
|
||||||
|
data-roll-key="poison"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
|
{{localize "LETHALFANTASY.Label.saves.poison"}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
{{formField systemFields.saves.fields.poison.fields.value value=system.saves.poison.value
|
{{formField
|
||||||
disabled=isPlayMode }}
|
systemFields.saves.fields.poison.fields.value
|
||||||
|
value=system.saves.poison.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
|
||||||
<span class="name">
|
<!-- <span class="name">
|
||||||
<a class="rollable" data-roll-type="save" data-roll-key="paincourage" data-roll-dice="D20" data-tooltip="Pain/Courage check on wound of..."><i
|
<a class="rollable" data-roll-type="save" data-roll-key="paincourage" data-roll-dice="D20" data-tooltip="Pain/Courage check on wound of..."><i
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
class="lf-roll-small fa-solid fa-dice-d20"></i>
|
||||||
{{localize "LETHALFANTASY.Label.saves.paincourage"}}
|
{{localize "LETHALFANTASY.Label.saves.paincourage"}}
|
||||||
@@ -88,65 +186,88 @@
|
|||||||
|
|
||||||
<span data-tooltip="Pain save if wound exceeds">
|
<span data-tooltip="Pain save if wound exceeds">
|
||||||
{{formField systemFields.hp.fields.painDamage value=system.hp.painDamage disabled=isPlayMode tooltip="Pain Damage"}}
|
{{formField systemFields.hp.fields.painDamage value=system.hp.painDamage disabled=isPlayMode tooltip="Pain Damage"}}
|
||||||
</span>
|
</span>-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="monster-characteristics monster-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="monster-characteristics monster-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.skills"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.skills"}}</legend>
|
||||||
<div class="monster-skills">
|
<div class="monster-skills">
|
||||||
<div class="monster-skill">
|
<div class="monster-skill">
|
||||||
<span class="name"><a class="rollable" data-roll-type="monster-skill" data-roll-key="resistTorture"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
class="rollable"
|
||||||
"LETHALFANTASY.Label.resistTorture"}}</a></span>
|
data-roll-type="monster-skill"
|
||||||
{{formField systemFields.resists.fields.resistTorture.fields.value value=system.resists.resistTorture.value
|
data-roll-key="resistTorture"
|
||||||
disabled=isPlayMode
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.resistTorture"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.resists.fields.resistTorture.fields.value
|
||||||
|
value=system.resists.resistTorture.value
|
||||||
|
disabled=isPlayMode
|
||||||
}}
|
}}
|
||||||
<span class="name"><a class="rollable" data-roll-type="monster-skill" data-roll-key="resistPerformance"><i
|
<span class="name"><a
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
class="rollable"
|
||||||
"LETHALFANTASY.Label.resistPerformance"}}</a></span>
|
data-roll-type="monster-skill"
|
||||||
{{formField systemFields.resists.fields.resistPerformance.fields.value value=system.resists.resistPerformance.value
|
data-roll-key="resistPerformance"
|
||||||
disabled=isPlayMode
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.resistPerformance"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.resists.fields.resistPerformance.fields.value
|
||||||
|
value=system.resists.resistPerformance.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
<span class="name"><a
|
||||||
|
class="rollable"
|
||||||
|
data-roll-type="monster-skill"
|
||||||
|
data-roll-key="resistIntimidation"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.resistIntimidation"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.resists.fields.resistIntimidation.fields.value
|
||||||
|
value=system.resists.resistIntimidation.value
|
||||||
|
disabled=isPlayMode
|
||||||
}}
|
}}
|
||||||
<span class="name"><a class="rollable" data-roll-type="monster-skill" data-roll-key="resistIntimidation"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
|
||||||
"LETHALFANTASY.Label.resistIntimidation"}}</a></span>
|
|
||||||
{{formField systemFields.resists.fields.resistIntimidation.fields.value value=system.resists.resistIntimidation.value
|
|
||||||
disabled=isPlayMode }}
|
|
||||||
|
|
||||||
<span class="name"><a class="rollable" data-roll-type="monster-skill" data-roll-key="perception"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
|
||||||
"LETHALFANTASY.Label.perception"}}</a></span>
|
|
||||||
{{formField systemFields.resists.fields.perception.fields.value value=system.resists.perception.value
|
|
||||||
disabled=isPlayMode }}
|
|
||||||
|
|
||||||
<span class="name"><a class="rollable" data-roll-type="monster-skill" data-roll-key="stealth"><i
|
|
||||||
class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
|
||||||
"LETHALFANTASY.Label.stealth"}}</a></span>
|
|
||||||
{{formField systemFields.resists.fields.stealth.fields.value value=system.resists.stealth.value
|
|
||||||
disabled=isPlayMode }}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="monster-skill">
|
||||||
</fieldset>
|
<span class="name"><a
|
||||||
|
class="rollable"
|
||||||
|
data-roll-type="monster-skill"
|
||||||
|
data-roll-key="perception"
|
||||||
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
|
"LETHALFANTASY.Label.perception"
|
||||||
|
}}</a></span>
|
||||||
|
{{formField
|
||||||
|
systemFields.resists.fields.perception.fields.value
|
||||||
|
value=system.resists.perception.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
|
||||||
|
<span class="name"><a
|
||||||
<fieldset class="monster-characteristics monster-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
class="rollable"
|
||||||
<legend>{{localize "LETHALFANTASY.Label.Movement"}}</legend>
|
data-roll-type="monster-skill"
|
||||||
<div class="monster-movements">
|
data-roll-key="stealth"
|
||||||
<div class="monster-movement">
|
><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.walk"}}</span>
|
"LETHALFANTASY.Label.stealth"
|
||||||
{{formField systemFields.movement.fields.walk value=system.movement.walk disabled=isPlayMode}}
|
}}</a></span>
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.jog"}}</span>
|
{{formField
|
||||||
{{formField systemFields.movement.fields.jog value=system.challenges.movement.jog disabled=isPlayMode}}
|
systemFields.resists.fields.stealth.fields.value
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.run"}}</span>
|
value=system.resists.stealth.value
|
||||||
{{formField systemFields.movement.fields.run value=system.movement.run disabled=isPlayMode}}
|
disabled=isPlayMode
|
||||||
<span class="name">{{localize "LETHALFANTASY.Label.movement.sprint"}}</span>
|
}}
|
||||||
{{formField systemFields.movement.fields.sprint value=system.movement.sprint disabled=isPlayMode}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
@@ -154,23 +275,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="monster-characteristics monster-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
|
<fieldset
|
||||||
|
class="monster-characteristics monster-characteristics-{{ifThen
|
||||||
|
isPlayMode
|
||||||
|
'play'
|
||||||
|
'edit'
|
||||||
|
}}"
|
||||||
|
>
|
||||||
<legend>{{localize "LETHALFANTASY.Label.characteristics"}}</legend>
|
<legend>{{localize "LETHALFANTASY.Label.characteristics"}}</legend>
|
||||||
<div class="monster-characteristic">
|
<div class="monster-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.int"}}
|
<span>{{localize "LETHALFANTASY.Label.int"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="int" }}
|
systemFields.characteristics.fields.int.fields.value
|
||||||
|
value=system.characteristics.int.value
|
||||||
{{formField systemFields.characteristics.fields.int.fields.percent value=system.characteristics.int.percent
|
disabled=isPlayMode
|
||||||
disabled=isPlayMode type="number" }}
|
data-char-id="int"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="monster-characteristic">
|
<div class="monster-characteristic">
|
||||||
{{localize "LETHALFANTASY.Label.dex"}}
|
<span>{{localize "LETHALFANTASY.Label.dex"}}</span>
|
||||||
{{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value
|
{{formField
|
||||||
disabled=isPlayMode data-char-id="wis" }}
|
systemFields.characteristics.fields.dex.fields.value
|
||||||
|
value=system.characteristics.dex.value
|
||||||
|
disabled=isPlayMode
|
||||||
|
data-char-id="wis"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{formField systemFields.characteristics.fields.dex.fields.percent value=system.characteristics.dex.percent
|
<legend>{{localize "LETHALFANTASY.Label.Movement"}}</legend>
|
||||||
disabled=isPlayMode type="number" }}
|
<div class="monster-movements">
|
||||||
|
<div class="monster-movement">
|
||||||
|
<div class="flexrow monster-hp">
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.walk"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.walk
|
||||||
|
value=system.movement.walk
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="flexrow monster-hp">
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.jog"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.jog
|
||||||
|
value=system.movement.jog
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="flexrow monster-hp">
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.run"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.run
|
||||||
|
value=system.movement.run
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="flexrow monster-hp">
|
||||||
|
<span class="name">{{localize
|
||||||
|
"LETHALFANTASY.Label.movement.sprint"
|
||||||
|
}}</span>
|
||||||
|
{{formField
|
||||||
|
systemFields.movement.fields.sprint
|
||||||
|
value=system.movement.sprint
|
||||||
|
disabled=isPlayMode
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
<section>
|
|
||||||
{{!log "opponent sheet" this}}
|
|
||||||
<div class="opponent-header">
|
|
||||||
<img class="opponent-img" src="{{actor.img}}" data-edit="img" data-action="editImage" data-tooltip="{{actor.name}}" />
|
|
||||||
{{formInput fields.name value=source.name}}
|
|
||||||
<a class="control" data-action="toggleSheet" data-tooltip="TENEBRIS.ToggleSheet" data-tooltip-direction="UP">
|
|
||||||
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="opponent-main">
|
|
||||||
<div class="opponent-gauche">
|
|
||||||
<fieldset class="opponent-caracteristiques">
|
|
||||||
<legend>{{localize "TENEBRIS.Character.Label.caracteristiques"}}</legend>
|
|
||||||
{{formField systemFields.dv value=system.dv disabled=isPlayMode}}
|
|
||||||
{{formField systemFields.pv.fields.value value=system.pv.value}}
|
|
||||||
{{formField systemFields.pv.fields.max value=system.pv.max disabled=isPlayMode}}
|
|
||||||
{{formField systemFields.armure value=system.armure disabled=isPlayMode}}
|
|
||||||
{{formField systemFields.malus value=system.malus disabled=isPlayMode}}
|
|
||||||
{{formField systemFields.actions value=system.actions disabled=isPlayMode}}
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset class="opponent-attacks">
|
|
||||||
<legend>{{localize "TENEBRIS.Character.Label.attaques"}}
|
|
||||||
{{#if isEditMode}}<a class="action" data-tooltip="{{localize 'TENEBRIS.Tooltip.addAttack'}}" data-tooltip-direction="UP"><i
|
|
||||||
class="fas fa-plus"
|
|
||||||
data-action="createAttack"
|
|
||||||
></i></a>{{/if}}</legend>
|
|
||||||
{{#each attacks as |attack|}}
|
|
||||||
<div class="opponent-attack" data-drag="true" data-drag-type="attack" data-roll-value="{{attack.system.degats}}" data-roll-target="{{attack.name}}">
|
|
||||||
<div class="attack-name">
|
|
||||||
<a
|
|
||||||
class="rollable"
|
|
||||||
data-item-id="{{attack.id}}"
|
|
||||||
data-item-name="{{attack.name}}"
|
|
||||||
data-action="roll"
|
|
||||||
data-roll-type="attack"
|
|
||||||
data-roll-value="{{attack.system.degats}}"
|
|
||||||
>{{attack.system.degats}}</a>
|
|
||||||
(<span data-tooltip="{{attack.system.toolTip}}">{{attack.name}}</span>)
|
|
||||||
</div>
|
|
||||||
{{#if @root.isEditMode}}
|
|
||||||
<div class="controls">
|
|
||||||
<a data-tooltip="{{localize 'TENEBRIS.Edit'}}" data-action="edit" data-item-id="{{attack.id}}" data-item-uuid="{{attack.uuid}}"><i class="fas fa-edit"></i></a>
|
|
||||||
<a data-tooltip="{{localize 'TENEBRIS.Delete'}}" data-action="delete" data-item-id="{{attack.id}}" data-item-uuid="{{attack.uuid}}"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
{{#if (or isEditMode (and isPlayMode hasSpells))}}
|
|
||||||
<fieldset class="opponent-spells">
|
|
||||||
<legend>{{localize "TENEBRIS.Label.spells"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "TENEBRIS.Tooltip.addSpell"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createSpell"></i></a>{{/if}}</legend>
|
|
||||||
{{#each spells as |spell|}}
|
|
||||||
<div class="opponent-spell">
|
|
||||||
<div class="name" data-tooltip="{{{spell.system.description}}}">
|
|
||||||
{{spell.name}}
|
|
||||||
</div>
|
|
||||||
{{#if @root.isEditMode}}
|
|
||||||
<div class="controls">
|
|
||||||
<a data-tooltip="{{localize 'TENEBRIS.Edit'}}" data-action="edit" data-item-id="{{spell.id}}" data-item-uuid="{{spell.uuid}}"><i class="fas fa-edit"></i></a>
|
|
||||||
<a data-tooltip="{{localize 'TENEBRIS.Delete'}}" data-action="delete" data-item-id="{{spell.id}}" data-item-uuid="{{spell.uuid}}"><i class="fas fa-trash"></i></a>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</fieldset>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="opponent-droite">
|
|
||||||
<fieldset class="opponent-description">
|
|
||||||
<legend>{{localize "TENEBRIS.Label.description"}}</legend>
|
|
||||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true compact=true}}
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user