Fix actor sheet modifications/updates
This commit is contained in:
+11
-3
@@ -22,6 +22,8 @@
|
||||
"AWEMMY.Condition.Edge": "Edge",
|
||||
"AWEMMY.Condition.Hampered": "Hampered",
|
||||
"AWEMMY.Condition.Inhibited": "Inhibited",
|
||||
"AWEMMY.Condition.Penalty": "Penalty",
|
||||
"AWEMMY.Condition.DCPenalty": "DC Penalty",
|
||||
"AWEMMY.Condition.Jumbled": "Jumbled",
|
||||
"AWEMMY.Condition.Mishap": "Mishap",
|
||||
"AWEMMY.Condition.Prone": "Prone",
|
||||
@@ -31,6 +33,7 @@
|
||||
"AWEMMY.Condition.Panel": "Conditions",
|
||||
"AWEMMY.Roll.ConditionBonus": "Condition",
|
||||
"AWEMMY.Item.Description": "Description",
|
||||
"AWEMMY.Item.RollBonus": "Roll Bonus",
|
||||
"AWEMMY.Error.TraitPasteFailed": "Failed to update traits — please try again.",
|
||||
"AWEMMY.Kit.Use": "Use Kit",
|
||||
"AWEMMY.Kit.Used": "{name} used",
|
||||
@@ -59,9 +62,13 @@
|
||||
"AWEMMY.Roll.Check": "Check",
|
||||
"AWEMMY.Roll.Roll": "Roll",
|
||||
"AWEMMY.Roll.DialogTitle": "Roll: {name}",
|
||||
"AWEMMY.Roll.SituationalBonus": "Situational Bonus",
|
||||
"AWEMMY.Roll.RollTwice": "Roll Twice",
|
||||
"AWEMMY.Roll.Normal": "Normal",
|
||||
"AWEMMY.Roll.TakeHigher": "Take Higher",
|
||||
"AWEMMY.Roll.TakeLower": "Take Lower",
|
||||
"AWEMMY.Roll.SituationalBonus": "Bonus or Penalty",
|
||||
"AWEMMY.Roll.AttributeBonus": "Attribute Bonus",
|
||||
"AWEMMY.Roll.KnowledgeBonus": "Knowledge Bonus",
|
||||
"AWEMMY.Roll.KnowledgeBonus": "Item Bonus",
|
||||
"AWEMMY.Roll.Formula": "Formula",
|
||||
"AWEMMY.Roll.DC": "DC",
|
||||
"AWEMMY.Roll.Visibility": "Visibility",
|
||||
@@ -79,7 +86,8 @@
|
||||
"AWEMMY.Character.HPTemp": "Temp HP",
|
||||
"AWEMMY.Character.FlowPoints": "Flow Points",
|
||||
"AWEMMY.Character.FlowPointsTemp": "Temp FP",
|
||||
"AWEMMY.Character.BoostLevel": "Boost Level",
|
||||
"AWEMMY.Character.BoostLevel": "Boost",
|
||||
"AWEMMY.Character.Repertoire": "Repertoire",
|
||||
"AWEMMY.Character.Mod": "MOD",
|
||||
"AWEMMY.Character.DC": "DC",
|
||||
"AWEMMY.Character.Bonus": "+/−",
|
||||
|
||||
@@ -100,6 +100,11 @@ export default class AwECharacterSheet extends AwEActorSheet {
|
||||
img: `systems/fvtt-adventures-with-emmy/assets/conditions/${c.id}.svg`,
|
||||
active: doc.statuses.has(c.id)
|
||||
}))
|
||||
context.inhibitedActive = doc.statuses.has("inhibited")
|
||||
context.vulnerableActive = doc.statuses.has("vulnerable")
|
||||
context.inhibitedPenalty = doc.system.inhibitedPenalty
|
||||
context.vulnerablePenalty = doc.system.vulnerablePenalty
|
||||
context.hasConditionPenalties = context.inhibitedActive || context.vulnerableActive
|
||||
break
|
||||
case "biography":
|
||||
context.tab = context.tabs.biography
|
||||
|
||||
+20
-11
@@ -44,11 +44,7 @@ export default class AwEActor extends Actor {
|
||||
const attribute = this.system.attributes[attrId]
|
||||
if (!attribute) return null
|
||||
|
||||
const knowledgeBonuses = this.itemTypes.field?.map(f => ({
|
||||
label: f.name,
|
||||
bonus: f.system.knowledgeBonus ?? ""
|
||||
})).filter(f => f.bonus !== "") ?? []
|
||||
|
||||
const knowledgeBonuses = this.#buildItemBonuses()
|
||||
const { conditionBonus, conditionLabels } = this.#buildConditionOptions()
|
||||
|
||||
const roll = await AwERoll.prompt({
|
||||
@@ -101,12 +97,7 @@ export default class AwEActor extends Actor {
|
||||
const attribute = this.system.attributes[attributeId]
|
||||
if (!attribute) return null
|
||||
|
||||
// Collect knowledge bonuses from embedded Field items
|
||||
const knowledgeBonuses = this.itemTypes.field?.map(f => ({
|
||||
label: f.name,
|
||||
bonus: f.system.knowledgeBonus ?? ""
|
||||
})).filter(f => f.bonus !== "") ?? []
|
||||
|
||||
const knowledgeBonuses = this.#buildItemBonuses()
|
||||
const { conditionBonus, conditionLabels } = this.#buildConditionOptions()
|
||||
|
||||
const roll = await AwERoll.prompt({
|
||||
@@ -127,6 +118,19 @@ export default class AwEActor extends Actor {
|
||||
return roll
|
||||
}
|
||||
|
||||
/** Collect roll bonuses from all item types that declare a rollBonus or knowledgeBonus. */
|
||||
#buildItemBonuses() {
|
||||
const entries = [
|
||||
// Field items use the original knowledgeBonus field
|
||||
...(this.itemTypes.field ?? []).map(i => ({ label: i.name, bonus: i.system.knowledgeBonus ?? "" })),
|
||||
// Ability, equipment, specialization use rollBonus
|
||||
...(this.itemTypes.ability ?? []).map(i => ({ label: i.name, bonus: i.system.rollBonus ?? "" })),
|
||||
...(this.itemTypes.equipment ?? []).map(i => ({ label: i.name, bonus: i.system.rollBonus ?? "" })),
|
||||
...(this.itemTypes.specialization ?? []).map(i => ({ label: i.name, bonus: i.system.rollBonus ?? "" })),
|
||||
]
|
||||
return entries.filter(e => e.bonus !== "")
|
||||
}
|
||||
|
||||
#buildConditionOptions() {
|
||||
let conditionBonus = 0
|
||||
const conditionLabels = []
|
||||
@@ -142,6 +146,11 @@ export default class AwEActor extends Actor {
|
||||
conditionBonus -= 2
|
||||
conditionLabels.push({ label: game.i18n.localize("AWEMMY.Condition.Jumbled"), bonus: -2 })
|
||||
}
|
||||
if (this.statuses.has("inhibited")) {
|
||||
const penalty = this.system.inhibitedPenalty ?? 2
|
||||
conditionBonus -= penalty
|
||||
conditionLabels.push({ label: game.i18n.localize("AWEMMY.Condition.Inhibited"), bonus: -penalty })
|
||||
}
|
||||
return { conditionBonus, conditionLabels }
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ export default class AwERoll extends Roll {
|
||||
get damageCritical() { return this.options.damageCritical ?? false }
|
||||
get conditionBonus() { return this.options.conditionBonus ?? 0 }
|
||||
get conditionLabels() { return this.options.conditionLabels ?? [] }
|
||||
get rollTwice() { return this.options.rollTwice ?? "" }
|
||||
|
||||
// --- Outcome calculation ---
|
||||
|
||||
@@ -116,17 +117,23 @@ export default class AwERoll extends Roll {
|
||||
const el = dialog.element
|
||||
const bonusSelect = el.querySelector('#awe-bonus')
|
||||
const knowledgeSel = el.querySelector('#awe-knowledge')
|
||||
const rollTwiceSel = el.querySelector('#awe-roll-twice')
|
||||
const preview = el.querySelector('#awe-formula-preview')
|
||||
const diceExprEl = el.querySelector('#awe-dice-expr')
|
||||
function updatePreview() {
|
||||
const sit = parseInt(bonusSelect?.value) || 0
|
||||
const kn = parseInt(knowledgeSel?.value) || 0
|
||||
const total = baseMod + sit + kn
|
||||
const sign = total >= 0 ? '+' : '−'
|
||||
const abs = Math.abs(total)
|
||||
preview.textContent = total === 0 ? '1d20' : `1d20 ${sign} ${abs}`
|
||||
const mode = rollTwiceSel?.value
|
||||
const dice = mode === 'higher' ? '2d20kh1' : mode === 'lower' ? '2d20kl1' : '1d20'
|
||||
if (diceExprEl) diceExprEl.textContent = dice
|
||||
preview.textContent = total === 0 ? dice : `${dice} ${sign} ${abs}`
|
||||
}
|
||||
bonusSelect?.addEventListener('change', updatePreview)
|
||||
knowledgeSel?.addEventListener('change', updatePreview)
|
||||
rollTwiceSel?.addEventListener('change', updatePreview)
|
||||
updatePreview()
|
||||
},
|
||||
buttons: [{
|
||||
@@ -146,10 +153,16 @@ export default class AwERoll extends Roll {
|
||||
const knowledgeBonus = parseInt(result.knowledgeBonus) || 0
|
||||
const dc = result.dc !== "" ? parseInt(result.dc) : undefined
|
||||
const rollMode = result.visibility ?? game.settings.get("core", "rollMode")
|
||||
const rollTwice = result.rollTwice ?? ""
|
||||
|
||||
// Formula: 1d20 + (mod + attrBonus) [± bonus] [± knowledgeBonus] [± conditionBonus]
|
||||
// Dice expression based on roll-twice mode
|
||||
const diceExpr = rollTwice === 'higher' ? '2d20kh1'
|
||||
: rollTwice === 'lower' ? '2d20kl1'
|
||||
: '1d20'
|
||||
|
||||
// Formula: {diceExpr} + (mod + attrBonus) [± bonus] [± knowledgeBonus] [± conditionBonus]
|
||||
const totalMod = mod + attrBonus + bonus + knowledgeBonus + (options.conditionBonus ?? 0)
|
||||
let formula = `1d20`
|
||||
let formula = diceExpr
|
||||
if (totalMod > 0) formula += ` + ${totalMod}`
|
||||
else if (totalMod < 0) formula += ` - ${Math.abs(totalMod)}`
|
||||
|
||||
@@ -162,6 +175,7 @@ export default class AwERoll extends Roll {
|
||||
knowledgeBonus,
|
||||
conditionBonus: options.conditionBonus ?? 0,
|
||||
conditionLabels: options.conditionLabels ?? [],
|
||||
rollTwice,
|
||||
dc,
|
||||
actorId: options.actorId,
|
||||
actorName: options.actorName,
|
||||
@@ -175,8 +189,9 @@ export default class AwERoll extends Roll {
|
||||
await roll.evaluate()
|
||||
|
||||
// Compute degree of success when a DC is known
|
||||
// Use the *kept* die result (active:true) for nat-20/nat-1 adjustment
|
||||
if (dc !== undefined) {
|
||||
const d20Value = roll.dice[0]?.results[0]?.result ?? 0
|
||||
const d20Value = roll.dice[0]?.results.find(r => r.active)?.result ?? 0
|
||||
roll.options.outcome = AwERoll.computeOutcome(roll.total, dc, d20Value)
|
||||
}
|
||||
|
||||
@@ -220,6 +235,7 @@ export default class AwERoll extends Roll {
|
||||
conditionBonus: isPrivate ? null : this.conditionBonus,
|
||||
conditionLabels: this.conditionLabels,
|
||||
dice: this.dice,
|
||||
rollTwice: this.rollTwice,
|
||||
outcome: isPrivate ? null : this.outcome,
|
||||
dc: this.dc,
|
||||
actorId: this.actorId,
|
||||
|
||||
@@ -28,6 +28,7 @@ export default class AwEAbility extends foundry.abstract.TypeDataModel {
|
||||
schema.isDaily = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.flowPointCost = new fields.NumberField({ required: true, nullable: false, initial: 0, min: 0, integer: true })
|
||||
schema.usedToday = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.rollBonus = new fields.StringField({ initial: "", required: false, nullable: true })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@ export default class AwECharacter extends foundry.abstract.TypeDataModel {
|
||||
}, {})
|
||||
)
|
||||
|
||||
// Condition penalty magnitudes (used when the respective condition is active)
|
||||
schema.inhibitedPenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 })
|
||||
schema.vulnerablePenalty = new fields.NumberField({ required: true, nullable: false, integer: true, initial: 2, min: 0 })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ export default class AwEEquipment extends foundry.abstract.TypeDataModel {
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.quantity = new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
|
||||
schema.weight = new fields.NumberField({ required: true, nullable: false, initial: 0, min: 0 })
|
||||
schema.rollBonus = new fields.StringField({ initial: "", required: false, nullable: true })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ export default class AwESpecialization extends foundry.abstract.TypeDataModel {
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.traits = new fields.ArrayField(new fields.StringField())
|
||||
schema.rollBonus = new fields.StringField({ initial: "", required: false, nullable: true })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{localize "AWEMMY.Item.RollBonus"}}</label>
|
||||
{{formInput systemFields.rollBonus value=system.rollBonus placeholder="e.g. 2 to Recall Knowledge"}}
|
||||
</div>
|
||||
|
||||
<div class="form-group-tags">
|
||||
<label>{{localize "AWEMMY.Ability.Traits"}}</label>
|
||||
<div class="tags-list">
|
||||
|
||||
@@ -6,10 +6,22 @@
|
||||
<label>{{localize "AWEMMY.Character.Pronouns"}}</label>
|
||||
{{formInput systemFields.pronouns value=system.pronouns disabled=isPlayMode}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{localize "AWEMMY.Character.Specialization"}}</label>
|
||||
{{formInput systemFields.specialization value=system.specialization disabled=isPlayMode}}
|
||||
</fieldset>
|
||||
|
||||
<!-- Background (max 1) -->
|
||||
<fieldset class="items-list-fieldset">
|
||||
<legend>{{localize "AWEMMY.Item.Background"}}</legend>
|
||||
{{#each backgrounds}}
|
||||
<div class="item-row" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-drag="true" data-tooltip="{{itemTooltip this}}">
|
||||
<img src="{{img}}" class="item-img" alt="{{name}}" />
|
||||
<span class="item-name">{{name}}</span>
|
||||
<div class="item-controls">
|
||||
<a class="item-control" data-action="edit" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-tooltip="{{localize 'AWEMMY.Sheet.EditItem'}}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control" data-action="delete" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-tooltip="{{localize 'AWEMMY.Sheet.DeleteItem'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#unless backgrounds.length}}<div class="item-row item-empty"><em>{{localize "AWEMMY.Character.DropBackground"}}</em></div>{{/unless}}
|
||||
</fieldset>
|
||||
|
||||
<!-- Field (max 1) -->
|
||||
@@ -81,22 +93,6 @@
|
||||
{{#unless archetypes.length}}<div class="item-row item-empty"><em>{{localize "AWEMMY.Character.DropArchetype"}}</em></div>{{/unless}}
|
||||
</fieldset>
|
||||
|
||||
<!-- Background (max 1) -->
|
||||
<fieldset class="items-list-fieldset">
|
||||
<legend>{{localize "AWEMMY.Item.Background"}}</legend>
|
||||
{{#each backgrounds}}
|
||||
<div class="item-row" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-drag="true" data-tooltip="{{itemTooltip this}}">
|
||||
<img src="{{img}}" class="item-img" alt="{{name}}" />
|
||||
<span class="item-name">{{name}}</span>
|
||||
<div class="item-controls">
|
||||
<a class="item-control" data-action="edit" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-tooltip="{{localize 'AWEMMY.Sheet.EditItem'}}"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-control" data-action="delete" data-item-id="{{id}}" data-item-uuid="{{uuid}}" data-tooltip="{{localize 'AWEMMY.Sheet.DeleteItem'}}"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{#unless backgrounds.length}}<div class="item-row item-empty"><em>{{localize "AWEMMY.Character.DropBackground"}}</em></div>{{/unless}}
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "AWEMMY.Character.Description"}}</legend>
|
||||
{{formInput
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
{{!-- Abilities --}}
|
||||
<fieldset>
|
||||
<legend>{{localize "AWEMMY.Item.Ability"}}</legend>
|
||||
<legend>{{localize "AWEMMY.Character.Repertoire"}}</legend>
|
||||
<div class="item-list">
|
||||
{{#each abilities as |item|}}
|
||||
<div class="item-row {{#if item.usedToday}}ability-used{{/if}}" data-drag="true" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-tooltip="{{itemTooltip item}}">
|
||||
@@ -95,6 +95,22 @@
|
||||
</a>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if hasConditionPenalties}}
|
||||
<div class="condition-penalties">
|
||||
{{#if inhibitedActive}}
|
||||
<div class="condition-penalty-row">
|
||||
<label>{{localize "AWEMMY.Condition.Inhibited"}} {{localize "AWEMMY.Condition.Penalty"}}</label>
|
||||
{{formInput systemFields.inhibitedPenalty value=inhibitedPenalty classes="condition-penalty-input"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if vulnerableActive}}
|
||||
<div class="condition-penalty-row">
|
||||
<label>{{localize "AWEMMY.Condition.Vulnerable"}} {{localize "AWEMMY.Condition.DCPenalty"}}</label>
|
||||
{{formInput systemFields.vulnerablePenalty value=vulnerablePenalty classes="condition-penalty-input"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</fieldset>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="roll-breakdown">
|
||||
{{#each dice}}
|
||||
{{#each results}}
|
||||
<span class="die-result {{#if (eq result ../faces)}}max{{else if (eq result 1)}}min{{/if}}">
|
||||
<span class="die-result {{#unless active}}discarded{{else}}{{#if (eq result ../faces)}}max{{else if (eq result 1)}}min{{/if}}{{/unless}}">
|
||||
<i class="fa-solid fa-dice-d{{../faces}}"></i> {{result}}
|
||||
</span>
|
||||
{{/each}}
|
||||
@@ -55,6 +55,15 @@
|
||||
{{#if dc}}<span class="roll-dc">/ DC {{dc}}</span>{{/if}}
|
||||
</div>
|
||||
|
||||
{{!-- Roll-twice mode badge --}}
|
||||
{{#if rollTwice}}
|
||||
<div class="roll-twice-badge">
|
||||
{{#if (eq rollTwice "higher")}}<i class="fas fa-angles-up"></i> {{localize "AWEMMY.Roll.TakeHigher"}}
|
||||
{{else}}<i class="fas fa-angles-down"></i> {{localize "AWEMMY.Roll.TakeLower"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- Outcome badge --}}
|
||||
{{#if outcome}}
|
||||
<div class="outcome-badge {{outcome}}">
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{localize "AWEMMY.Item.RollBonus"}}</label>
|
||||
{{formInput systemFields.rollBonus value=system.rollBonus placeholder="e.g. 2 to Recall Knowledge"}}
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "AWEMMY.Item.Description"}}</legend>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="roll-header">
|
||||
<span class="roll-attr-name">{{attrLabel}}</span>
|
||||
<span class="roll-formula-summary">
|
||||
1d20
|
||||
<span id="awe-dice-expr">1d20</span>
|
||||
{{#if (gt modifier 0)}} + {{modifier}}{{else if (lt modifier 0)}} − {{abs modifier}}{{/if}}
|
||||
{{#if (gt attributeBonus 0)}} + <em>{{attributeBonus}}</em>{{else if (lt attributeBonus 0)}} − <em>{{abs attributeBonus}}</em>{{/if}}
|
||||
</span>
|
||||
@@ -20,6 +20,16 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- Roll twice --}}
|
||||
<div class="dialog-row">
|
||||
<label for="awe-roll-twice">{{localize "AWEMMY.Roll.RollTwice"}}</label>
|
||||
<select id="awe-roll-twice" name="rollTwice">
|
||||
<option value="">{{localize "AWEMMY.Roll.Normal"}}</option>
|
||||
<option value="higher">{{localize "AWEMMY.Roll.TakeHigher"}}</option>
|
||||
<option value="lower">{{localize "AWEMMY.Roll.TakeLower"}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{!-- Situational bonus / penalty --}}
|
||||
<div class="dialog-row">
|
||||
<label for="awe-bonus">{{localize "AWEMMY.Roll.SituationalBonus"}}</label>
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{localize "AWEMMY.Item.RollBonus"}}</label>
|
||||
{{formInput systemFields.rollBonus value=system.rollBonus placeholder="e.g. 2 to Recall Knowledge"}}
|
||||
</div>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "AWEMMY.Item.Description"}}</legend>
|
||||
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
|
||||
|
||||
Reference in New Issue
Block a user