forked from smogon/pokemon-showdown
-
Notifications
You must be signed in to change notification settings - Fork 1
/
dex-abilities.ts
131 lines (114 loc) · 4.13 KB
/
dex-abilities.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import type {PokemonEventMethods, ConditionData} from './dex-conditions';
import {assignMissingFields, BasicEffect, toID} from './dex-data';
import {Utils} from '../lib';
interface AbilityEventMethods {
onCheckShow?: (this: Battle, pokemon: Pokemon) => void;
onEnd?: (this: Battle, target: Pokemon & Side & Field) => void;
onPreStart?: (this: Battle, pokemon: Pokemon) => void;
onStart?: (this: Battle, target: Pokemon) => void;
}
/* Possible Ability flags */
interface AbilityFlags {
breakable?: 1; // Can be suppressed by Mold Breaker and related effects
cantsuppress?: 1; // Ability can't be suppressed by e.g. Gastro Acid or Neutralizing Gas
failroleplay?: 1; // Role Play fails if target has this Ability
failskillswap?: 1; // Skill Swap fails if either the user or target has this Ability
noentrain?: 1; // Entrainment fails if user has this Ability
noreceiver?: 1; // Receiver and Power of Alchemy will not activate if an ally faints with this Ability
notrace?: 1; // Trace cannot copy this Ability
notransform?: 1; // Disables the Ability if the user is Transformed
}
export interface AbilityData extends Partial<Ability>, AbilityEventMethods, PokemonEventMethods {
name: string;
}
export type ModdedAbilityData = AbilityData | Partial<AbilityData> & {inherit: true};
export interface AbilityDataTable {[abilityid: IDEntry]: AbilityData}
export interface ModdedAbilityDataTable {[abilityid: IDEntry]: ModdedAbilityData}
export class Ability extends BasicEffect implements Readonly<BasicEffect> {
declare readonly effectType: 'Ability';
/** Rating from -1 Detrimental to +5 Essential; see `data/abilities.ts` for details. */
readonly rating: number;
readonly suppressWeather: boolean;
readonly flags: AbilityFlags;
declare readonly condition?: ConditionData;
constructor(data: AnyObject) {
super(data);
this.fullname = `ability: ${this.name}`;
this.effectType = 'Ability';
this.suppressWeather = !!data.suppressWeather;
this.flags = data.flags || {};
this.rating = data.rating || 0;
if (!this.gen) {
if (this.num >= 268) {
this.gen = 9;
} else if (this.num >= 234) {
this.gen = 8;
} else if (this.num >= 192) {
this.gen = 7;
} else if (this.num >= 165) {
this.gen = 6;
} else if (this.num >= 124) {
this.gen = 5;
} else if (this.num >= 77) {
this.gen = 4;
} else if (this.num >= 1) {
this.gen = 3;
}
}
assignMissingFields(this, data);
}
}
const EMPTY_ABILITY = Utils.deepFreeze(new Ability({id: '', name: '', exists: false}));
export class DexAbilities {
readonly dex: ModdedDex;
readonly abilityCache = new Map<ID, Ability>();
allCache: readonly Ability[] | null = null;
constructor(dex: ModdedDex) {
this.dex = dex;
}
get(name: string | Ability = ''): Ability {
if (name && typeof name !== 'string') return name;
const id = toID(name.trim());
return this.getByID(id);
}
getByID(id: ID): Ability {
if (id === '') return EMPTY_ABILITY;
let ability = this.abilityCache.get(id);
if (ability) return ability;
if (this.dex.data.Aliases.hasOwnProperty(id)) {
ability = this.get(this.dex.data.Aliases[id]);
} else if (id && this.dex.data.Abilities.hasOwnProperty(id)) {
const abilityData = this.dex.data.Abilities[id] as any;
const abilityTextData = this.dex.getDescs('Abilities', id, abilityData);
ability = new Ability({
name: id,
...abilityData,
...abilityTextData,
});
if (ability.gen > this.dex.gen) {
(ability as any).isNonstandard = 'Future';
}
if (this.dex.currentMod === 'gen7letsgo' && ability.id !== 'noability') {
(ability as any).isNonstandard = 'Past';
}
if ((this.dex.currentMod === 'gen7letsgo' || this.dex.gen <= 2) && ability.id === 'noability') {
(ability as any).isNonstandard = null;
}
} else {
ability = new Ability({
id, name: id, exists: false,
});
}
if (ability.exists) this.abilityCache.set(id, this.dex.deepFreeze(ability));
return ability;
}
all(): readonly Ability[] {
if (this.allCache) return this.allCache;
const abilities = [];
for (const id in this.dex.data.Abilities) {
abilities.push(this.getByID(id as ID));
}
this.allCache = abilities;
return this.allCache;
}
}