diff --git a/config/formats.ts b/config/formats.ts index bde10d12e5..ab522b0d30 100644 --- a/config/formats.ts +++ b/config/formats.ts @@ -4653,7 +4653,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [ mod: 'gen4', gameType: 'doubles', searchShow: false, - ruleset: ['Flat Rules', 'Min Team Size = 4', 'Max Team Size = 4', 'Limit Two Restricted'], + ruleset: ['Flat Rules', 'Limit Two Restricted'], restricted: ['Restricted Legendary'], banlist: ['Soul Dew'], }, @@ -4662,7 +4662,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [ mod: 'gen4pt', gameType: 'doubles', searchShow: false, - ruleset: ['Flat Rules', '! Adjust Level Down', 'Max Level = 50', 'Min Team Size = 4', 'Max Team Size = 4'], + ruleset: ['Flat Rules', '! Adjust Level Down', 'Max Level = 50'], banlist: ['Tyranitar', 'Rotom', 'Judgment', 'Soul Dew'], }, { diff --git a/data/mods/gen4/rulesets.ts b/data/mods/gen4/rulesets.ts index 68bdc86226..bbcb4232d2 100644 --- a/data/mods/gen4/rulesets.ts +++ b/data/mods/gen4/rulesets.ts @@ -5,7 +5,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable }, flatrules: { inherit: true, - ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Item Clause = 1', 'Adjust Level Down = 50', 'Cancel Mod'], + ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Item Clause = 1', 'Adjust Level Down = 50', 'Picked Team Size = Auto', 'Cancel Mod'], }, teampreview: { inherit: true, diff --git a/data/mods/gen8linked/scripts.ts b/data/mods/gen8linked/scripts.ts index b952d274ee..1c4d7811cf 100644 --- a/data/mods/gen8linked/scripts.ts +++ b/data/mods/gen8linked/scripts.ts @@ -65,15 +65,52 @@ export const Scripts: ModdedBattleScriptsData = { case 'start': { for (const side of this.sides) { if (side.pokemonLeft) side.pokemonLeft = side.pokemon.length; + this.add('teamsize', side.id, side.pokemon.length); } this.add('start'); - if (this.format.onBattleStart) this.format.onBattleStart.call(this); + // Change Zacian/Zamazenta into their Crowned formes + for (const pokemon of this.getAllPokemon()) { + let rawSpecies: Species | null = null; + if (pokemon.species.id === 'zacian' && pokemon.item === 'rustedsword') { + rawSpecies = this.dex.species.get('Zacian-Crowned'); + } else if (pokemon.species.id === 'zamazenta' && pokemon.item === 'rustedshield') { + rawSpecies = this.dex.species.get('Zamazenta-Crowned'); + } + if (!rawSpecies) continue; + const species = pokemon.setSpecies(rawSpecies); + if (!species) continue; + pokemon.baseSpecies = rawSpecies; + pokemon.details = pokemon.getUpdatedDetails(); + // pokemon.setAbility(species.abilities['0'], null, true); + // pokemon.baseAbility = pokemon.ability; + + const behemothMove: { [k: string]: string } = { + 'Zacian-Crowned': 'behemothblade', 'Zamazenta-Crowned': 'behemothbash', + }; + const ironHead = pokemon.baseMoves.indexOf('ironhead'); + if (ironHead >= 0) { + const move = this.dex.moves.get(behemothMove[rawSpecies.name]); + pokemon.baseMoveSlots[ironHead] = { + move: move.name, + id: move.id, + pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5, + maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5, + target: move.target, + disabled: false, + disabledSource: '', + used: false, + }; + pokemon.moveSlots = pokemon.baseMoveSlots.slice(); + } + } + + this.format.onBattleStart?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBattleStart) subFormat.onBattleStart.call(this); + subFormat.onBattleStart?.call(this); } for (const side of this.sides) { diff --git a/data/mods/gen9ssb/scripts.ts b/data/mods/gen9ssb/scripts.ts index 62ee0a19d4..9a11f8846a 100644 --- a/data/mods/gen9ssb/scripts.ts +++ b/data/mods/gen9ssb/scripts.ts @@ -369,6 +369,7 @@ export const Scripts: ModdedBattleScriptsData = { case 'start': { for (const side of this.sides) { if (side.pokemonLeft) side.pokemonLeft = side.pokemon.length; + this.add('teamsize', side.id, side.pokemon.length); } this.add('start'); @@ -409,11 +410,11 @@ export const Scripts: ModdedBattleScriptsData = { } } - if (this.format.onBattleStart) this.format.onBattleStart.call(this); + this.format.onBattleStart?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBattleStart) subFormat.onBattleStart.call(this); + subFormat.onBattleStart?.call(this); } for (const side of this.sides) { diff --git a/data/mods/mixandmega/scripts.ts b/data/mods/mixandmega/scripts.ts index 431575013e..e2ca07864c 100644 --- a/data/mods/mixandmega/scripts.ts +++ b/data/mods/mixandmega/scripts.ts @@ -42,10 +42,6 @@ export const Scripts: ModdedBattleScriptsData = { } } - for (const side of this.sides) { - this.add('teamsize', side.id, side.pokemon.length); - } - this.add('gen', this.gen); this.add('tier', format.name); @@ -54,11 +50,11 @@ export const Scripts: ModdedBattleScriptsData = { this.add('rated', typeof this.rated === 'string' ? this.rated : ''); } - if (format.onBegin) format.onBegin.call(this); + format.onBegin?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBegin) subFormat.onBegin.call(this); + subFormat.onBegin?.call(this); } for (const pokemon of this.getAllPokemon()) { const item = pokemon.getItem(); @@ -87,11 +83,25 @@ export const Scripts: ModdedBattleScriptsData = { this.add(`raw|
${format.customRules.length} custom rule${plural}: ${format.customRules.join(', ')}
`); } - if (format.onTeamPreview) format.onTeamPreview.call(this); + format.onTeamPreview?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onTeamPreview) subFormat.onTeamPreview.call(this); + subFormat.onTeamPreview?.call(this); + } + + if (this.requestState !== 'teampreview' && this.ruleTable.pickedTeamSize) { + this.add('clearpoke'); + for (const side of this.sides) { + for (const pokemon of side.pokemon) { + // Still need to hide these formes since they change on battle start + const details = pokemon.details.replace(', shiny', '') + .replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*') + .replace(/(Xerneas)(-[a-zA-Z?-]+)?/g, '$1-*'); + this.addSplit(side.id, ['poke', pokemon.side.id, details, '']); + } + } + this.makeRequest('teampreview'); } this.queue.addChoice({ choice: 'start' }); @@ -106,6 +116,7 @@ export const Scripts: ModdedBattleScriptsData = { case 'start': { for (const side of this.sides) { if (side.pokemonLeft) side.pokemonLeft = side.pokemon.length; + this.add('teamsize', side.id, side.pokemon.length); } this.add('start'); @@ -147,11 +158,11 @@ export const Scripts: ModdedBattleScriptsData = { } } - if (this.format.onBattleStart) this.format.onBattleStart.call(this); + this.format.onBattleStart?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBattleStart) subFormat.onBattleStart.call(this); + subFormat.onBattleStart?.call(this); } for (const side of this.sides) { diff --git a/data/mods/monkeyspaw/scripts.ts b/data/mods/monkeyspaw/scripts.ts index cf384d3623..dd9a604e34 100644 --- a/data/mods/monkeyspaw/scripts.ts +++ b/data/mods/monkeyspaw/scripts.ts @@ -188,6 +188,7 @@ export const Scripts: ModdedBattleScriptsData = { case 'start': { for (const side of this.sides) { if (side.pokemonLeft) side.pokemonLeft = side.pokemon.length; + this.add('teamsize', side.id, side.pokemon.length); } this.add('start'); @@ -228,11 +229,11 @@ export const Scripts: ModdedBattleScriptsData = { } } - if (this.format.onBattleStart) this.format.onBattleStart.call(this); + this.format.onBattleStart?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBattleStart) subFormat.onBattleStart.call(this); + subFormat.onBattleStart?.call(this); } for (const side of this.sides) { diff --git a/data/mods/randomroulette/scripts.ts b/data/mods/randomroulette/scripts.ts index a0ab26978c..9df29569da 100644 --- a/data/mods/randomroulette/scripts.ts +++ b/data/mods/randomroulette/scripts.ts @@ -80,10 +80,6 @@ export const Scripts: ModdedBattleScriptsData = { } } - for (const side of this.sides) { - this.add('teamsize', side.id, side.pokemon.length); - } - this.add('gen', this.gen); this.add('tier', format.name); @@ -92,11 +88,11 @@ export const Scripts: ModdedBattleScriptsData = { this.add('rated', typeof this.rated === 'string' ? this.rated : ''); } - if (format.onBegin) format.onBegin.call(this); + format.onBegin?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBegin) subFormat.onBegin.call(this); + subFormat.onBegin?.call(this); } if (this.sides.some(side => !side.pokemon[0])) { @@ -113,11 +109,25 @@ export const Scripts: ModdedBattleScriptsData = { this.add(`raw|
${format.customRules.length} custom rule${plural}: ${format.customRules.join(', ')}
`); } - if (format.onTeamPreview) format.onTeamPreview.call(this); + format.onTeamPreview?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onTeamPreview) subFormat.onTeamPreview.call(this); + subFormat.onTeamPreview?.call(this); + } + + if (this.requestState !== 'teampreview' && this.ruleTable.pickedTeamSize) { + this.add('clearpoke'); + for (const side of this.sides) { + for (const pokemon of side.pokemon) { + // Still need to hide these formes since they change on battle start + const details = pokemon.details.replace(', shiny', '') + .replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*') + .replace(/(Xerneas)(-[a-zA-Z?-]+)?/g, '$1-*'); + this.addSplit(side.id, ['poke', pokemon.side.id, details, '']); + } + } + this.makeRequest('teampreview'); } this.queue.addChoice({ choice: 'start' }); diff --git a/data/rulesets.ts b/data/rulesets.ts index dd637762ea..acb6c1f924 100644 --- a/data/rulesets.ts +++ b/data/rulesets.ts @@ -1976,12 +1976,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = { name: 'Picked Team Size', desc: "Team size (number of pokemon) that can be brought out of Team Preview", hasValue: 'positive-integer', - // hardcoded in sim/side - onValidateRule() { - if (!(this.ruleTable.has('teampreview') || this.ruleTable.has('teamtypepreview'))) { - throw new Error(`The "Picked Team Size" rule${this.ruleTable.blame('pickedteamsize')} requires Team Preview.`); - } - }, + // hardcoded in sim/side and sim/battle }, minteamsize: { effectType: 'ValidatorRule', diff --git a/sim/battle.ts b/sim/battle.ts index d0df521c08..f1799dc312 100644 --- a/sim/battle.ts +++ b/sim/battle.ts @@ -1868,10 +1868,6 @@ export class Battle { } } - for (const side of this.sides) { - this.add('teamsize', side.id, side.pokemon.length); - } - this.add('gen', this.gen); this.add('tier', format.name); @@ -1908,6 +1904,20 @@ export class Battle { subFormat.onTeamPreview?.call(this); } + if (this.requestState !== 'teampreview' && this.ruleTable.pickedTeamSize) { + this.add('clearpoke'); + for (const side of this.sides) { + for (const pokemon of side.pokemon) { + // Still need to hide these formes since they change on battle start + const details = pokemon.details.replace(', shiny', '') + .replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*') + .replace(/(Xerneas)(-[a-zA-Z?-]+)?/g, '$1-*'); + this.addSplit(side.id, ['poke', pokemon.side.id, details, '']); + } + } + this.makeRequest('teampreview'); + } + this.queue.addChoice({ choice: 'start' }); this.midTurn = true; if (!this.requestState) this.turnLoop(); @@ -2601,6 +2611,7 @@ export class Battle { case 'start': { for (const side of this.sides) { if (side.pokemonLeft) side.pokemonLeft = side.pokemon.length; + this.add('teamsize', side.id, side.pokemon.length); } this.add('start'); @@ -2641,11 +2652,11 @@ export class Battle { } } - if (this.format.onBattleStart) this.format.onBattleStart.call(this); + this.format.onBattleStart?.call(this); for (const rule of this.ruleTable.keys()) { if ('+*-!'.includes(rule.charAt(0))) continue; const subFormat = this.dex.formats.get(rule); - if (subFormat.onBattleStart) subFormat.onBattleStart.call(this); + subFormat.onBattleStart?.call(this); } for (const side of this.sides) {