mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-06-02 22:08:36 -05:00
Stricter typing for formats and rules
- Legacy effect type ``Ruleset`` removed - New type ``RuleValueType`` for ``rule.hasValue`` - New interface ``RuleTableBuildContext`` for ``onValidateRule`` handlers - New interface: ``RuleEventMethods`` extending ``EventMethods`` - ``data/rulesets.ts``: Different tag-discriminated types for ``effectType='Rule'`` vs ``effectType='ValidatorRule'``: ``RuleData`` vs ``ValidatorRuleData``. - ``data/rulesets.ts``: Renamed ``FormatDataTable`` to ``RulesetTable`` - Distinguishes types for formats in ``config/formats.ts`` vs in ``Dex.data.Rulesets``: ``FormatData`` vs ``LoadedFormatData``. - Union type for formats OR rulesets in ``Dex.data.Rulesets``: ``RulesetData`` - Implements ``DexFormats#find|some``, for searches excluding rules. - Remove obsolete comment regarding former lack of support for format.onResidual
This commit is contained in:
parent
b76b0499cd
commit
29f778f233
|
|
@ -1507,7 +1507,6 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
'Mewtwo', 'Miraidon', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palafin', 'Palkia', 'Palkia-Origin', 'Rayquaza', 'Regieleki', 'Reshiram', 'Shaymin-Sky',
|
||||
'Solgaleo', 'Terapagos', 'Urshifu-Single-Strike', 'Zacian', 'Zacian-Crowned', 'Zamazenta-Crowned', 'Zekrom',
|
||||
],
|
||||
// Implemented the mechanics as a Rule because I'm too lazy to make battles read base format for `onResidual` at the moment
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Flipped",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
terastalclause: {
|
||||
effectType: 'Rule',
|
||||
name: 'Terastal Clause',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Learnset } from "../../../sim/dex-species";
|
||||
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
obtainablemoves: {
|
||||
inherit: true,
|
||||
banlist: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
teampreview: {
|
||||
inherit: true,
|
||||
onBattleStart() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedRulesetTable = {
|
||||
sleepclausemod: {
|
||||
inherit: true,
|
||||
onSetStatus(status, target, source) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import type { Learnset } from "../sim/dex-species";
|
||||
|
||||
// The list of formats is stored in config/formats.js
|
||||
export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
|
||||
export const Rulesets: import('../sim/dex-formats').RulesetTable = {
|
||||
|
||||
// Rulesets
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
|
@ -564,7 +564,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
|
|||
},
|
||||
},
|
||||
forceselect: {
|
||||
effectType: 'ValidatorRule',
|
||||
effectType: 'Rule',
|
||||
name: 'Force Select',
|
||||
desc: `Forces a Pokemon to be on the team and selected at Team Preview. Usage: Force Select = [Pokemon], e.g. "Force Select = Magikarp"`,
|
||||
hasValue: true,
|
||||
|
|
@ -3253,8 +3253,11 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
|
|||
if (this.ruleTable.adjustLevel) {
|
||||
throw new Error(`This format's rules force Pokemon to be level ${this.ruleTable.adjustLevel}, so they can't be rebalanced.`);
|
||||
}
|
||||
const speciesMods = [...this.ruleTable.keys()].map(r => this.dex.data.Rulesets[r]).filter(r => r?.onModifySpecies);
|
||||
if (!speciesMods.length) throw new Error('This format has no rules that modify base stats.');
|
||||
const anySpeciesMods = [...this.ruleTable.keys()].some(ruleName => {
|
||||
const rule = this.dex.data.Rulesets[ruleName];
|
||||
return rule && rule.effectType !== 'ValidatorRule' && rule.onModifySpecies;
|
||||
});
|
||||
if (!anySpeciesMods) throw new Error('This format has no rules that modify base stats.');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import * as ConfigLoader from '../config-loader';
|
||||
import { ProcessManager, Utils } from '../../lib';
|
||||
import type { FormatData } from '../../sim/dex-formats';
|
||||
import type { RulesetData } from '../../sim/dex-formats';
|
||||
import { TeamValidator } from '../../sim/team-validator';
|
||||
import { Chat } from '../chat';
|
||||
|
||||
|
|
@ -635,8 +635,12 @@ function getRule(target: string) {
|
|||
x => x.toLowerCase().replace(/[^a-z0-9=]+/g, '').split('rule=')[1]), count };
|
||||
}
|
||||
|
||||
function prepareDexsearchValidator(usedMod: string | undefined, rules: FormatData[], nationalSearch: boolean | null) {
|
||||
const format = Object.entries(Dex.data.Rulesets).find(([a, f]) => f.mod === usedMod)?.[1].name || 'gen9ou';
|
||||
function prepareDexsearchValidator(
|
||||
usedMod: string | undefined,
|
||||
rules: RulesetData[],
|
||||
nationalSearch: boolean | null
|
||||
) {
|
||||
const format = Dex.formats.find(f => f.mod === usedMod)?.name || 'gen9ou';
|
||||
const ruleTable = Dex.formats.getRuleTable(Dex.formats.get(format));
|
||||
const additionalRules = [];
|
||||
for (const rule of rules) {
|
||||
|
|
@ -661,7 +665,7 @@ function runDexsearch(target: string, cmd: string, message: string, isTest: bool
|
|||
}
|
||||
}
|
||||
const mod = Dex.mod(usedMod || 'base');
|
||||
const rules: FormatData[] = [];
|
||||
const rules: RulesetData[] = [];
|
||||
for (const rule of usedRules) {
|
||||
if (!dexsearchHelpRules.includes(rule))
|
||||
return { error: `${rule} is an unsupported rule, see /dexsearchhelp` };
|
||||
|
|
@ -1316,7 +1320,8 @@ function runDexsearch(target: string, cmd: string, message: string, isTest: bool
|
|||
) {
|
||||
let newSpecies = species;
|
||||
for (const rule of rules) {
|
||||
newSpecies = rule?.onModifySpecies?.call({ dex: mod, clampIntRange: Utils.clampIntRange, toID } as Battle,
|
||||
if (!rule || rule.effectType === 'ValidatorRule') continue;
|
||||
newSpecies = rule.onModifySpecies?.call({ dex: mod, clampIntRange: Utils.clampIntRange, toID } as Battle,
|
||||
newSpecies) || newSpecies;
|
||||
}
|
||||
dex[newSpecies.id] = newSpecies;
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ export interface EventMethods {
|
|||
onWeatherModifyDamage?: CommonHandlers['ModifierSourceMove'];
|
||||
onModifyDamagePhase1?: CommonHandlers['ModifierSourceMove'];
|
||||
onModifyDamagePhase2?: CommonHandlers['ModifierSourceMove'];
|
||||
onModifySpecies?: (
|
||||
this: Battle, species: Species, target?: Pokemon, source?: Pokemon, effect?: Effect
|
||||
) => Species | void;
|
||||
onFoeDamagingHit?: (this: Battle, damage: number, target: Pokemon, source: Pokemon, move: ActiveMove) => void;
|
||||
onFoeAfterEachBoost?: (this: Battle, boost: SparseBoostsTable, target: Pokemon, source: Pokemon) => void;
|
||||
onFoeAfterHit?: MoveEventMethods['onAfterHit'];
|
||||
|
|
@ -472,6 +475,7 @@ export interface EventMethods {
|
|||
onModifySpAPriority?: number;
|
||||
onModifySpDPriority?: number;
|
||||
onModifySpePriority?: number;
|
||||
onModifySpeciesPriority?: number;
|
||||
onModifySTABPriority?: number;
|
||||
onModifyTypePriority?: number;
|
||||
onModifyWeightPriority?: number;
|
||||
|
|
@ -615,6 +619,14 @@ export interface FieldEventMethods extends EventMethods {
|
|||
onFieldResidualPriority?: number;
|
||||
onFieldResidualSubOrder?: number;
|
||||
}
|
||||
export interface RuleEventMethods extends EventMethods {
|
||||
onBegin?: (this: Battle) => void;
|
||||
onBattleStart?: (this: Battle) => void;
|
||||
onTeamPreview?: (this: Battle) => void;
|
||||
onChooseTeam?: (
|
||||
this: Battle, positions: number[], pokemon: Pokemon[], autoChoose?: boolean
|
||||
) => number[] | string | void;
|
||||
}
|
||||
export interface PokemonConditionData extends Partial<Condition>, PokemonEventMethods {}
|
||||
export interface SideConditionData extends
|
||||
Partial<Omit<Condition, 'onStart' | 'onRestart' | 'onEnd'>>, SideEventMethods {}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,174 @@
|
|||
import { Utils } from '../lib/utils';
|
||||
import { assignMissingFields, toID, BasicEffect } from './dex-data';
|
||||
import type { EventMethods } from './dex-conditions';
|
||||
import type { RuleEventMethods } from './dex-conditions';
|
||||
import type { SpeciesData } from './dex-species';
|
||||
import { Tags } from '../data/tags';
|
||||
|
||||
const DEFAULT_MOD = 'gen9';
|
||||
|
||||
export interface FormatData extends Partial<Format>, EventMethods {
|
||||
name: string;
|
||||
export type RuleValueType = boolean | 'integer' | 'positive-integer';
|
||||
|
||||
/** Used for onValidateRule handlers */
|
||||
export interface RuleTableBuildContext {
|
||||
format: Format;
|
||||
ruleTable: RuleTable;
|
||||
dex: ModdedDex;
|
||||
}
|
||||
|
||||
export type FormatList = (FormatData | { section: string, column?: number })[];
|
||||
export type ModdedFormatData = FormatData | Omit<FormatData, 'name'> & { inherit: true };
|
||||
export interface FormatDataTable { [id: IDEntry]: FormatData }
|
||||
export interface ModdedFormatDataTable { [id: IDEntry]: ModdedFormatData }
|
||||
type NamedBasicEffectFragment = Omit<WithRequired<Readonly<BasicEffect>, 'name'>, 'effectType'>;
|
||||
|
||||
type FormatEffectType = 'Format' | 'Ruleset' | 'Rule' | 'ValidatorRule';
|
||||
interface ValidatorRuleFields {
|
||||
/** List of rule names. */
|
||||
ruleset?: string[];
|
||||
/** List of banned effects. */
|
||||
banlist?: string[];
|
||||
/** List of effects that aren't completely banned. */
|
||||
restricted?: string[];
|
||||
/** List of inherited banned effects to override. */
|
||||
unbanlist?: string[];
|
||||
|
||||
/** Needed in order to print clauses */
|
||||
onBegin?: RuleEventMethods['onBegin'];
|
||||
checkCanLearn?: (
|
||||
this: TeamValidator, move: Move, species: Species, setSources: PokemonSources, set: PokemonSet
|
||||
) => string | null;
|
||||
onChangeSet?: (
|
||||
this: TeamValidator, set: PokemonSet, format: Format, setHas?: AnyObject, teamHas?: AnyObject
|
||||
) => string[] | void;
|
||||
onValidateSet?: (
|
||||
this: TeamValidator, set: PokemonSet, format: Format, setHas: AnyObject, teamHas: AnyObject
|
||||
) => string[] | void;
|
||||
onValidateTeam?: (
|
||||
this: TeamValidator, team: PokemonSet[], format: Format, teamHas: AnyObject
|
||||
) => string[] | void;
|
||||
|
||||
/** ID of rule that can't be combined with this rule */
|
||||
mutuallyExclusiveWith?: string;
|
||||
}
|
||||
|
||||
interface RuleFields extends ValidatorRuleFields, RuleEventMethods {}
|
||||
|
||||
interface FormatFields extends RuleFields {
|
||||
mod?: string;
|
||||
/**
|
||||
* Name of the team generator algorithm, if this format uses
|
||||
* random/fixed teams. null if players can bring teams.
|
||||
*/
|
||||
team?: string;
|
||||
debug?: boolean;
|
||||
noLog?: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not a format will update ladder points if searched
|
||||
* for using the "Battle!" button.
|
||||
* (Challenge and tournament games will never update ladder points.)
|
||||
* (Defaults to `true`.)
|
||||
*/
|
||||
rated?: boolean | string;
|
||||
/** Game type. */
|
||||
gameType?: GameType;
|
||||
|
||||
threads?: string[];
|
||||
|
||||
/** Overrides for battle scripts */
|
||||
battle?: ModdedBattleScriptsData;
|
||||
pokemon?: ModdedBattlePokemon;
|
||||
queue?: ModdedBattleQueue;
|
||||
field?: ModdedField;
|
||||
actions?: ModdedBattleActions;
|
||||
side?: ModdedBattleSide;
|
||||
|
||||
/** Flags for the formats list */
|
||||
challengeShow?: boolean;
|
||||
searchShow?: boolean;
|
||||
tournamentShow?: boolean;
|
||||
bestOfDefault?: boolean;
|
||||
teraPreviewDefault?: boolean;
|
||||
itemClauseDefault?: boolean;
|
||||
|
||||
/** Validator overrides */
|
||||
validateSet?: (this: TeamValidator, set: PokemonSet, teamHas: AnyObject) => string[] | null;
|
||||
validateTeam?: (this: TeamValidator, team: PokemonSet[], options?: {
|
||||
removeNicknames?: boolean,
|
||||
skipSets?: { [name: string]: { [key: string]: boolean } },
|
||||
}) => string[] | void;
|
||||
|
||||
// OMs
|
||||
getEvoFamily?: (this: Format, speciesid: string) => ID;
|
||||
getSharedPower?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
getSharedItems?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
}
|
||||
|
||||
interface TaggedValidatorRuleFields extends ValidatorRuleFields {
|
||||
effectType: 'ValidatorRule';
|
||||
|
||||
/**
|
||||
* Only applies to rules, not formats
|
||||
*/
|
||||
hasValue?: RuleValueType;
|
||||
onValidateRule?: (this: RuleTableBuildContext, value: string) => string | void;
|
||||
}
|
||||
|
||||
interface TaggedRuleFields extends RuleFields {
|
||||
effectType: 'Rule';
|
||||
|
||||
/**
|
||||
* Only applies to rules, not formats
|
||||
*/
|
||||
hasValue?: RuleValueType;
|
||||
onValidateRule?: (this: RuleTableBuildContext, value: string) => string | void;
|
||||
}
|
||||
|
||||
interface TaggedFormatFields extends FormatFields {
|
||||
/**
|
||||
* A format can be used as a rule, but without an associated value.
|
||||
*/
|
||||
onValidateRule?: (this: RuleTableBuildContext) => string | void;
|
||||
}
|
||||
|
||||
export interface ValidatorRuleData extends NamedBasicEffectFragment, Readonly<TaggedValidatorRuleFields> {}
|
||||
export interface RuleData extends NamedBasicEffectFragment, Readonly<TaggedRuleFields> {}
|
||||
export interface FormatData extends NamedBasicEffectFragment, Readonly<TaggedFormatFields> {}
|
||||
|
||||
/** Distinguishes types for formats in `config/formats.ts` vs in `Dex.data.Rulesets` */
|
||||
export interface LoadedFormatData extends FormatData {
|
||||
effectType: 'Format';
|
||||
section: string;
|
||||
column: number;
|
||||
ruleTable: RuleTable | null;
|
||||
}
|
||||
|
||||
type FormatDataVariantMap = {
|
||||
Format: FormatData,
|
||||
Rule: RuleData,
|
||||
ValidatorRule: ValidatorRuleData,
|
||||
};
|
||||
|
||||
export type FormatEffectType = keyof FormatDataVariantMap;
|
||||
export type RulesetEffectType = Exclude<FormatEffectType, 'Format'>;
|
||||
type FormatDataVariant<K extends FormatEffectType> = FormatDataVariantMap[K];
|
||||
export type GeneralizedFormatData = FormatDataVariant<FormatEffectType>;
|
||||
type GeneralizedRuleData = FormatDataVariant<RulesetEffectType>;
|
||||
|
||||
export type ModdedRuleData = RuleData | (Omit<
|
||||
Omit<RuleData, 'name'>,
|
||||
'effectType'
|
||||
> & { inherit: true });
|
||||
export type ModdedValidatorRuleData = ValidatorRuleData | (Omit<
|
||||
Omit<ValidatorRuleData, 'name'>,
|
||||
'effectType'
|
||||
> & { inherit: true });
|
||||
export type ModdedGeneralizedRuleData = GeneralizedRuleData | (Omit<
|
||||
Omit<GeneralizedRuleData, 'name'>,
|
||||
'effectType'
|
||||
> & { inherit: true });
|
||||
|
||||
export type FormatList = (FormatData | { section: string, column?: number })[];
|
||||
export interface RulesetTable { [id: IDEntry]: GeneralizedRuleData }
|
||||
export interface ModdedRulesetTable { [id: IDEntry]: ModdedGeneralizedRuleData }
|
||||
|
||||
/** Union type for formats OR rules in `Dex.data.Rulesets` */
|
||||
export type RulesetData = (LoadedFormatData | GeneralizedRuleData);
|
||||
|
||||
/** rule, source, limit, bans */
|
||||
export type ComplexBan = [string, string, number, string[]];
|
||||
|
|
@ -46,7 +199,7 @@ export class RuleTable extends Map<string, string> {
|
|||
complexBans: ComplexBan[];
|
||||
complexTeamBans: ComplexTeamBan[];
|
||||
checkCanLearn: [TeamValidator['checkCanLearn'], string] | null;
|
||||
onChooseTeam: [NonNullable<Format['onChooseTeam']>, string] | null;
|
||||
onChooseTeam: [NonNullable<RuleEventMethods['onChooseTeam']>, string] | null;
|
||||
timer: [Partial<GameTimerSettings>, string] | null;
|
||||
tagRules: string[];
|
||||
valueRules: Map<string, string>;
|
||||
|
|
@ -375,7 +528,7 @@ export class RuleTable extends Map<string, string> {
|
|||
}
|
||||
}
|
||||
|
||||
export class Format extends BasicEffect implements Readonly<BasicEffect> {
|
||||
export class Format extends BasicEffect implements Readonly<BasicEffect>, RuleEventMethods {
|
||||
readonly mod: string;
|
||||
/**
|
||||
* Name of the team generator algorithm, if this format uses
|
||||
|
|
@ -384,6 +537,7 @@ export class Format extends BasicEffect implements Readonly<BasicEffect> {
|
|||
declare readonly team?: string;
|
||||
override readonly effectType: FormatEffectType;
|
||||
readonly debug: boolean;
|
||||
readonly noLog: boolean;
|
||||
/**
|
||||
* Whether or not a format will update ladder points if searched
|
||||
* for using the "Battle!" button.
|
||||
|
|
@ -412,16 +566,13 @@ export class Format extends BasicEffect implements Readonly<BasicEffect> {
|
|||
readonly customRules: string[] | null;
|
||||
/** Table of rule names and banned effects. */
|
||||
ruleTable: RuleTable | null;
|
||||
/** An optional function that runs at the start of a battle. */
|
||||
readonly onBegin?: (this: Battle) => void;
|
||||
readonly noLog: boolean;
|
||||
|
||||
/**
|
||||
* Only applies to rules, not formats
|
||||
*/
|
||||
declare readonly hasValue?: boolean | 'integer' | 'positive-integer';
|
||||
declare readonly hasValue?: RuleValueType;
|
||||
declare readonly onValidateRule?: (
|
||||
this: { format: Format, ruleTable: RuleTable, dex: ModdedDex }, value: string
|
||||
this: RuleTableBuildContext, value: string
|
||||
) => string | void;
|
||||
/** ID of rule that can't be combined with this rule */
|
||||
declare readonly mutuallyExclusiveWith?: string;
|
||||
|
|
@ -432,49 +583,54 @@ export class Format extends BasicEffect implements Readonly<BasicEffect> {
|
|||
declare readonly field?: ModdedField;
|
||||
declare readonly actions?: ModdedBattleActions;
|
||||
declare readonly side?: ModdedBattleSide;
|
||||
|
||||
declare readonly challengeShow?: boolean;
|
||||
declare readonly searchShow?: boolean;
|
||||
declare readonly tournamentShow?: boolean;
|
||||
declare readonly bestOfDefault?: boolean;
|
||||
declare readonly teraPreviewDefault?: boolean;
|
||||
declare readonly itemClauseDefault?: boolean;
|
||||
declare readonly threads?: string[];
|
||||
declare readonly tournamentShow?: boolean;
|
||||
|
||||
declare readonly checkCanLearn?: (
|
||||
this: TeamValidator, move: Move, species: Species, setSources: PokemonSources, set: PokemonSet
|
||||
) => string | null;
|
||||
declare readonly getEvoFamily?: (this: Format, speciesid: string) => ID;
|
||||
declare readonly getSharedPower?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
declare readonly getSharedItems?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
declare readonly onChangeSet?: (
|
||||
this: TeamValidator, set: PokemonSet, format: Format, setHas?: AnyObject, teamHas?: AnyObject
|
||||
) => string[] | void;
|
||||
declare readonly onModifySpeciesPriority?: number;
|
||||
declare readonly onModifySpecies?: (
|
||||
this: Battle, species: Species, target?: Pokemon, source?: Pokemon, effect?: Effect
|
||||
) => Species | void;
|
||||
declare readonly onBattleStart?: (this: Battle) => void;
|
||||
declare readonly onTeamPreview?: (this: Battle) => void;
|
||||
declare readonly onChooseTeam?: (
|
||||
this: Battle, positions: number[], pokemon: Pokemon[], autoChoose?: boolean
|
||||
) => number[] | string | void;
|
||||
declare readonly onValidateSet?: (
|
||||
this: TeamValidator, set: PokemonSet, format: Format, setHas: AnyObject, teamHas: AnyObject
|
||||
) => string[] | void;
|
||||
declare readonly onValidateTeam?: (
|
||||
this: TeamValidator, team: PokemonSet[], format: Format, teamHas: AnyObject
|
||||
) => string[] | void;
|
||||
|
||||
declare readonly validateSet?: (this: TeamValidator, set: PokemonSet, teamHas: AnyObject) => string[] | null;
|
||||
declare readonly validateTeam?: (this: TeamValidator, team: PokemonSet[], options?: {
|
||||
removeNicknames?: boolean,
|
||||
skipSets?: { [name: string]: { [key: string]: boolean } },
|
||||
}) => string[] | void;
|
||||
|
||||
declare readonly onBegin?: RuleEventMethods['onBegin'];
|
||||
declare readonly onBattleStart?: RuleEventMethods['onBattleStart'];
|
||||
declare readonly onTeamPreview?: RuleEventMethods['onTeamPreview'];
|
||||
declare readonly onChooseTeam?: RuleEventMethods['onChooseTeam'];
|
||||
|
||||
declare readonly onModifySpeciesPriority?: RuleEventMethods['onModifySpeciesPriority'];
|
||||
declare readonly onModifySpecies?: RuleEventMethods['onModifySpecies'];
|
||||
|
||||
declare readonly section?: string;
|
||||
declare readonly column?: number;
|
||||
|
||||
// OMs
|
||||
getEvoFamily?: (this: Format, speciesid: string) => ID;
|
||||
getSharedPower?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
getSharedItems?: (this: Format, pokemon: Pokemon) => Set<string>;
|
||||
|
||||
constructor(data: AnyObject) {
|
||||
super(data);
|
||||
|
||||
this.mod = Utils.getString(data.mod) || 'gen9';
|
||||
this.mod = Utils.getString(data.mod) || DEFAULT_MOD;
|
||||
this.effectType = Utils.getString(data.effectType) as FormatEffectType || 'Condition';
|
||||
this.debug = !!data.debug;
|
||||
this.rated = (typeof data.rated === 'string' ? data.rated : data.rated !== false);
|
||||
|
|
@ -514,11 +670,11 @@ function mergeFormatLists(main: FormatList, custom: FormatList | undefined): For
|
|||
// populates the original sections and formats easily
|
||||
// there should be no repeat sections at this point.
|
||||
for (const element of main) {
|
||||
if (element.section) {
|
||||
if ('section' in element) {
|
||||
current = { section: element.section, column: element.column, formats: [] };
|
||||
build.push(current);
|
||||
} else if ((element as FormatData).name) {
|
||||
current.formats.push((element as FormatData));
|
||||
} else if (element.name) {
|
||||
current.formats.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +682,7 @@ function mergeFormatLists(main: FormatList, custom: FormatList | undefined): For
|
|||
if (custom !== undefined) {
|
||||
for (const element of custom) {
|
||||
// finds the section and makes it if it doesn't exist.
|
||||
if (element.section) {
|
||||
if ('section' in element) {
|
||||
current = build.find(e => e.section === element.section);
|
||||
|
||||
// if it's new it makes a new entry.
|
||||
|
|
@ -534,8 +690,8 @@ function mergeFormatLists(main: FormatList, custom: FormatList | undefined): For
|
|||
current = { section: element.section, column: element.column, formats: [] };
|
||||
build.push(current);
|
||||
}
|
||||
} else if ((element as FormatData).name) { // otherwise, adds the element to its section.
|
||||
current.formats.push(element as FormatData);
|
||||
} else if (element.name) { // otherwise, adds the element to its section.
|
||||
current.formats.push(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -605,7 +761,7 @@ export class DexFormats {
|
|||
if (format.bestOfDefault === undefined) format.bestOfDefault = false;
|
||||
if (format.teraPreviewDefault === undefined) format.teraPreviewDefault = false;
|
||||
if (format.itemClauseDefault === undefined) format.itemClauseDefault = false;
|
||||
if (format.mod === undefined) format.mod = 'gen9';
|
||||
if (format.mod === undefined) format.mod = DEFAULT_MOD;
|
||||
if (!this.dex.dexes[format.mod]) throw new Error(`Format "${format.name}" requires nonexistent mod: '${format.mod}'`);
|
||||
|
||||
this.checkDeprecated(format);
|
||||
|
|
@ -729,6 +885,19 @@ export class DexFormats {
|
|||
return this.formatsListCache!;
|
||||
}
|
||||
|
||||
find(filterFn: (format: Format) => boolean): Format | null {
|
||||
this.load();
|
||||
for (const format of this.formatsListCache!) {
|
||||
if (filterFn(format)) return format;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
filter(filterFn: (format: Format) => boolean): Format[] {
|
||||
this.load();
|
||||
return this.formatsListCache!.filter(filterFn);
|
||||
}
|
||||
|
||||
isPokemonRule(ruleSpec: string) {
|
||||
return (
|
||||
ruleSpec.slice(1).startsWith('pokemontag:') || ruleSpec.slice(1).startsWith('pokemon:') ||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export interface AliasesTable { [id: IDEntry]: string }
|
|||
|
||||
interface DexTableData {
|
||||
Abilities: DexTable<import('./dex-abilities').AbilityData>;
|
||||
Rulesets: DexTable<import('./dex-formats').FormatData>;
|
||||
Rulesets: DexTable<import('./dex-formats').RulesetData>;
|
||||
Items: DexTable<import('./dex-items').ItemData>;
|
||||
Learnsets: DexTable<import('./dex-species').LearnsetData>;
|
||||
Moves: DexTable<import('./dex-moves').MoveData>;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ type Mutable<T> = {
|
|||
-readonly [P in keyof T]: T[P];
|
||||
};
|
||||
|
||||
type WithRequired<T, K extends keyof T> = Partial<T> & Required<Pick<T, K>>;
|
||||
|
||||
type Battle = import('./battle').Battle;
|
||||
type BattleQueue = import('./battle-queue').BattleQueue;
|
||||
type BattleActions = import('./battle-actions').BattleActions;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user