Skip to content

Commit eb6ecd9

Browse files
committed
Standarize the combat turn taking across combat hud and tracker
1 parent e10a985 commit eb6ecd9

File tree

7 files changed

+4301
-4338
lines changed

7 files changed

+4301
-4338
lines changed

module/ui/combat-hud.mjs

+24-63
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,11 @@ export class CombatHUD extends Application {
142142
data.cssClasses = this.options.classes.join(' ');
143143
data.cssId = this.options.id;
144144
data.isCompact = game.settings.get(SYSTEM, SETTINGS.optionCombatHudCompact);
145-
data.isGM = game.user.isGM;
146145

147146
const opacity = game.settings.get(SYSTEM, SETTINGS.optionCombatHudOpacity) / 100;
148147
data.additionalStyle = this._getAdditionalStyle(opacity);
149148

150149
const ordering = game.settings.get(SYSTEM, SETTINGS.optionCombatHudActorOrdering);
151-
152150
data.npcs = [];
153151
data.characters = [];
154152

@@ -174,14 +172,9 @@ export class CombatHUD extends Application {
174172

175173
const NPCTurnsLeftMode = game.settings.get(SYSTEM, SETTINGS.optionCombatHudShowNPCTurnsLeftMode);
176174

177-
const currentTurn = game.combat.getCurrentTurn();
178-
const turnsLeft = ui.combat.countTurnsLeft(game.combat);
179-
// const round = game.combat.round;
180-
181175
/** @type FUCombat **/
182176
const combat = game.combat;
183-
data.turnStarted = combat.isTurnStarted;
184-
data.hasCombatStarted = game.combat.started;
177+
combat.populateData(data);
185178

186179
for (const combatant of game.combat.combatants) {
187180
if (!combatant.actor || !combatant.token) continue;
@@ -191,12 +184,15 @@ export class CombatHUD extends Application {
191184
id: combatant.id,
192185
name: combatant.name,
193186
actor: combatant.actor,
187+
isOwner: combatant.isOwner,
188+
totalTurns: combatant.totalTurns,
194189
token: combatant.token,
195190
effects: activeEffects,
196-
img: game.settings.get(SYSTEM, SETTINGS.optionCombatHudPortrait) === 'token' ?
197-
// token._source should contain the most current version of the token's texture.
198-
combatant.token._source.texture.src :
199-
combatant.actor.img,
191+
img:
192+
game.settings.get(SYSTEM, SETTINGS.optionCombatHudPortrait) === 'token'
193+
? // token._source should contain the most current version of the token's texture.
194+
combatant.token._source.texture.src
195+
: combatant.actor.img,
200196
trackedResourcePart1: trackedResourcePart1,
201197
trackedResourcePart2: trackedResourcePart2,
202198
trackedResourcePart3: trackedResourcePart3,
@@ -238,7 +234,6 @@ export class CombatHUD extends Application {
238234

239235
// Ensure shouldEffectsMarquee is false if effectsMarqueeDuration is over 9000
240236
actorData.shouldEffectsMarquee = actorData.effects.length > maxEffectsBeforeMarquee && effectsMarqueeDuration < 9000;
241-
242237
actorData.effectsMarqueeDuration = effectsMarqueeDuration;
243238

244239
const marqueeDirection = game.settings.get(SYSTEM, SETTINGS.optionCombatHudEffectsMarqueeMode);
@@ -262,29 +257,19 @@ export class CombatHUD extends Application {
262257
});
263258
}
264259

265-
actorData.isOwner = combatant.isOwner;
266260
actorData.order = order;
267261

268-
actorData.totalTurns = combatant.totalTurns;
269262
if (NPCTurnsLeftMode === 'never') {
270263
actorData.totalTurns = 1;
271264
} else if (NPCTurnsLeftMode === 'only-studied' && !this._isNPCStudied(combatant.token)) {
272265
actorData.totalTurns = 1;
273266
}
274267

275-
actorData.turnsLeft = turnsLeft[combatant.id] ?? 0;
276-
277268
if (combatant.token.disposition === foundry.CONST.TOKEN_DISPOSITIONS.FRIENDLY) {
278-
actorData.isCurrentTurn = currentTurn === 'friendly';
279269
data.characters.push(actorData);
280270
} else {
281-
actorData.isCurrentTurn = currentTurn === 'hostile';
282271
data.npcs.push(actorData);
283272
}
284-
285-
// Decides whether combatant can (start turn | take turn)
286-
actorData.isCurrentCombatant = combat.isCurrentCombatant(combatant);
287-
actorData.hasTurns = turnsLeft[combatant.id] && actorData.isCurrentTurn;
288273
}
289274

290275
data.characters.sort((a, b) => a.order - b.order);
@@ -332,7 +317,7 @@ export class CombatHUD extends Application {
332317
dragButton.on('drag', this._doHudDrag.bind(this));
333318
dragButton.on('dragend', this._doHudDrop.bind(this));
334319

335-
if(navigator.userAgent.toLowerCase().includes('firefox')) {
320+
if (navigator.userAgent.toLowerCase().includes('firefox')) {
336321
$(window.document).on('dragover', this._fireFoxDragWorkaround.bind(this));
337322
}
338323

@@ -395,7 +380,7 @@ export class CombatHUD extends Application {
395380

396381
const draggedPosition = {
397382
x: offset.left,
398-
y: positionFromTop ? offset.top : $(window).height() - offset.top - height
383+
y: positionFromTop ? offset.top : $(window).height() - offset.top - height,
399384
};
400385
game.settings.set(SYSTEM, SETTINGS.optionCombatHudDraggedPosition, draggedPosition);
401386
}
@@ -739,33 +724,28 @@ export class CombatHUD extends Application {
739724

740725
_onUpdateToken(token, changes) {
741726
// Is the updated token in the current combat?
742-
if(!game.combat?.combatants.some(c => c.token.uuid === token.uuid)) {
727+
if (!game.combat?.combatants.some((c) => c.token.uuid === token.uuid)) {
743728
return;
744729
}
745730

746731
// Are any of the changes relevant to the Combat HUD?
747732
if (
748733
foundry.utils.hasProperty(changes, 'name') ||
749-
foundry.utils.hasProperty(changes, 'actorId') ||
750-
foundry.utils.hasProperty(changes, 'disposition') ||
751-
(
752-
game.settings.get(SYSTEM, 'optionCombatHudPortrait') === 'token' &&
753-
foundry.utils.hasProperty(changes, 'texture.src')
754-
)
734+
foundry.utils.hasProperty(changes, 'actorId') ||
735+
foundry.utils.hasProperty(changes, 'disposition') ||
736+
(game.settings.get(SYSTEM, 'optionCombatHudPortrait') === 'token' && foundry.utils.hasProperty(changes, 'texture.src'))
755737
) {
756738
this._onUpdateHUD();
757739
}
758740
}
759741

760742
_onUpdateActor(actor, changes) {
761743
// Is the updated actor in the current combat?
762-
if(!game.combat?.combatants.some(c => c.actor.uuid === actor.uuid)) {
744+
if (!game.combat?.combatants.some((c) => c.actor.uuid === actor.uuid)) {
763745
return;
764746
}
765747

766-
const systemResources = [
767-
'hp', 'mp', 'ip', 'fp', 'exp', 'zenit'
768-
];
748+
const systemResources = ['hp', 'mp', 'ip', 'fp', 'exp', 'zenit'];
769749

770750
const trackedResources = [
771751
game.settings.get(SYSTEM, SETTINGS.optionCombatHudTrackedResource1),
@@ -775,10 +755,7 @@ export class CombatHUD extends Application {
775755
];
776756

777757
// Are any of the changes relevant to the Combat HUD?
778-
if (
779-
trackedResources.filter(r => systemResources.includes(r))
780-
.some(r => foundry.utils.hasProperty(changes, `system.resources.${r}`))
781-
) {
758+
if (trackedResources.filter((r) => systemResources.includes(r)).some((r) => foundry.utils.hasProperty(changes, `system.resources.${r}`))) {
782759
this._onUpdateHUD();
783760
}
784761
}
@@ -793,10 +770,7 @@ export class CombatHUD extends Application {
793770

794771
_onModifyItem(item, changes) {
795772
// Is the item owned by an actor in the current combat?
796-
if (
797-
item.parent?.documentName !== 'Actor' ||
798-
!game.combat?.combatants.some(c => c.actor.uuid === item.parent.uuid)
799-
) {
773+
if (item.parent?.documentName !== 'Actor' || !game.combat?.combatants.some((c) => c.actor.uuid === item.parent.uuid)) {
800774
return;
801775
}
802776

@@ -809,20 +783,11 @@ export class CombatHUD extends Application {
809783

810784
// Are any of the changes relevant to the combat HUD?
811785
if (
812-
trackedResources.includes('zeropower') &&
813-
item.type === 'optionalFeature' &&
814-
(
815-
item.system.optionalType === 'projectfu.zeroPower') ||
816-
// The optionalType can theoretically change, so make sure to check for it.
817-
foundry.utils.hasProperty(changes, 'system.optionalType'
818-
)
819-
&&
820-
(
786+
(trackedResources.includes('zeropower') && item.type === 'optionalFeature' && item.system.optionalType === 'projectfu.zeroPower') ||
787+
// The optionalType can theoretically change, so make sure to check for it.
788+
(foundry.utils.hasProperty(changes, 'system.optionalType') &&
821789
// Progress changes aren't relevant during create/delete hooks.
822-
!changes ||
823-
foundry.utils.hasProperty(changes, 'system.data.progress.current') ||
824-
foundry.utils.hasProperty(changes, 'system.data.progress.max')
825-
)
790+
(!changes || foundry.utils.hasProperty(changes, 'system.data.progress.current') || foundry.utils.hasProperty(changes, 'system.data.progress.max')))
826791
) {
827792
this._onUpdateHUD();
828793
}
@@ -831,17 +796,13 @@ export class CombatHUD extends Application {
831796
_onModifyActiveEffect(activeEffect, changes) {
832797
if (
833798
// Is the active effect targeting an actor in the current combat?
834-
!(
835-
activeEffect.target &&
836-
game.combat?.combatants.some(c => c.actor.uuid === activeEffect.target.uuid)
837-
)
838-
&&
799+
!(activeEffect.target && game.combat?.combatants.some((c) => c.actor.uuid === activeEffect.target.uuid)) &&
839800
// Did the transfer property change on an effect on an item owned by an actor in the current combat?
840801
!(
841802
activeEffect.parent?.documentName === 'Item' &&
842803
activeEffect.parent.parent?.documentName === 'Actor' &&
843804
foundry.utils.hasProperty(changes, 'transfer') &&
844-
game.combat?.combatants.some(c => c.actor.uuid === activeEffect.parent.parent.uuid)
805+
game.combat?.combatants.some((c) => c.actor.uuid === activeEffect.parent.parent.uuid)
845806
)
846807
) {
847808
return;

module/ui/combat-tracker.mjs

+1-29
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,8 @@ export class FUCombatTracker extends CombatTracker {
2323
/** @type FUCombat **/
2424
const combat = data.combat;
2525
if (combat) {
26-
data.turnStarted = combat.isTurnStarted;
27-
// The current combatant, if any
28-
data.combatant = combat.combatant;
29-
// What faction's turn it is
30-
data.currentTurn = combat.getCurrentTurn();
31-
// ID : Turns Left
32-
data.turnsLeft = this.countTurnsLeft(combat);
26+
combat.populateData(data);
3327
// ID : Total Turns
34-
data.totalTurns = combat.combatants.reduce((agg, combatant) => {
35-
agg[combatant.id] = combatant.totalTurns;
36-
return agg;
37-
}, {});
3828
data.turns = data.turns?.map((turn) => {
3929
turn.statusEffects = combat.combatants.get(turn.id)?.actor.temporaryEffects.map((effect) => ({
4030
name: effect.name,
@@ -47,27 +37,10 @@ export class FUCombatTracker extends CombatTracker {
4737
console.error(`Found no available turns on combat ${combat}`);
4838
}
4939
data.factions = await this.getFactions(data.turns, combat);
50-
// if (data.factions.friendly.length === 0 || data.factions.friendly.length === 0) {
51-
// console.error(`Factions were not set up on combat ${combat}`);
52-
// }
53-
// TODO: Set option to toggle?
54-
data.outOfTurn = false;
5540
}
5641
return data;
5742
}
5843

59-
countTurnsLeft(combat) {
60-
const countTurnsTaken = combat.currentRoundTurnsTaken.reduce((agg, currentValue) => {
61-
agg[currentValue] = (agg[currentValue] ?? 0) + 1;
62-
return agg;
63-
}, {});
64-
65-
return combat.combatants.reduce((agg, combatant) => {
66-
agg[combatant.id] = combatant.totalTurns - (countTurnsTaken[combatant.id] ?? 0);
67-
return agg;
68-
}, {});
69-
}
70-
7144
/**
7245
* @param {jQuery} html
7346
*/
@@ -132,7 +105,6 @@ export class FUCombatTracker extends CombatTracker {
132105
return turns.reduce(
133106
(agg, combatantData) => {
134107
const combatant = combat.combatants.get(combatantData.id);
135-
combatant.startedTurn = combat.isCurrentCombatant(combatant);
136108
if (combatant.token.disposition === foundry.CONST.TOKEN_DISPOSITIONS.FRIENDLY) {
137109
agg.friendly.push(combatantData);
138110
} else {

module/ui/combat.mjs

+46
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ export class CombatEvent {
5858
* @remarks {@link https://foundryvtt.com/api/interfaces/client.CombatHistoryData.html}
5959
*/
6060

61+
/**
62+
* @typedef CombatRenderData
63+
* @description Used by component rendering (such as the combat tracker, combat hud)
64+
* @property {Boolean} turnStarted
65+
* @property {Combatant} combatant
66+
* @property {Boolean} hasCombatStarted
67+
* @property turnsLeft
68+
* @property currentTurn The faction whose turn it is
69+
*/
70+
6171
/**
6272
* @typedef Combat
6373
* @property {Combatant[]} turns
@@ -345,6 +355,42 @@ export class FUCombat extends Combat {
345355
return this.combatant != null;
346356
}
347357

358+
/**
359+
* @param {CombatRenderData} data Used by the rendering components
360+
*/
361+
populateData(data) {
362+
data.hasCombatStarted = this.started;
363+
data.totalTurns = this.combatants.reduce((agg, combatant) => {
364+
agg[combatant.id] = combatant.totalTurns;
365+
return agg;
366+
}, {});
367+
data.turnStarted = this.isTurnStarted;
368+
// The current combatant, if any
369+
data.combatant = this.combatant;
370+
// ID : Turns Left
371+
data.turnsLeft = this.countTurnsLeft();
372+
// What faction's turn it is
373+
data.currentTurn = this.getCurrentTurn();
374+
data.outOfTurn = false;
375+
data.round = this.round;
376+
data.isGM = game.user.isGM;
377+
}
378+
379+
/**
380+
* @returns {{}}
381+
*/
382+
countTurnsLeft() {
383+
const countTurnsTaken = this.currentRoundTurnsTaken.reduce((agg, currentValue) => {
384+
agg[currentValue] = (agg[currentValue] ?? 0) + 1;
385+
return agg;
386+
}, {});
387+
388+
return this.combatants.reduce((agg, combatant) => {
389+
agg[combatant.id] = combatant.totalTurns - (countTurnsTaken[combatant.id] ?? 0);
390+
return agg;
391+
}, {});
392+
}
393+
348394
/**
349395
* @param {FUCombatant} combatant
350396
* @returns {Boolean} True if the given combatant is that has started their turn

0 commit comments

Comments
 (0)