Skip to content

Implement mvp party actor#1673

Draft
krbz999 wants to merge 1 commit intodevelopfrom
party-actor
Draft

Implement mvp party actor#1673
krbz999 wants to merge 1 commit intodevelopfrom
party-actor

Conversation

@krbz999
Copy link
Member

@krbz999 krbz999 commented Feb 23, 2026

  • Adds party actor.
  • Deprecates canvas.tokens.performTokenPlacement in favor of canvas.tokens.placeToken to be in line with canvas.regions.placeRegion.
  • Fixed issues with canvas.tokens.#getTokenData which threw errors when items or effect were empty.

Notes

  • I wasn't really able to find a good spot for using canvas.tokens.#getTokenData and don't think it's relevant for this anyhow. We are also not using it anywhere in the system at present.
  • This is a proof of concept for now while we discuss whether we want to add it to 0.11.

TODO

  • Implement basic party sheet.
  • Extend the Actor sidebar and implement game.actors.party as an easy access getter.
  • Add setting to assign "primary party" with context menu options in the sidebar.
  • Disallow creating (any?) items and effects on the party actor.

To test:

Create party actor and hero actor.

const party = await Actor.implementation.create({ type: "party", name: "Party" });
const hero = await Actor.implementation.create({ type: "hero", name: "Hero" });
await party.system.addMembers([hero]);
await party.system.placeMembers();

@krbz999 krbz999 requested a review from JPMeehan February 23, 2026 16:45
@krbz999 krbz999 self-assigned this Feb 23, 2026
@JPMeehan
Copy link
Contributor

JPMeehan commented Feb 23, 2026

  1. RE: performTokenPlacement, we had previously discussed not wanting to do placeToken because it's more likely to be used by core
  2. We already have DrawSteelActors as a subclass for game.actors, just need to add the access point
  3. We've got metadata.invalidActorTypes on the item subclasses as us trying to more broadly accomodate module-added subtypes. I think that's probably sufficient?

@JPMeehan JPMeehan marked this pull request as draft February 23, 2026 17:22

const { HTMLField, SchemaField, TypedObjectField } = foundry.data.fields;

export default class PartyModel extends foundry.abstract.TypeDataModel {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be DrawSteelSystemModel? I don't think it's super likely we end up with any pseudo collections but it does seem expected.

Comment on lines +44 to +54
const update = {};
if (!foundry.utils.hasProperty(data, "prototypeToken.actorLink"))
foundry.utils.setProperty(update, "prototypeToken.actorLink", true);

if (!foundry.utils.hasProperty(data, "prototypeToken.sight.enabled"))
foundry.utils.setProperty(update, "prototypeToken.sight.enabled", false);

if (!foundry.utils.hasProperty(data, "prototypeToken.disposition"))
foundry.utils.setProperty(update, "prototypeToken.disposition", CONST.TOKEN_DISPOSITIONS.FRIENDLY);

if (!foundry.utils.isEmpty(update)) this.parent.updateSource(update);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think foundry.utils.mergeObject(defaultData, data, { insertKeys: false, insertValues: false }) gets us equivalent results while being more maintainable?

Comment on lines +63 to +72
Object.defineProperty(this, "members", {
enumerable: true,
get() {
return Object.entries(this._source.members).reduce((acc, [id, data]) => {
const actor = game.actors.get(id);
if (this.validMember(actor)) acc.set(actor.id, { ...data, actor });
return acc;
}, new foundry.utils.Collection());
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want an a new field for this instead of overwriting the initialized TOF?

* @returns {boolean}
*/
validMember(actor) {
return (actor instanceof foundry.documents.Actor) && ["hero"].includes(actor.type)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the array should be some static property on the constructor

async removeMembers(actors = []) {
const update = {};
actors.forEach(actor => {
if (this.validMember(actor) && this.members.has(actor.id)) update[`-=${actor.id}`] = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we check if it's a valid member first? e.g. if I do a forced type update to turn a hero into an NPC I can no longer use this method to remove them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants