Skip to content

Commit 9116863

Browse files
committed
Convert distribute coins to appv2
1 parent 83ddc7e commit 9116863

File tree

5 files changed

+91
-91
lines changed

5 files changed

+91
-91
lines changed

src/module/actor/loot/sheet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { PhysicalItemPF2e } from "@item";
99
import { TextEditorPF2e } from "@system/text-editor.ts";
1010
import { htmlClosest, htmlQuery } from "@util";
1111
import { ActorSheetPF2e } from "../sheet/base.ts";
12-
import { DistributeCoinsPopup } from "../sheet/popups/distribute-coins-popup.ts";
12+
import { DistributeCoinsDialog } from "../sheet/popups/distribute-coins-dialog.ts";
1313
import { LootNPCsPopup } from "../sheet/popups/loot-npcs-popup.ts";
1414
import type { LootSystemSchema } from "./data.ts";
1515

@@ -59,7 +59,7 @@ export class LootSheetPF2e<TActor extends LootPF2e> extends ActorSheetPF2e<TActo
5959
htmlQuery(html, "[data-sidebar-buttons]")?.addEventListener("click", (event) => {
6060
const button = htmlClosest(event.target, "button[data-action]");
6161
if (button?.dataset.action === "split-coins") {
62-
new DistributeCoinsPopup(this.actor).render(true);
62+
new DistributeCoinsDialog({ actor: this.actor }).render(true);
6363
} else if (button?.dataset.action === "loot-npcs") {
6464
if (canvas.tokens.controlled.some((token) => token.actor?.id !== this.actor.id)) {
6565
new LootNPCsPopup(this.actor).render(true);

src/module/actor/party/sheet.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isReallyPC } from "@actor/helpers.ts";
55
import { ActorSheetPF2e } from "@actor/sheet/base.ts";
66
import type { ActorSheetDataPF2e, ActorSheetRenderOptionsPF2e } from "@actor/sheet/data-types.ts";
77
import { condenseSenses } from "@actor/sheet/helpers.ts";
8-
import { DistributeCoinsPopup } from "@actor/sheet/popups/distribute-coins-popup.ts";
8+
import { DistributeCoinsDialog } from "@actor/sheet/popups/distribute-coins-dialog.ts";
99
import type { ActorSheetOptions } from "@client/appv1/sheets/actor-sheet.d.mts";
1010
import type { DropCanvasData } from "@client/helpers/hooks.d.mts";
1111
import type { ActorUUID } from "@common/documents/_module.d.mts";
@@ -408,7 +408,7 @@ class PartySheetPF2e extends ActorSheetPF2e<PartyPF2e> {
408408
}
409409

410410
htmlQuery(html, "button[data-action=distribute-coins]")?.addEventListener("click", () => {
411-
new DistributeCoinsPopup(this.actor, { recipients: this.actor.members }).render(true);
411+
new DistributeCoinsDialog({ actor: this.actor, recipients: this.actor.members }).render(true);
412412
});
413413

414414
htmlQuery(html, "[data-action=clear-exploration]")?.addEventListener("click", async () => {
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,69 @@
11
import type { ActorPF2e, CharacterPF2e } from "@actor";
22
import { Coins } from "@item/physical/helpers.ts";
33
import { ChatMessagePF2e } from "@module/chat-message/document.ts";
4-
import appv1 = foundry.appv1;
54

6-
interface PopupData extends appv1.api.FormApplicationData<ActorPF2e> {
7-
selection?: string[];
8-
actorInfo?: {
9-
id: string;
10-
name: string;
11-
checked: boolean;
12-
}[];
13-
}
5+
/** Allows the distribution and split of coins to multiple players */
6+
export class DistributeCoinsDialog extends fa.api.HandlebarsApplicationMixin(fa.api.ApplicationV2) {
7+
constructor(
8+
options: Partial<DistributeCoinsConfiguration> & Required<Pick<DistributeCoinsConfiguration, "actor">>,
9+
) {
10+
super(options);
11+
this.actor = options.actor;
12+
}
1413

15-
interface PopupFormData extends FormData {
16-
actorIds: string[];
17-
breakCoins: boolean;
18-
}
14+
static override DEFAULT_OPTIONS: DeepPartial<DistributeCoinsConfiguration> = {
15+
id: "distribute-coins",
16+
tag: "form",
17+
window: {
18+
title: "Distribute Coins",
19+
contentClasses: ["standard-form"],
20+
},
21+
form: {
22+
closeOnSubmit: true,
23+
handler: DistributeCoinsDialog.#onSubmit,
24+
},
25+
};
1926

20-
/**
21-
* @category Other
22-
*/
23-
export class DistributeCoinsPopup extends appv1.api.FormApplication<ActorPF2e, DistributeCoinsOptions> {
24-
constructor(actor: ActorPF2e, options: Partial<DistributeCoinsOptions> = {}) {
25-
super(actor, options);
26-
}
27+
static override PARTS = {
28+
base: { template: "systems/pf2e/templates/actors/distribute-coins.hbs", root: true },
29+
};
2730

28-
static override get defaultOptions(): appv1.api.FormApplicationOptions {
29-
const options = super.defaultOptions;
30-
options.id = "distribute-coins";
31-
options.classes = [];
32-
options.title = "Distribute Coins";
33-
options.template = "systems/pf2e/templates/actors/distribute-coins.hbs";
34-
options.width = "auto";
35-
return options;
36-
}
31+
actor: ActorPF2e;
32+
declare options: DistributeCoinsConfiguration;
3733

38-
override async getData(options?: Partial<DistributeCoinsOptions>): Promise<PopupData> {
39-
const sheetData: PopupData = await super.getData(options);
40-
const playerActors = (options?.recipients ?? game.actors.contents).filter(
34+
override async _prepareContext(options: fa.ApplicationRenderOptions): Promise<DistributeCoinsContext> {
35+
const data = await super._prepareContext(options);
36+
const playerActors = (this.options.recipients ?? game.actors.contents).filter(
4137
(a) =>
4238
a.hasPlayerOwner &&
4339
a.isOfType("character") &&
4440
!a.isToken &&
4541
!a.system.traits.value.some((t) => ["minion", "eidolon"].includes(t)),
4642
);
47-
sheetData.actorInfo = playerActors.map((a) => ({
48-
id: a.id,
49-
name: a.name,
50-
checked: game.users.players.some((u) => u.active && u.character?.id === a.id),
51-
}));
52-
53-
return sheetData;
43+
return {
44+
...data,
45+
rootId: this.id,
46+
actorInfo: playerActors.map((a) => ({
47+
id: a.id,
48+
name: a.name,
49+
checked: game.users.players.some((u) => u.active && u.character?.id === a.id),
50+
})),
51+
};
5452
}
5553

56-
override async _updateObject(_event: Event, formData: Record<string, unknown> & PopupFormData): Promise<void> {
57-
const thisActor = this.object;
58-
const selectedActors: CharacterPF2e[] = formData.actorIds.flatMap((actorId) => {
54+
static async #onSubmit(
55+
this: DistributeCoinsDialog,
56+
_event: Event,
57+
form: HTMLFormElement,
58+
formData: fa.ux.FormDataExtended,
59+
) {
60+
// Get actor ids, we need to get it directly since the DOM may not give back an array if only one
61+
const actor = this.actor;
62+
const actorIds: string[] = Array.from(form.elements).flatMap((element) =>
63+
element instanceof HTMLInputElement && element.name === "actorIds" && element.checked ? element.value : [],
64+
);
65+
66+
const selectedActors: CharacterPF2e[] = actorIds.flatMap((actorId) => {
5967
const maybeActor = game.actors.get(actorId);
6068
return maybeActor?.isOfType("character") ? maybeActor : [];
6169
});
@@ -66,21 +74,21 @@ export class DistributeCoinsPopup extends appv1.api.FormApplication<ActorPF2e, D
6674
}
6775

6876
const coinShare = new Coins();
69-
if (formData.breakCoins) {
70-
const thisActorCopperValue = thisActor.inventory.coins.copperValue;
77+
if (formData.object.breakCoins) {
78+
const thisActorCopperValue = actor.inventory.coins.copperValue;
7179
const copperToDistribute = Math.trunc(thisActorCopperValue / playerCount);
7280
// return if there is nothing to distribute
7381
if (copperToDistribute === 0) {
7482
ui.notifications.warn("Nothing to distribute");
7583
return;
7684
}
77-
thisActor.inventory.removeCoins({ cp: copperToDistribute * playerCount });
85+
actor.inventory.removeCoins({ cp: copperToDistribute * playerCount });
7886
coinShare.cp = copperToDistribute % 10;
7987
coinShare.sp = Math.trunc(copperToDistribute / 10) % 10;
8088
coinShare.gp = Math.trunc(copperToDistribute / 100) % 10;
8189
coinShare.pp = Math.trunc(copperToDistribute / 1000);
8290
} else {
83-
const thisActorCurrency = thisActor.inventory.coins;
91+
const thisActorCurrency = actor.inventory.coins;
8492
coinShare.pp = Math.trunc(thisActorCurrency.pp / playerCount);
8593
coinShare.cp = Math.trunc(thisActorCurrency.cp / playerCount);
8694
coinShare.gp = Math.trunc(thisActorCurrency.gp / playerCount);
@@ -92,15 +100,15 @@ export class DistributeCoinsPopup extends appv1.api.FormApplication<ActorPF2e, D
92100
}
93101

94102
const coinsToRemove = coinShare.scale(playerCount);
95-
thisActor.inventory.removeCoins(coinsToRemove, { byValue: false });
103+
actor.inventory.removeCoins(coinsToRemove, { byValue: false });
96104
}
97105
let message = `Distributed `;
98106
if (coinShare.pp !== 0) message += `${coinShare.pp} pp `;
99107
if (coinShare.gp !== 0) message += `${coinShare.gp} gp `;
100108
if (coinShare.sp !== 0) message += `${coinShare.sp} sp `;
101109
if (coinShare.cp !== 0) message += `${coinShare.cp} cp `;
102110
const each = playerCount > 1 ? "each " : "";
103-
message += `${each}from ${thisActor.name} to `;
111+
message += `${each}from ${actor.name} to `;
104112
for (const actor of selectedActors) {
105113
await actor.inventory.addCoins(coinShare);
106114
const index = selectedActors.indexOf(actor);
@@ -114,21 +122,19 @@ export class DistributeCoinsPopup extends appv1.api.FormApplication<ActorPF2e, D
114122
content: message,
115123
});
116124
}
117-
118-
/** Prevent Foundry from converting the actor IDs to boolean values */
119-
protected override async _onSubmit(
120-
event: Event,
121-
options: appv1.api.OnSubmitFormOptions = {},
122-
): Promise<Record<string, unknown> | false> {
123-
const actorIds: string[] = Array.from(this.form.elements).flatMap((element) =>
124-
element instanceof HTMLInputElement && element.name === "actorIds" && element.checked ? element.value : [],
125-
);
126-
options.updateData = fu.mergeObject(options.updateData ?? {}, { actorIds: actorIds });
127-
return super._onSubmit(event, options);
128-
}
129125
}
130126

131-
interface DistributeCoinsOptions extends appv1.api.FormApplicationOptions {
127+
interface DistributeCoinsConfiguration extends fa.api.DialogV2Configuration {
128+
actor: ActorPF2e;
132129
/** An optional initial list of recipients to receive coins */
133130
recipients?: ActorPF2e[];
134131
}
132+
133+
interface DistributeCoinsContext extends fa.ApplicationRenderContext {
134+
rootId: string;
135+
actorInfo: {
136+
id: string;
137+
name: string;
138+
checked: boolean;
139+
}[];
140+
}

static/lang/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6685,6 +6685,7 @@
66856685
}
66866686
},
66876687
"loot": {
6688+
"AllowConversion": "Allow coin type conversion",
66886689
"BuySubtitle": "Buy item",
66896690
"DepositMessage": "{depositor} deposits {quantity} × {item} in {container}.",
66906691
"DepositSubtitle": "Deposit item",
Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
1-
<form class="loot-actor-popup" autocomplete="off" onsubmit="event.preventDefault();">
2-
<div class="checkboxes">
3-
<h1>{{localize "PF2E.loot.SplitCoinsPopupHeader"}}</h1>
4-
{{#each actorInfo as |info|}}
5-
<p>
6-
<label>
7-
<input type="checkbox" name="actorIds" value="{{info.id}}" {{checked info.checked}} />
8-
<span>{{info.name}}</span>
9-
</label>
10-
</p>
11-
{{/each}}
12-
<hr />
13-
<p>
14-
<label class="break-coins" for="breakCoins">
15-
<input type="checkbox" name="breakCoins" />
16-
<span>Allow coin type conversion</span>
17-
</label>
18-
</p>
19-
</div>
20-
<p>
21-
<button class="confirm-button" type="submit">
22-
<i class="fa-regular fa-floppy-disk"></i>
23-
{{localize "PF2E.loot.SplitCoinsLabel"}}
24-
</button>
25-
</p>
26-
</form>
1+
<fieldset>
2+
<legend>{{localize "PF2E.loot.SplitCoinsPopupHeader"}}</legend>
3+
{{#each actorInfo as |info|}}
4+
<label>
5+
<input type="checkbox" name="actorIds" value="{{info.id}}" {{checked info.checked}} />
6+
<span>{{info.name}}</span>
7+
</label>
8+
{{/each}}
9+
</fieldset>
10+
<div class="form-group">
11+
<label for="{{rootId}}-breakCoins">{{localize "PF2E.loot.AllowConversion"}}</label>
12+
<input type="checkbox" name="breakCoins" id="{{rootId}}-breakCoins"/>
13+
</div>
14+
<div class="form-footer">
15+
<button type="submit">
16+
<i class="fa-regular fa-floppy-disk"></i>
17+
{{localize "PF2E.loot.SplitCoinsLabel"}}
18+
</button>
19+
</div>

0 commit comments

Comments
 (0)