feat: D30 combat effects, spell tiers, small damage removal, token HUD luck/grit
- Replace Knockback with Internal Injury on D30 (5, 10, 15); remove Shield Bash from D30 counter-attacks - Eliminate small weapon damage: keep only medium damage labelled Damage in sheets, rolls, and chat - D30 bonus dice (20, 27, 30) auto-resolved before grit/luck/shield decisions; choice dialogs for special strikes - D30 combat effects: bleeding wounds, damage ×2/×3 before DR, DR ×2/×3 with component picker dialog - Add hp.wounds to monster schema for bleeding support - Show Save against spell? checkbox for all save rolls (not just magic users) - Fix mulligan restart: persistent D30 process flags prevent double-application and allow both sides to react - For Dice So Nice, show main roll animation before explosion dice for correct ordering - Spell tier selection: force Standard/Overpowered choice at cast time, tier-specific aether cost, only chosen damage button shown - Add +1/−1 luck and grit controls to Token HUD - Fix inconsistent indentation, remove duplicate i18n key, remove unused includesShield return
This commit is contained in:
@@ -281,7 +281,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 (=).
|
||||
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||
*/
|
||||
async roll(rollType, rollTarget, defenderId, defenderTokenId, extraShieldDr = 0) {
|
||||
async roll(rollType, rollTarget, defenderId, defenderTokenId, extraShieldDr = 0, d30Effects = {}) {
|
||||
const hasTarget = false
|
||||
let roll = await LethalFantasyRoll.prompt({
|
||||
rollType,
|
||||
@@ -293,7 +293,11 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
|
||||
target: false,
|
||||
defenderId,
|
||||
defenderTokenId,
|
||||
extraShieldDr
|
||||
extraShieldDr,
|
||||
damageTier: rollTarget.damageTier || "standard",
|
||||
d30Bleed: d30Effects.d30Bleed || false,
|
||||
d30DamageMultiplier: d30Effects.d30DamageMultiplier || 1,
|
||||
d30DrMultiplier: d30Effects.d30DrMultiplier || 1
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
|
||||
@@ -56,10 +56,28 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
||||
}, {}),
|
||||
)
|
||||
|
||||
const woundFieldSchema = {
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
duration: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
description: new fields.StringField({ initial: "", required: false, nullable: true }),
|
||||
}
|
||||
|
||||
schema.hp = new fields.SchemaField({
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
average: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
wounds: new fields.ArrayField(new fields.SchemaField(woundFieldSchema), {
|
||||
initial: [
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 },
|
||||
{ description: "", value: 0, duration: 0 }
|
||||
], min: 8
|
||||
}),
|
||||
damageResistance: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
painDamage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
})
|
||||
@@ -164,7 +182,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 (=).
|
||||
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
|
||||
*/
|
||||
async roll(rollType, rollTarget, defenderId = undefined, defenderTokenId = undefined, extraShieldDr = 0) {
|
||||
async roll(rollType, rollTarget, defenderId = undefined, defenderTokenId = undefined, extraShieldDr = 0, d30Effects = {}) {
|
||||
const hasTarget = false
|
||||
|
||||
// Ranged monster defense uses the ranged defense dialog (movement, range, size modifiers)
|
||||
@@ -192,14 +210,18 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
||||
target: false,
|
||||
defenderId,
|
||||
defenderTokenId,
|
||||
extraShieldDr
|
||||
extraShieldDr,
|
||||
damageTier: rollTarget.damageTier || "standard",
|
||||
d30Bleed: d30Effects.d30Bleed || false,
|
||||
d30DamageMultiplier: d30Effects.d30DamageMultiplier || 1,
|
||||
d30DrMultiplier: d30Effects.d30DrMultiplier || 1
|
||||
})
|
||||
if (!roll) return null
|
||||
|
||||
await roll.toMessage({}, { messageMode: roll.options.rollMode })
|
||||
}
|
||||
|
||||
async prepareMonsterRoll(rollType, rollKey, rollDice = undefined, tokenId = undefined, damageModifier = undefined, defenderId = undefined, defenderTokenId = undefined, extraShieldDr = 0) {
|
||||
async prepareMonsterRoll(rollType, rollKey, rollDice = undefined, tokenId = undefined, damageModifier = undefined, defenderId = undefined, defenderTokenId = undefined, extraShieldDr = 0, d30Effects = {}) {
|
||||
let rollTarget
|
||||
switch (rollType) {
|
||||
case "monster-attack":
|
||||
@@ -252,8 +274,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
||||
}, { messageMode: roll.options.rollMode ?? game.settings.get("core", "rollMode") })
|
||||
return
|
||||
}
|
||||
case "weapon-damage-small":
|
||||
case "weapon-damage-medium":
|
||||
case "weapon-damage":
|
||||
case "weapon-attack":
|
||||
case "weapon-defense": {
|
||||
let weapon = this.actor.items.find((i) => i.type === "weapon" && i.id === rollKey)
|
||||
@@ -300,7 +321,7 @@ export default class LethalFantasyMonster extends foundry.abstract.TypeDataModel
|
||||
// In all cases
|
||||
if (rollTarget) {
|
||||
rollTarget.tokenId = tokenId
|
||||
await this.roll(rollType, rollTarget, defenderId, defenderTokenId, extraShieldDr)
|
||||
await this.roll(rollType, rollTarget, defenderId, defenderTokenId, extraShieldDr, d30Effects)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ export default class LethalFantasySpell extends foundry.abstract.TypeDataModel {
|
||||
})
|
||||
|
||||
schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
schema.costOverpowered = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
schema.costOverpowered2 = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
schema.memorized = new fields.BooleanField({ required: true, initial: false })
|
||||
|
||||
schema.components = new fields.SchemaField({
|
||||
|
||||
Reference in New Issue
Block a user