import type { ConfiguredCombatant } from "#configuration"; import type { Identity, InexactPartial, Merge } from "#utils"; import type { documents } from "#client/client.d.mts"; import type Document from "#common/abstract/document.d.mts"; import type { DataSchema } from "#common/data/fields.d.mts"; import type BaseCombatant from "#common/documents/combatant.d.mts"; import fields = foundry.data.fields; declare namespace Combatant { /** * The document's name. */ type Name = "Combatant"; /** * The context used to create a `Combatant`. */ interface ConstructionContext extends Document.ConstructionContext {} /** * The documents embedded within `Combatant`. */ type Hierarchy = Readonly>; /** * The implementation of the `Combatant` document instance configured through `CONFIG.Combatant.documentClass` in Foundry and * {@linkcode DocumentClassConfig} or {@link ConfiguredCombatant | `fvtt-types/configuration/ConfiguredCombatant`} in fvtt-types. */ type Implementation = Document.ImplementationFor; /** * The implementation of the `Combatant` document configured through `CONFIG.Combatant.documentClass` in Foundry and * {@linkcode DocumentClassConfig} in fvtt-types. */ type ImplementationClass = Document.ImplementationClassFor; /** * A document's metadata is special information about the document ranging anywhere from its name, * whether it's indexed, or to the permissions a user has over it. */ interface Metadata extends Merge< Document.Metadata.Default, Readonly<{ name: "Combatant"; collection: "combatants"; label: string; labelPlural: string; isEmbedded: true; hasTypeData: true; schemaVersion: string; permissions: Metadata.Permissions; }> > {} namespace Metadata { /** * The permissions for whether a certain user can create, update, or delete this document. */ interface Permissions { create: "OWNER"; update(user: User.Internal.Implementation, doc: Implementation, data: UpdateData): boolean; delete: "OWNER"; } } /** * Allowed subtypes of `Combatant`. This is configured through various methods. Modern Foundry * recommends registering using [Data Models](https://foundryvtt.com/article/system-data-models/) * under {@linkcode CONFIG.Combatant.dataModels}. This corresponds to * fvtt-type's {@linkcode DataModelConfig}. * * Subtypes can also be registered through a `template.json` though this is discouraged. * The corresponding fvtt-type configs are {@linkcode SourceConfig} and * {@linkcode DataConfig}. */ type SubType = foundry.Game.Model.TypeNames<"Combatant">; /** * `ConfiguredSubType` represents the subtypes a user explicitly registered. This excludes * subtypes like the Foundry builtin subtype `"base"` and the catch-all subtype for arbitrary * module subtypes `${string}.${string}`. * * @see {@link SubType} for more information. */ type ConfiguredSubType = Document.ConfiguredSubTypeOf<"Combatant">; /** * `Known` represents the types of `Combatant` that a user explicitly registered. * * @see {@link ConfiguredSubType} for more information. */ type Known = Combatant.OfType; /** * `OfType` returns an instance of `Combatant` with the corresponding type. This works with both the * builtin `Combatant` class or a custom subclass if that is set up in * {@link ConfiguredCombatant | `fvtt-types/configuration/ConfiguredCombatant`}. */ type OfType = Document.Internal.DiscriminateSystem; /** @internal */ interface _OfType extends Identity<{ [Type in SubType]: Type extends unknown ? ConfiguredCombatant extends { document: infer Document } ? Document : // eslint-disable-next-line @typescript-eslint/no-restricted-types Combatant : never; }> {} /** * `SystemOfType` returns the system property for a specific `Combatant` subtype. */ type SystemOfType = Document.Internal.SystemOfType; /** * @internal */ interface _ModelMap extends Document.Internal.ModelMap {} /** * @internal */ interface _SystemMap extends Document.Internal.SystemMap {} /** * A document's parent is something that can contain it. * For example an `Item` can be contained by an `Actor` which makes `Actor` one of its possible parents. * * `Combatant` requires a parent so `null` is not an option here. */ type Parent = Combat.Implementation; /** * A document's descendants are any child documents, grandchild documents, etc. * This is a union of all instances, or never if the document doesn't have any descendants. */ type Descendant = never; /** * A document's descendants are any child documents, grandchild documents, etc. * This is a union of all classes, or never if the document doesn't have any descendants. */ type DescendantClass = never; /** * Types of `CompendiumCollection` this document might be contained in. * Note that `this.pack` will always return a string; this is the type for `game.packs.get(this.pack)` * * Will be `never` if cannot be contained in a `CompendiumCollection`. */ // Note: Takes any document in the heritage chain (i.e. itself or any parent, transitive or not) that can be contained in a compendium. type Pack = never; /** * An embedded document is a document contained in another. * For example an `Item` can be contained by an `Actor` which means `Item` can be embedded in `Actor`. * * If this is `never` it is because there are no embeddable documents (or there's a bug!). */ type Embedded = never; /** * The name of the world or embedded collection this document can find itself in. * For example an `Item` is always going to be inside a collection with a key of `items`. * This is a fixed string per document type and is primarily useful for {@link ClientDocumentMixin | `Descendant Document Events`}. */ type ParentCollectionName = Metadata["collection"]; /** * The world collection that contains this document type. Will be `never` if none exists. */ type CollectionClass = never; /** * The world collection that contains this document type. Will be `never` if none exists. */ type Collection = never; /** * An instance of `Combatant` that comes from the database but failed validation meaning that * its `system` and `_source` could theoretically be anything. */ type Invalid = Document.Internal.Invalid; /** * An instance of `Combatant` that comes from the database. */ type Stored = Document.Internal.Stored>; /** * The data put in {@link Combatant._source | `Combatant#_source`}. This data is what was * persisted to the database and therefore it must be valid JSON. * * For example a {@link fields.SetField | `SetField`} is persisted to the database as an array * but initialized as a {@linkcode Set}. */ interface Source extends fields.SchemaField.SourceData {} /** * The data necessary to create a document. Used in places like {@linkcode Combatant.create} * and {@link Combatant | `new Combatant(...)`}. * * For example a {@link fields.SetField | `SetField`} can accept any {@linkcode Iterable} * with the right values. This means you can pass a `Set` instance, an array of values, * a generator, or any other iterable. */ interface CreateData extends fields.SchemaField.CreateData {} /** * The data after a {@link foundry.abstract.Document | `Document`} has been initialized, for example * {@link Combatant.name | `Combatant#name`}. * * This is data transformed from {@linkcode Combatant.Source} and turned into more * convenient runtime data structures. For example a {@link fields.SetField | `SetField`} is * persisted to the database as an array of values but at runtime it is a `Set` instance. */ interface InitializedData extends fields.SchemaField.InitializedData {} /** * The data used to update a document, for example {@link Combatant.update | `Combatant#update`}. * It is a distinct type from {@link Combatant.CreateData | `DeepPartial`} because * it has different rules for `null` and `undefined`. */ interface UpdateData extends fields.SchemaField.UpdateData {} /** * The schema for {@linkcode Combatant}. This is the source of truth for how an Combatant document * must be structured. * * Foundry uses this schema to validate the structure of the {@linkcode Combatant}. For example * a {@link fields.StringField | `StringField`} will enforce that the value is a string. More * complex fields like {@link fields.SetField | `SetField`} goes through various conversions * starting as an array in the database, initialized as a set, and allows updates with any * iterable. */ interface Schema extends DataSchema { /** * The _id which uniquely identifies this Combatant embedded document * @defaultValue `null` */ _id: fields.DocumentIdField; /** @defaultValue `"base"` */ type: fields.DocumentTypeField; system: fields.TypeDataField; /** * The _id of an Actor associated with this Combatant * @defaultValue `null` */ actorId: fields.ForeignDocumentField; /** * The _id of a Token associated with this Combatant * @defaultValue `null` */ tokenId: fields.ForeignDocumentField; /** * @defaultValue `null` */ sceneId: fields.ForeignDocumentField; /** * A customized name which replaces the name of the Token in the tracker * @defaultValue `undefined` */ name: fields.StringField<{ label: "COMBAT.CombatantName"; textSearch: true }>; /** * A customized image which replaces the Token image in the tracker * @defaultValue `null` */ img: fields.FilePathField<{ categories: ["IMAGE"]; label: "COMBAT.CombatantImage" }>; /** * The initiative score for the Combatant which determines its turn order */ initiative: fields.NumberField<{ required: true; label: "COMBAT.CombatantInitiative" }>; /** * Is this Combatant currently hidden? * @defaultValue `false` */ hidden: fields.BooleanField<{ label: "COMBAT.CombatantHidden" }>; /** * Has this Combatant been defeated? * @defaultValue `false` */ defeated: fields.BooleanField<{ label: "COMBAT.CombatantDefeated" }>; /** * An optional group this Combatant belongs to. * @defaultValue `null` */ group: fields.DocumentIdField<{ readonly: false }>; /** * An object of optional key/value flags * @defaultValue `{}` */ flags: fields.DocumentFlagsField; _stats: fields.DocumentStatsField; } namespace Database { /** Options passed along in Get operations for Combatants */ interface Get extends foundry.abstract.types.DatabaseGetOperation {} /** Options passed along in Create operations for Combatants */ interface Create extends foundry.abstract.types.DatabaseCreateOperation { combatTurn?: number; turnEvents?: boolean; } /** Options passed along in Delete operations for Combatants */ interface Delete extends foundry.abstract.types.DatabaseDeleteOperation { combatTurn?: number; turnEvents?: boolean; } /** Options passed along in Update operations for Combatants */ interface Update extends foundry.abstract.types.DatabaseUpdateOperation { combatTurn?: number; turnEvents?: boolean; } /** Operation for {@linkcode Combatant.createDocuments} */ interface CreateDocumentsOperation extends Document.Database.CreateOperation> {} /** Operation for {@linkcode Combatant.updateDocuments} */ interface UpdateDocumentsOperation extends Document.Database.UpdateDocumentsOperation {} /** Operation for {@linkcode Combatant.deleteDocuments} */ interface DeleteDocumentsOperation extends Document.Database.DeleteDocumentsOperation {} /** Operation for {@linkcode Combatant.create} */ interface CreateOperation extends Document.Database.CreateOperation> {} /** Operation for {@link Combatant.update | `Combatant#update`} */ interface UpdateOperation extends Document.Database.UpdateOperation {} interface DeleteOperation extends Document.Database.DeleteOperation {} /** Options for {@linkcode Combatant.get} */ interface GetOptions extends Document.Database.GetOptions {} /** Options for {@link Combatant._preCreate | `Combatant#_preCreate`} */ interface PreCreateOptions extends Document.Database.PreCreateOptions {} /** Options for {@link Combatant._onCreate | `Combatant#_onCreate`} */ interface OnCreateOptions extends Document.Database.CreateOptions {} /** Operation for {@linkcode Combatant._preCreateOperation} */ interface PreCreateOperation extends Document.Database.PreCreateOperationStatic {} /** Operation for {@link Combatant._onCreateOperation | `Combatant#_onCreateOperation`} */ interface OnCreateOperation extends Combatant.Database.Create {} /** Options for {@link Combatant._preUpdate | `Combatant#_preUpdate`} */ interface PreUpdateOptions extends Document.Database.PreUpdateOptions {} /** Options for {@link Combatant._onUpdate | `Combatant#_onUpdate`} */ interface OnUpdateOptions extends Document.Database.UpdateOptions {} /** Operation for {@linkcode Combatant._preUpdateOperation} */ interface PreUpdateOperation extends Combatant.Database.Update {} /** Operation for {@link Combatant._onUpdateOperation | `Combatant._preUpdateOperation`} */ interface OnUpdateOperation extends Combatant.Database.Update {} /** Options for {@link Combatant._preDelete | `Combatant#_preDelete`} */ interface PreDeleteOptions extends Document.Database.PreDeleteOperationInstance {} /** Options for {@link Combatant._onDelete | `Combatant#_onDelete`} */ interface OnDeleteOptions extends Document.Database.DeleteOptions {} /** Options for {@link Combatant._preDeleteOperation | `Combatant#_preDeleteOperation`} */ interface PreDeleteOperation extends Combatant.Database.Delete {} /** Options for {@link Combatant._onDeleteOperation | `Combatant#_onDeleteOperation`} */ interface OnDeleteOperation extends Combatant.Database.Delete {} /** Context for {@linkcode Combatant._onDeleteOperation} */ interface OnDeleteDocumentsContext extends Document.ModificationContext {} /** Context for {@linkcode Combatant._onCreateDocuments} */ interface OnCreateDocumentsContext extends Document.ModificationContext {} /** Context for {@linkcode Combatant._onUpdateDocuments} */ interface OnUpdateDocumentsContext extends Document.ModificationContext {} /** * Options for {@link Combatant._preCreateDescendantDocuments | `Combatant#_preCreateDescendantDocuments`} * and {@link Combatant._onCreateDescendantDocuments | `Combatant#_onCreateDescendantDocuments`} */ interface CreateOptions extends Document.Database.CreateOptions {} /** * Options for {@link Combatant._preUpdateDescendantDocuments | `Combatant#_preUpdateDescendantDocuments`} * and {@link Combatant._onUpdateDescendantDocuments | `Combatant#_onUpdateDescendantDocuments`} */ interface UpdateOptions extends Document.Database.UpdateOptions {} /** * Options for {@link Combatant._preDeleteDescendantDocuments | `Combatant#_preDeleteDescendantDocuments`} * and {@link Combatant._onDeleteDescendantDocuments | `Combatant#_onDeleteDescendantDocuments`} */ interface DeleteOptions extends Document.Database.DeleteOptions {} /** * Create options for {@linkcode Combatant.createDialog}. */ interface DialogCreateOptions extends InexactPartial {} } /** * If `Temporary` is true then `Combatant.Implementation`, otherwise `Combatant.Stored`. */ type TemporaryIf = true extends Temporary ? Combatant.Implementation : Combatant.Stored; /** * The flags that are available for this document in the form `{ [scope: string]: { [key: string]: unknown } }`. */ interface Flags extends Document.Internal.ConfiguredFlagsForName {} namespace Flags { /** * The valid scopes for the flags on this document e.g. `"core"` or `"dnd5e"`. */ type Scope = Document.Internal.FlagKeyOf; /** * The valid keys for a certain scope for example if the scope is "core" then a valid key may be `"sheetLock"` or `"viewMode"`. */ type Key = Document.Internal.FlagKeyOf>; /** * Gets the type of a particular flag given a `Scope` and a `Key`. */ type Get> = Document.Internal.GetFlag; } interface DropData extends Document.Internal.DropData {} interface DropDataOptions extends Document.DropDataOptions {} interface DefaultNameContext extends Document.DefaultNameContext> {} interface CreateDialogData extends Document.CreateDialogData {} interface CreateDialogOptions extends Document.CreateDialogOptions {} /** * @remarks * This is typed based on what is reasonable to expect, rather than accurately, as accurately would mean `unknown` (Foundry's type is `object|null`). * * Technically this is the value of an arbitrary property path in the Combatant's Actor's `system` (using `getProperty`), and while that path can usually be * assumed to have been set to something in the return of {@linkcode TokenDocument.getTrackedAttributes}, since that's what the {@linkcode CombatTrackerConfig} * provides as options, the path is stored in the {@linkcode Combat.CONFIG_SETTING} which could be updated to be anything. Also, `TokenDocument.getTrackedAttributes` * doesn't actually check what the type of `value` and `max` are for bar type attributes, so even sticking to those choices isn't guaranteed safe. * * There's clear intent that the value *should* be numeric or null, but nothing seems to do math on it in core, and it's simply output in the {@linkcode CombatEncounters} * template as `{{resource}}`, so `string` has been allowed. * * @privateRemarks Adding `boolean` is something that was discussed and decided against for now, but its plausible a system may request such in the future, and wouldn't * make us any more wrong than currently. */ type Resource = string | number | null; /** * The arguments to construct the document. * * @deprecated Writing the signature directly has helped reduce circularities and therefore is * now recommended. */ // eslint-disable-next-line @typescript-eslint/no-deprecated type ConstructorArgs = Document.ConstructorParameters; /** * @deprecated Replaced with {@linkcode Combatant.ConfiguredSubType} (will be removed in v14). */ type ConfiguredSubTypes = ConfiguredSubType; } /** * The client-side Combatant document which extends the common BaseCombatant model. * * @see {@linkcode Combat} The Combat document which contains Combatant embedded documents * @see {@linkcode CombatantConfig} The Combatant configuration application */ declare class Combatant extends BaseCombatant.Internal .ClientDocument { /** * @param data - Initial data from which to construct the `Combatant` * @param context - Construction context options */ // Note(LukeAbby): `data` is not actually required but `context.parent` is. constructor(data: Combatant.CreateData | undefined, context: Combatant.ConstructionContext); /** * The token video source image (if any) * @defaultValue `null` */ _videoSrc: string | null; /** The current value of the special tracked resource which pertains to this Combatant */ resource: Combatant.Resource | null; /** * A convenience alias of Combatant#parent which is more semantically intuitive */ get combat(): Combat.Implementation | null; /** This is treated as a non-player combatant if it has no associated actor and no player users who can control it */ get isNPC(): boolean; /** * Eschew `ClientDocument`'s redirection to `Combat#permission` in favor of special ownership determination. * @remarks Uses {@link BaseCombatant.getUserLevel | `BaseCombatant#getUserLevel`}, so can't return `null` */ override get permission(): CONST.DOCUMENT_OWNERSHIP_LEVELS; override get visible(): boolean; /** A reference to the Actor document which this Combatant represents, if any */ get actor(): Actor.Implementation | null; /** A reference to the Token document which this Combatant represents, if any */ get token(): TokenDocument.Implementation | null; /** An array of non-Gamemaster Users who have ownership of this Combatant. */ get players(): User.Implementation[]; /** * Has this combatant been marked as defeated? */ get isDefeated(): boolean; /** * Get a Roll object which represents the initiative roll for this Combatant. * @param formula - An explicit Roll formula to use for the combatant. * @returns The Roll instance to use for the combatant. */ getInitiativeRoll(formula?: string): Roll.Implementation; /** * Roll initiative for this particular combatant. * @param formula - A dice formula which overrides the default for this Combatant. * @returns The updated Combatant. */ rollInitiative(formula?: string): Promise; /** * @remarks Initializes `_videoSrc`, applies `img` and `name` fallbacks, and calls {@link Combatant.updateResource | `Combatant#updateResource`} */ override prepareDerivedData(): void; /** * Update the value of the tracked resource for this Combatant. */ updateResource(): Combatant.Resource; /** * Acquire the default dice formula which should be used to roll initiative for this combatant. * Modules or systems could choose to override or extend this to accommodate special situations. * @returns The initiative formula to use for this combatant. */ protected _getInitiativeFormula(): string; /** * Prepare derived data based on group membership. */ protected _prepareGroup(): void; /** * Clear the movement history of the Combatant's Token. */ clearMovementHistory: Promise; // DatabaseLifecycle Events are overridden but with no signature changes. // These are already covered in BaseCombatant /* * After this point these are not really overridden methods. * They are here because Foundry's documents are complex and have lots of edge cases. * There are DRY ways of representing this but this ends up being harder to understand * for end users extending these functions, especially for static methods. There are also a * number of methods that don't make sense to call directly on `Document` like `createDocuments`, * as there is no data that can safely construct every possible document. Finally keeping definitions * separate like this helps against circularities. */ // ClientDocument overrides // Descendant Document operations have been left out because Combatant does not have any descendant documents. /** @remarks `context` must contain a `pack` or `parent`. */ static override defaultName(context: Combatant.DefaultNameContext): string; /** @remarks `createOptions` must contain a `pack` or `parent`. */ static override createDialog( data: Combatant.CreateDialogData | undefined, createOptions: Combatant.Database.DialogCreateOptions, options?: Combatant.CreateDialogOptions, ): Promise; override deleteDialog( options?: InexactPartial, operation?: Document.Database.DeleteOperationForName<"Combatant">, ): Promise; static override fromDropData( data: Combatant.DropData, options?: Combatant.DropDataOptions, ): Promise; static override fromImport( source: Combatant.Source, context?: Document.FromImportContext | null, ): Promise; override _onClickDocumentLink(event: MouseEvent): ClientDocument.OnClickDocumentLinkReturn; } export default Combatant;