mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-09 08:59:29 +02:00
Fixed issues with merging
This commit is contained in:
parent
768fb7036a
commit
5a4f7effb3
@ -10,9 +10,6 @@ export type ArenaTrapTagType =
|
||||
| ArenaTagType.STEALTH_ROCK
|
||||
| ArenaTagType.IMPRISON;
|
||||
|
||||
/** Subset of {@linkcode ArenaTagType}s that are considered delayed attacks */
|
||||
export type ArenaDelayedAttackTagType = ArenaTagType.FUTURE_SIGHT | ArenaTagType.DOOM_DESIRE;
|
||||
|
||||
/** Subset of {@linkcode ArenaTagType}s that create {@link https://bulbapedia.bulbagarden.net/wiki/Category:Screen-creating_moves | screens}. */
|
||||
export type ArenaScreenTagType = ArenaTagType.REFLECT | ArenaTagType.LIGHT_SCREEN | ArenaTagType.AURORA_VEIL;
|
||||
|
||||
|
@ -20,7 +20,6 @@ import { StatusEffect } from "#enums/status-effect";
|
||||
import type { Arena } from "#field/arena";
|
||||
import type { Pokemon } from "#field/pokemon";
|
||||
import type {
|
||||
ArenaDelayedAttackTagType,
|
||||
ArenaScreenTagType,
|
||||
ArenaTagTypeData,
|
||||
ArenaTrapTagType,
|
||||
@ -33,7 +32,7 @@ import i18next from "i18next";
|
||||
/*
|
||||
ArenaTags are are meant for effects that are tied to the arena (as opposed to a specific pokemon).
|
||||
Examples include (but are not limited to)
|
||||
- Cross-turn effects that persist even if the user/target switches out, such as Wish, Future Sight, and Happy Hour
|
||||
- Cross-turn effects that persist even if the user/target switches out, such as and Happy Hour
|
||||
- Effects that are applied to a specific side of the field, such as Crafty Shield, Reflect, and Spikes
|
||||
- Field-Effects, like Gravity and Trick Room
|
||||
|
||||
@ -43,7 +42,7 @@ Serializable ArenaTags have strict rules for their fields.
|
||||
These rules ensure that only the data necessary to reconstruct the tag is serialized, and that the
|
||||
session loader is able to deserialize saved tags correctly.
|
||||
|
||||
If the data is static (i.e. it is always the same for all instances of the class, such as the
|
||||
If the data is static (i.e. it is always the same for all instances of the class, such as the
|
||||
type that is weakened by Mud Sport/Water Sport), then it must not be defined as a field, and must
|
||||
instead be defined as a getter.
|
||||
A static property is also acceptable, though static properties are less ergonomic with inheritance.
|
||||
@ -1076,48 +1075,6 @@ class StickyWebTag extends ArenaTrapTag {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Arena Tag class for delayed attacks, such as {@linkcode MoveId.FUTURE_SIGHT} or {@linkcode MoveId.DOOM_DESIRE}.
|
||||
* Delays the attack's effect by a set amount of turns, usually 3 (including the turn the move is used),
|
||||
* and deals damage after the turn count is reached.
|
||||
*/
|
||||
export class DelayedAttackTag extends SerializableArenaTag {
|
||||
public targetIndex: BattlerIndex;
|
||||
public readonly tagType: ArenaDelayedAttackTagType;
|
||||
|
||||
constructor(
|
||||
tagType: ArenaTagType.DOOM_DESIRE | ArenaTagType.FUTURE_SIGHT,
|
||||
sourceMove: MoveId | undefined,
|
||||
sourceId: number | undefined,
|
||||
targetIndex: BattlerIndex,
|
||||
side: ArenaTagSide = ArenaTagSide.BOTH,
|
||||
) {
|
||||
super(3, sourceMove, sourceId, side);
|
||||
this.tagType = tagType;
|
||||
this.targetIndex = targetIndex;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
lapse(arena: Arena): boolean {
|
||||
const ret = super.lapse(arena);
|
||||
|
||||
if (!ret) {
|
||||
// TODO: This should not add to move history (for Spite)
|
||||
globalScene.phaseManager.unshiftNew(
|
||||
"MoveEffectPhase",
|
||||
this.sourceId!,
|
||||
[this.targetIndex],
|
||||
allMoves[this.sourceMove!],
|
||||
MoveUseMode.FOLLOW_UP,
|
||||
); // TODO: are those bangs correct?
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
onRemove(_arena: Arena): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Trick_Room_(move) Trick Room}.
|
||||
* Reverses the Speed stats for all Pokémon on the field as long as this arena tag is up,
|
||||
@ -1682,7 +1639,7 @@ export function getArenaTag(
|
||||
*/
|
||||
export function loadArenaTag(source: ArenaTag | ArenaTagTypeData): ArenaTag {
|
||||
const tag =
|
||||
getArenaTag(source.tagType, source.sourceId, source.sourceMove, source.turnCount, source.side) ?? new NoneTag();
|
||||
getArenaTag(source.tagType, source.turnCount, source.sourceMove, source.sourceId, source.side) ?? new NoneTag();
|
||||
tag.loadTag(source);
|
||||
return tag;
|
||||
}
|
||||
|
@ -3141,7 +3141,7 @@ abstract class AddPositionalTagAttr extends OverrideMoveEffectAttr {
|
||||
|
||||
public override getCondition(): MoveConditionFunc {
|
||||
// Check the arena if another similar positional tag is active and affecting the same slot
|
||||
return (_user, target, move) => globalScene.arena.positionalTagManager.canAddTag(this.tagType, target.getBattlerIndex(), move.id)
|
||||
return (_user, target, move) => globalScene.arena.positionalTagManager.canAddTag(this.tagType, target.getBattlerIndex())
|
||||
}
|
||||
}
|
||||
|
||||
@ -3201,7 +3201,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
|
||||
|
||||
public override getCondition(): MoveConditionFunc {
|
||||
// Check the arena if another similar attack is active and affecting the same slot
|
||||
return (_user, target, move) => globalScene.arena.positionalTagManager.canAddTag(PositionalTagType.DELAYED_ATTACK, target.getBattlerIndex(), move.id)
|
||||
return (_user, target, move) => globalScene.arena.positionalTagManager.canAddTag(PositionalTagType.DELAYED_ATTACK, target.getBattlerIndex())
|
||||
}
|
||||
}
|
||||
|
||||
@ -3219,8 +3219,8 @@ export class WishAttr extends MoveEffectAttr {
|
||||
}
|
||||
|
||||
public override getCondition(): MoveConditionFunc {
|
||||
// Check the arena if another similar attack is active and affecting the same slot
|
||||
return (_user, target, move) => globalScene.arena.positionalTagManager.canAddTag(PositionalTagType.WISH, target.getBattlerIndex(), move.id)
|
||||
// Check the arena if another wish is active and affecting the same slot
|
||||
return (_user, target) => globalScene.arena.positionalTagManager.canAddTag(PositionalTagType.WISH, target.getBattlerIndex())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,16 +7,18 @@ import type { Constructor } from "#utils/common";
|
||||
* Add a new {@linkcode PositionalTag} to the arena.
|
||||
* @param tagType - The {@linkcode PositionalTagType} to create
|
||||
* @param args - The arguments needed to instantize the given tag
|
||||
* @returns The newly created tag.
|
||||
* @remarks
|
||||
* This function does not perform any checking if the added tag is valid.
|
||||
*/
|
||||
export function loadPositionalTag<T extends PositionalTagType>({
|
||||
tagType,
|
||||
...args
|
||||
}: serializedPosTagParamMap[T]): posTagInstanceMap[T];
|
||||
}: serializedPosTagMap[T]): posTagInstanceMap[T];
|
||||
/**
|
||||
* Add a new {@linkcode PositionalTag} to the arena.
|
||||
* @param tag - The {@linkcode SerializedPositionalTag} to instantiate
|
||||
* @returns The newly created tag.
|
||||
* @remarks
|
||||
* This function does not perform any checking if the added tag is valid.
|
||||
*/
|
||||
@ -24,12 +26,13 @@ export function loadPositionalTag(tag: SerializedPositionalTag): PositionalTag;
|
||||
export function loadPositionalTag<T extends PositionalTagType>({
|
||||
tagType,
|
||||
...rest
|
||||
}: serializedPosTagParamMap[T]): posTagInstanceMap[T] {
|
||||
}: serializedPosTagMap[T]): posTagInstanceMap[T] {
|
||||
// Note: We need 2 type assertions here:
|
||||
// 1 because TS doesn't narrow the type of TagClass correctly based on `T`.
|
||||
// It converts it into `new (DelayedAttackTag | WishTag) => DelayedAttackTag & WishTag`
|
||||
const tagClass = posTagConstructorMap[tagType] as new (args: posTagParamMap[T]) => posTagInstanceMap[T];
|
||||
// 2 because TS doesn't narrow `Omit<{tagType: T} & posTagParamMap[T], "tagType"> into `posTagParamMap[T]`
|
||||
// 2 because TS doesn't narrow the type of `rest` correctly
|
||||
// (from `Omit<serializedPosTagParamMap[T], "tagType"> into `posTagParamMap[T]`)
|
||||
return new tagClass(rest as unknown as posTagParamMap[T]);
|
||||
}
|
||||
|
||||
@ -38,10 +41,11 @@ const posTagConstructorMap = Object.freeze({
|
||||
[PositionalTagType.DELAYED_ATTACK]: DelayedAttackTag,
|
||||
[PositionalTagType.WISH]: WishTag,
|
||||
}) satisfies {
|
||||
// NB: This `satisfies` block ensures that all tag types have corresponding entries in the map.
|
||||
[k in PositionalTagType]: Constructor<PositionalTag & { tagType: k }>;
|
||||
};
|
||||
|
||||
/** Type mapping tag types to their constructors. */
|
||||
/** Type mapping positional tag types to their constructors. */
|
||||
type posTagMap = typeof posTagConstructorMap;
|
||||
|
||||
/** Type mapping all positional tag types to their instances. */
|
||||
@ -54,10 +58,13 @@ type posTagParamMap = {
|
||||
[k in PositionalTagType]: ConstructorParameters<posTagMap[k]>[0];
|
||||
};
|
||||
|
||||
/** Type mapping all positional tag types to their constructors' parameters, alongside the `tagType` selector. */
|
||||
type serializedPosTagParamMap = {
|
||||
/**
|
||||
* Type mapping all positional tag types to their constructors' parameters, alongside the `tagType` selector.
|
||||
* Equivalent to their serialized representations.
|
||||
*/
|
||||
export type serializedPosTagMap = {
|
||||
[k in PositionalTagType]: posTagParamMap[k] & { tagType: k };
|
||||
};
|
||||
|
||||
/** Union type containing all serialized {@linkcode PositionalTag}s. */
|
||||
export type SerializedPositionalTag = EnumValues<serializedPosTagParamMap>;
|
||||
export type SerializedPositionalTag = EnumValues<serializedPosTagMap>;
|
||||
|
@ -13,6 +13,7 @@ export interface SerializedArenaData {
|
||||
weather: NonFunctionProperties<Weather> | null;
|
||||
terrain: NonFunctionProperties<Terrain> | null;
|
||||
tags?: ArenaTagTypeData[];
|
||||
positionalTags: SerializedPositionalTag[];
|
||||
playerTerasUsed?: number;
|
||||
}
|
||||
|
||||
@ -34,17 +35,20 @@ export class ArenaData {
|
||||
?.filter((tag): tag is SerializableArenaTag => tag instanceof SerializableArenaTag) ?? [];
|
||||
|
||||
this.playerTerasUsed = source.playerTerasUsed ?? 0;
|
||||
this.positionalTags = (sourceArena ? sourceArena.positionalTagManager.tags : source.positionalTags) ?? [];
|
||||
|
||||
if (source instanceof Arena) {
|
||||
this.biome = source.biomeType;
|
||||
this.weather = source.weather;
|
||||
this.terrain = source.terrain;
|
||||
// The assertion here is ok - we ensure that all tags are inside the `posTagConstructorMap` map,
|
||||
// and that all `PositionalTags` will become their respective interfaces when serialized and de-serialized.
|
||||
this.positionalTags = (source.positionalTagManager.tags as unknown as SerializedPositionalTag[]) ?? [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.biome = source.biome;
|
||||
this.weather = source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : null;
|
||||
this.terrain = source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : null;
|
||||
this.positionalTags = source.positionalTags ?? [];
|
||||
}
|
||||
}
|
||||
|
29
test/types/positional-tags.test-d.ts
Normal file
29
test/types/positional-tags.test-d.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import type { SerializedPositionalTag, serializedPosTagMap } from "#data/positional-tags/load-positional-tag";
|
||||
import type { DelayedAttackTag, WishTag } from "#data/positional-tags/positional-tag";
|
||||
import type { PositionalTagType } from "#enums/positional-tag-type";
|
||||
import type { Mutable, NonFunctionPropertiesRecursive } from "#types/type-helpers";
|
||||
import { describe, expectTypeOf, it } from "vitest";
|
||||
|
||||
// Needed to get around properties being readonly in certain classes
|
||||
type NonFunctionMutable<T> = Mutable<NonFunctionPropertiesRecursive<T>>;
|
||||
|
||||
describe("serializedPositionalTagMap", () => {
|
||||
it("should contain representations of each tag's serialized form", () => {
|
||||
expectTypeOf<serializedPosTagMap[PositionalTagType.DELAYED_ATTACK]>().branded.toEqualTypeOf<
|
||||
NonFunctionMutable<DelayedAttackTag>
|
||||
>();
|
||||
expectTypeOf<serializedPosTagMap[PositionalTagType.WISH]>().branded.toEqualTypeOf<NonFunctionMutable<WishTag>>();
|
||||
});
|
||||
});
|
||||
|
||||
describe("SerializedPositionalTag", () => {
|
||||
it("should accept a union of all serialized tag forms", () => {
|
||||
expectTypeOf<SerializedPositionalTag>().branded.toEqualTypeOf<
|
||||
NonFunctionMutable<DelayedAttackTag> | NonFunctionMutable<WishTag>
|
||||
>();
|
||||
});
|
||||
it("should accept a union of all unserialized tag forms", () => {
|
||||
expectTypeOf<WishTag>().toExtend<SerializedPositionalTag>();
|
||||
expectTypeOf<DelayedAttackTag>().toExtend<SerializedPositionalTag>();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user