Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attack message normalisation #148

Merged
merged 10 commits into from
Dec 21, 2023
5 changes: 2 additions & 3 deletions src/module/active-effects/afflictions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class DLAfflictions {
const isBlocked = actor.system.maluses.autoFail[actionType]?.[actionAttribute] > 0
if (isBlocked) {
// TODO: more precise message? Currently it picks the first message
let msg = actor.getEmbeddedCollection('ActiveEffect').find(effect => Boolean(effect.flags?.warningMessage))
let msg = Array.from(actor.allApplicableEffects()).find(effect => Boolean(effect.flags?.warningMessage))
?.flags.warningMessage
msg = msg ?? game.i18n.localize(`DL.AutoFail${actionType.capitalize()}s`)
ui.notifications.error(msg)
Expand All @@ -42,8 +42,7 @@ export class DLAfflictions {

static async clearAfflictions(actor) {
if (!actor) return
const afflictions = actor
.getEmbeddedCollection('ActiveEffect')
const afflictions = Array.from(actor.allApplicableEffects())
.filter(e => e.statuses.size > 0)
.map(e => e._id)
await actor.deleteEmbeddedDocuments('ActiveEffect', afflictions)
Expand Down
15 changes: 10 additions & 5 deletions src/module/active-effects/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
* @param {MouseEvent} event The left-click event on the effect control
* @param {Actor|Item} owner The owning entity which manages this effect
*/
import { DemonlordActor } from "../actor/actor";
import {calcEffectRemainingRounds, calcEffectRemainingSeconds, calcEffectRemainingTurn} from "../combat/combat";
import { DemonlordItem } from "../item/item";
import {i18n} from "../utils/utils";

export async function onManageActiveEffect(event, owner) {
event.preventDefault()
const a = event.currentTarget
const li = a.closest('li')
const effect = li.dataset.effectId ? owner.effects.get(li.dataset.effectId) : null
const effect = li.dataset.effectId ? (owner instanceof DemonlordActor ? Array.from(owner.allApplicableEffects()).find(e => e._id === li.dataset.effectId) : owner.effects.get(li.dataset.effectId)) : null
const isCharacter = owner.type === 'character'
switch (a.dataset.action) {
case 'create':
Expand Down Expand Up @@ -43,34 +45,37 @@ export async function onManageActiveEffect(event, owner) {
* @param {Integer} showControls What controls to show
* @return {object} Data for rendering
*/
export function prepareActiveEffectCategories(effects, showCreateButtons = false, showControls = 3) {
export function prepareActiveEffectCategories(effects, showCreateButtons = false, ownerIsItem = false) {
// Define effect header categories
let categories = {
temporary: {
type: 'temporary',
name: 'Temporary Effects',
showCreateButtons: showCreateButtons,
showControls: showControls,
showControls: 3,
effects: [],
},
passive: {
type: 'passive',
name: 'Passive Effects',
showCreateButtons: showCreateButtons,
showControls: showControls,
showControls: 3,
effects: [],
},
inactive: {
type: 'inactive',
name: 'Inactive Effects',
showCreateButtons: showCreateButtons,
showControls: showControls,
showControls: 3,
effects: [],
},
}

// Iterate over active effects, classifying them into categories.
for (let e of effects) {
// First thing, set notEditable flag on effects that come from items where !ownerIsItem
e.flags.notDeletable = e.flags.notDeletable ?? (e.parent instanceof DemonlordItem && !ownerIsItem)

// Also set the 'remaining time' in seconds or rounds depending on if in combat
if (e.isTemporary && (e.duration.seconds || e.duration.rounds || e.duration.turns)) {
if (game.combat) {
Expand Down
3 changes: 2 additions & 1 deletion src/module/active-effects/item-effects.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DemonlordActor } from '../actor/actor'
import { plusify } from '../utils/utils'

export const addEffect = (key, value, priority) => ({
Expand Down Expand Up @@ -52,7 +53,7 @@ const falsyChangeFilter = change => Boolean(change.value)

export class DLActiveEffects {
static async removeEffectsByOrigin(doc, originID) {
const toDel = doc.getEmbeddedCollection('ActiveEffect').filter(effect => effect.data?.origin?.includes(originID))
const toDel = (doc instanceof DemonlordActor ? Array.from(doc.allApplicableEffects()) : doc.effects).filter(effect => effect?.origin?.includes(originID))

const promises = []
for await (const e of toDel) {
Expand Down
84 changes: 62 additions & 22 deletions src/module/actor/actor.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export class DemonlordActor extends Actor {

// We can reapply some active effects if we know they happened
// We're copying what it's done in applyActiveEffects
const effectChanges = this.effects.reduce((changes, e) => {
const effectChanges = Array.from(this.allApplicableEffects()).reduce((changes, e) => {
if (e.disabled || e.isSuppressed) return changes
return changes.concat(e.changes.map(c => {
c = foundry.utils.duplicate(c)
Expand Down Expand Up @@ -191,23 +191,63 @@ export class DemonlordActor extends Actor {
if (result !== null) this.overrides[change.key] = result
}

// WIP: Adjust size here
// for (let change of effectChanges.filter(e => e.key.includes("size"))) {
// let size = change.value
// let newSize = 0
// Adjust size here
const originalSize = this._source.system.characteristics.size
let modifiedSize = 0
let newSize = "1"
if (originalSize.includes("/")) {
const [numerator, denominator] = originalSize.split("/")
modifiedSize = parseInt(numerator) / parseInt(denominator)
} else {
modifiedSize = parseInt(originalSize)
}
for (let change of effectChanges.filter(e => e.key.includes("size"))) {
let sizeMod = 0

if (change.value.includes("/")) {
const [numerator, denominator] = change.value.split("/")
sizeMod = parseInt(numerator) / parseInt(denominator)
} else {
sizeMod = parseInt(change.value)
}

// if (size.includes("/")) {
// const [numerator, denominator] = size.split("/")
// newSize = parseInt(numerator) / parseInt(denominator)
// } else {
// newSize = parseInt(size)
// }
switch (change.mode) {
case 0: // CUSTOM
break
case 1: // MULTIPLY
modifiedSize *= sizeMod
break
case 2: // ADD
modifiedSize += sizeMod
break
case 3: // DOWNGRADE
modifiedSize = Math.min(modifiedSize, sizeMod)
break
case 4: // UPGRADE
modifiedSize = Math.max(modifiedSize, sizeMod)
break
case 5: // OVERRIDE
modifiedSize = sizeMod
break
}

// change.value = newSize.toString()
// Calculate string if fraction
if (modifiedSize >= 1) {
newSize = Math.floor(modifiedSize).toString()
} else if (modifiedSize >= 0.5) {
newSize = "1/2";
} else if (modifiedSize >= 0.25) {
newSize = "1/4";
} else if (modifiedSize >= 0.125) {
newSize = "1/8";
} else if (modifiedSize >= 0.0625) {
newSize = "1/16";
} else if (modifiedSize >= 0.03125) {
newSize = "1/32";
}
}

// const result = change.effect.apply(this, change)
// if (result !== null) this.overrides[change.key] = result
// }
this.system.characteristics.size = newSize
}

/* -------------------------------------------- */
Expand Down Expand Up @@ -720,14 +760,14 @@ export class DemonlordActor extends Actor {
let uses = talent.system.uses?.value || 0
const usesmax = talent.system.uses?.max || 0
if (usesmax > 0 && uses < usesmax)
return await talent.update({'data.uses.value': ++uses, 'data.addtonextroll': setActive}, {parent: this})
return await talent.update({'system.uses.value': ++uses, 'system.addtonextroll': setActive}, {parent: this})
}

async deactivateTalent(talent, decrement = 0, onlyTemporary = false) {
if (onlyTemporary && !talent.system.uses?.max) return
let uses = talent.system.uses?.value || 0
uses = Math.max(0, uses - decrement)
return await talent.update({'data.uses.value': uses, 'data.addtonextroll': false}, {parent: this})
return await talent.update({'system.uses.value': uses, 'system.addtonextroll': false}, {parent: this})
}

/* -------------------------------------------- */
Expand All @@ -736,15 +776,15 @@ export class DemonlordActor extends Actor {
await Promise.all(game.user.targets.map(async target => {
const currentDamage = parseInt(target.actor.system.characteristics.health.value)
await target?.actor.update({
'data.characteristics.health.value': currentDamage + damage,
'system.characteristics.health.value': currentDamage + damage,
})
}))
}

async restActor() {
// Reset talent and spell uses
const talentData = this.items.filter(i => i.type === 'talent').map(t => ({_id: t.id, 'data.uses.value': 0}))
const spellData = this.items.filter(i => i.type === 'spell').map(s => ({_id: s.id, 'data.castings.value': 0}))
const talentData = this.items.filter(i => i.type === 'talent').map(t => ({_id: t.id, 'system.uses.value': 0}))
const spellData = this.items.filter(i => i.type === 'spell').map(s => ({_id: s.id, 'system.castings.value': 0}))

await this.updateEmbeddedDocuments('Item', [...talentData, ...spellData])
await this.applyHealing(true)
Expand Down Expand Up @@ -786,7 +826,7 @@ export class DemonlordActor extends Actor {
}

return this.update({
'data.characteristics.health.value': newHp
'system.characteristics.health.value': newHp
})
}

Expand All @@ -801,7 +841,7 @@ export class DemonlordActor extends Actor {
const rank = s.system.rank
const currentMax = s.system.castings.max
const newMax = CONFIG.DL.spelluses[power]?.[rank] ?? 0
if (currentMax !== newMax) diff.push({_id: s.id, 'data.castings.max': newMax})
if (currentMax !== newMax) diff.push({_id: s.id, 'system.castings.max': newMax})
})
if (diff.length > 0) return await this.updateEmbeddedDocuments('Item', diff)
}
Expand Down
10 changes: 5 additions & 5 deletions src/module/actor/sheets/base-actor-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default class DLBaseActorSheet extends ActorSheet {
actor: this.actor,
system: this.actor.system,
effects: true,
generalEffects: prepareActiveEffectCategories(this.actor.effects, true),
generalEffects: prepareActiveEffectCategories(Array.from(this.actor.allApplicableEffects()), true),
effectsOverview: buildOverview(this.actor),
flags: this.actor.flags,
}
Expand Down Expand Up @@ -60,7 +60,7 @@ export default class DLBaseActorSheet extends ActorSheet {
const actorData = sheetData.actor

const actorHasChangeBool = (actor, key) => {
return actor.getEmbeddedCollection('ActiveEffect').filter(e => !e.disabled && e.changes.filter(c => c.key === key && c.value === '1').length > 0).length > 0
return Array.from(actor.allApplicableEffects()).filter(e => !e.disabled && e.changes.filter(c => c.key === key && c.value === '1').length > 0).length > 0
}

const noAttacks = actorHasChangeBool(actorData, 'system.maluses.noAttacks')
Expand Down Expand Up @@ -242,7 +242,7 @@ export default class DLBaseActorSheet extends ActorSheet {
}
if (['action', 'afflictions', 'damage'].includes(div.dataset.type)) {
const type = capitalize(div.dataset.type)
const k = 'data.afflictionsTab.hideAction' + type
const k = 'system.afflictionsTab.hideAction' + type
const v = !this.actor.system.afflictionsTab[`hide${type}`]
await this.actor.update({[k]: v})
}
Expand Down Expand Up @@ -279,7 +279,7 @@ export default class DLBaseActorSheet extends ActorSheet {
const _itemwear = async (ev, bool) => {
const id = $(ev.currentTarget).closest('[data-item-id]').data('itemId')
const item = this.actor.items.get(id)
await item.update({'data.wear': bool}, {parent: this.actor})
await item.update({'system.wear': bool}, {parent: this.actor})
}
html.find('.item-wear').click(async ev => await _itemwear(ev, false))
html.find('.item-wearoff').click(async ev => await _itemwear(ev, true))
Expand Down Expand Up @@ -314,7 +314,7 @@ export default class DLBaseActorSheet extends ActorSheet {
const usesmax = +item.system.castings.max
if (ev.button == 0) uses = uses < usesmax ? uses + 1 : 0
else if (ev.button == 2) uses = uses > 0 ? uses - 1 : 0
await item.update({'data.castings.value': uses}, {parent: this.actor})
await item.update({'system.castings.value': uses}, {parent: this.actor})
})

// Rollable Attributes
Expand Down
22 changes: 11 additions & 11 deletions src/module/actor/sheets/character-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,29 @@ export default class DLCharacterSheet extends DLBaseActorSheet {

// Effects categories
data.ancestryEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'ancestry'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'ancestry'),
)
delete data.ancestryEffects.temporary

data.pathEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'path'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'path'),
)
delete data.pathEffects.temporary

data.talentEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'talent'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'talent'),
)
data.spellEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'spell'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'spell'),
)
data.itemEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => ['armor', 'weapon', 'item'].indexOf(effect.flags?.sourceType) >= 0),
Array.from(this.actor.allApplicableEffects()).filter(effect => ['armor', 'weapon', 'item'].indexOf(effect.flags?.sourceType) >= 0),
)
data.itemEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'creaturerole'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'creaturerole'),
)
data.itemEffects = prepareActiveEffectCategories(
this.actor.effects.filter(effect => effect.flags?.sourceType === 'relic'),
Array.from(this.actor.allApplicableEffects()).filter(effect => effect.flags?.sourceType === 'relic'),
)
this.prepareItems(data)
return data
Expand Down Expand Up @@ -179,7 +179,7 @@ export default class DLCharacterSheet extends DLBaseActorSheet {

await actor
.update({
'data.characteristics.editbar': actor.system.characteristics.editbar,
'system.characteristics.editbar': actor.system.characteristics.editbar,
})
.then(_ => this.render())
})
Expand All @@ -202,7 +202,7 @@ export default class DLCharacterSheet extends DLBaseActorSheet {
if (value <= 0) value = 0
else value--
}
await this.actor.update({ 'data.characteristics.insanity.value': value }).then(_ => this.render())
await this.actor.update({ 'system.characteristics.insanity.value': value }).then(_ => this.render())
})

// Corruption bar click
Expand All @@ -216,7 +216,7 @@ export default class DLCharacterSheet extends DLBaseActorSheet {
if (value <= 0) value = 0
else value--
}
await this.actor.update({ 'data.characteristics.corruption.value': value }).then(_ => this.render())
await this.actor.update({ 'system.characteristics.corruption.value': value }).then(_ => this.render())
})

// Health bar fill
Expand Down Expand Up @@ -281,7 +281,7 @@ export default class DLCharacterSheet extends DLBaseActorSheet {
html
.find('.religion-edit')
.click(async _ =>
await this.actor.update({ 'data.religion.edit': !this.actor.system.religion.edit }).then(() => this.render()),
await this.actor.update({ 'system.religion.edit': !this.actor.system.religion.edit }).then(() => this.render()),
)

// Ammo uses
Expand Down
2 changes: 1 addition & 1 deletion src/module/actor/sheets/creature-sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default class DLCreatureSheet extends DLBaseActorSheet {
const actorData = sheetData.actor

const actorHasChangeBool = (actor, key) => {
return actor.getEmbeddedCollection('ActiveEffect').filter(e => !e.disabled && e.changes.filter(c => c.key === key && c.value === '1').length > 0).length > 0
return Array.from(actor.allApplicableEffects()).filter(e => !e.disabled && e.changes.filter(c => c.key === key && c.value === '1').length > 0).length > 0
}

const noSpecialAttacks = actorHasChangeBool(actorData, 'system.maluses.noSpecialAttacks')
Expand Down
Loading
Loading