pkmn / ps

Modular Pokémon Showdown
MIT License
107 stars 15 forks source link

ditto sometimes fails to be interpreted by @poke/client battle #19

Closed vlin02 closed 1 year ago

vlin02 commented 1 year ago

Having ditto on a team can cause the error below sometimes.

TypeError: Cannot read properties of undefined (reading 'types')
    at Pokemon.copyTypesFrom (/home/ubuntu/dev/ps/ps-env/node_modules/@pkmn/client/build/index.js:1402:82)
    at Handler.|-transform| (/home/ubuntu/dev/ps/ps-env/node_modules/@pkmn/client/build/index.js:708:10)
    at Battle2.add (/home/ubuntu/dev/ps/ps-env/node_modules/@pkmn/client/build/index.js:1839:24)

Here's a repro

import { BattleStreams, Dex, Teams, toID } from "@pkmn/sim";
import { TeamGenerators } from "@pkmn/randoms";
import { Generations } from "@pkmn/data";
import * as Client from "@pkmn/client";

Teams.setGeneratorFactory(TeamGenerators);

const streams = BattleStreams.getPlayerStreams(
  new BattleStreams.BattleStream()
);

void streams.omniscient.write([
  '>start {"formatid":"gen9randombattle","seed":[35268,60808,6898,43784]}',
  '>player p1 {"name":"Bot 1","team":"Ditto||ChoiceScarf|Imposter|transform||85,85,85,85,85,85|N|||88|,,,,,Fire]Mudsdale||ChoiceBand|Stamina|earthquake,bodypress,heavyslam,stoneedge||85,85,85,85,85,85||||86|,,,,,Fighting]Grumpig||Leftovers|ThickFat|psychic,focusblast,earthpower,nastyplot||85,,85,85,85,85||,0,,,,||88|,,,,,Psychic]Camerupt||Leftovers|SolidRock|earthquake,lavaplume,stealthrock,yawn||85,85,85,85,85,85||||88|,,,,,Water]Passimian||ChoiceBand|Defiant|closecombat,knockoff,uturn,rockslide||85,85,85,85,85,85||||86|,,,,,Dark]Dragapult||ChoiceSpecs|Infiltrator|dracometeor,shadowball,thunderbolt,fireblast||85,,85,85,85,85||,0,,,,||80|,,,,,Dragon"}',
  '>player p2 {"name":"Bot 2","team":"Greninja||LifeOrb|Protean|hydropump,darkpulse,gunkshot,toxicspikes||85,85,85,85,85,85||||80|,,,,,Poison]Clodsire||Leftovers|Unaware|curse,earthquake,gunkshot,recover||85,85,85,85,85,85||||80|,,,,,Flying]Coalossal||HeavyDutyBoots|FlameBody|stoneedge,overheat,willowisp,rapidspin||85,85,85,85,85,85||||88|,,,,,Water]Mesprit||ChoiceScarf|Levitate|psychic,thunderbolt,uturn,trick||85,85,85,85,85,85|N|||86|,,,,,Electric]Moltres||HeavyDutyBoots|FlameBody|fireblast,bravebird,roost,willowisp||85,85,85,85,85,85|N|||84|,,,,,Ground]Vespiquen||HeavyDutyBoots|Unnerve|airslash,roost,uturn,toxicspikes||85,85,85,85,85,85|F|||90|,,,,,Steel"}'
].join('\n'));

const p1Bat = new Client.Battle(new Generations(Dex), toID("p1"));

for await (const chunk of streams.p1) {
  for (const line of chunk.split("\n")) {
    p1Bat.add(line);
  }
}
scheibo commented 1 year ago

Hi! The issue here is that Greninja does not actually exist in Generation 9 (yay Dexit!) so Ditto doesn't know what to copy types from. You need to change the exists function (second argument to the Generations constructor) in order to include unconventional Pokémon.

If you change:

const p1Bat = new Client.Battle(new Generations(Dex), toID("p1"));

to:

const p1Bat = new Client.Battle(new Generations(Dex, d => !!d.exists), toID("p1"));

(ie, a very lazy exists function) then no error gets thrown.

Pokémon Showdown does not adhere to cartridge legality for some (most?) of its formats, so you will likely need to remember to customize the exists function if you are using @pkmn/data to interop Pokémon Showdown

vlin02 commented 1 year ago

Thanks! That works for what I need.