3030from showdown .engine .objects import State
3131from showdown .engine .objects import Side
3232from showdown .engine .objects import Pokemon as TransposePokemon
33+ from showdown .engine .objects import MoveChoice
3334
3435from showdown .engine .helpers import remove_duplicate_spreads
3536from showdown .engine .helpers import get_pokemon_info_from_condition
@@ -74,6 +75,7 @@ def __init__(self, battle_tag):
7475 self .wait = False
7576
7677 self .battle_type = None
78+ self .pokemon_mode = None
7779 self .generation = None
7880 self .time_remaining = None
7981
@@ -117,10 +119,13 @@ def start_non_team_preview_battle(self, user_json, opponent_switch_string):
117119
118120 def mega_evolve_possible (self ):
119121 return (
120- any (g in self .generation for g in constants .MEGA_EVOLVE_GENERATIONS ) or
121- 'nationaldex' in ShowdownConfig .pokemon_mode
122+ any (g in self .generation for g in constants .MEGA_EVOLVE_GENERATIONS ) or
123+ 'nationaldex' in ShowdownConfig .pokemon_mode
122124 )
123125
126+ def tera_possible (self ):
127+ return any (g in self .generation for g in constants .TERASTALLIZE_GENERATIONS )
128+
124129 def prepare_battles (self , guess_mega_evo_opponent = True , join_moves_together = False ):
125130 """Returns a list of battles based on this one
126131 The battles have the opponent's reserve pokemon's unknowns filled in
@@ -207,10 +212,10 @@ def create_state(self):
207212 for mon in self .opponent .reserve :
208213 opponent_reserve [mon .name ] = TransposePokemon .from_state_pokemon_dict (mon .to_dict ())
209214
210- user = Side (user_active , user_reserve , copy (self .user .wish ), copy (self .user .side_conditions ), copy (self .user .future_sight ))
211- opponent = Side (opponent_active , opponent_reserve , copy (self .opponent .wish ), copy (self .opponent .side_conditions ), copy (self .opponent .future_sight ))
215+ user = Side (user_active , user_reserve , copy (self .user .wish ), copy (self .user .side_conditions ), copy (self .user .future_sight ), used_tera = self . user . used_tera )
216+ opponent = Side (opponent_active , opponent_reserve , copy (self .opponent .wish ), copy (self .opponent .side_conditions ), copy (self .opponent .future_sight ), used_tera = self . opponent . used_tera )
212217
213- state = State (user , opponent , self .weather , self .field , self .trick_room )
218+ state = State (user , opponent , self .weather , self .field , self .trick_room , tera_allowed = self . tera_possible () )
214219 return state
215220
216221 def get_all_options (self ):
@@ -219,7 +224,7 @@ def get_all_options(self):
219224
220225 # double faint or team preview
221226 if force_switch and wait :
222- user_options = self .user .get_switches () or [constants .DO_NOTHING_MOVE ]
227+ user_options = self .user .get_switches () or [MoveChoice ( id = constants .DO_NOTHING_MOVE ) ]
223228
224229 # edge-case for uturn or voltswitch killing
225230 if (
@@ -228,9 +233,9 @@ def get_all_options(self):
228233 self .user .last_used_move .turn == self .turn
229234
230235 ):
231- opponent_options = [constants .DO_NOTHING_MOVE ]
236+ opponent_options = [MoveChoice ( id = constants .DO_NOTHING_MOVE ) ]
232237 else :
233- opponent_options = self .opponent .get_switches () or [constants .DO_NOTHING_MOVE ]
238+ opponent_options = self .opponent .get_switches () or [MoveChoice ( id = constants .DO_NOTHING_MOVE ) ]
234239
235240 return user_options , opponent_options
236241
@@ -243,25 +248,39 @@ def get_all_options(self):
243248 self .opponent .last_used_move .turn != self .turn and
244249 self .user .last_used_move .turn == self .turn
245250 ):
246- opponent_options = [m .name for m in self .opponent .active .moves if not m .disabled ] or [constants .DO_NOTHING_MOVE ]
251+ opponent_options = (
252+ [MoveChoice (m .name ) for m in self .opponent .active .moves if not m .disabled ] or
253+ [MoveChoice (id = constants .DO_NOTHING_MOVE )]
254+ )
247255 else :
248- opponent_options = [constants .DO_NOTHING_MOVE ]
256+ opponent_options = [MoveChoice ( id = constants .DO_NOTHING_MOVE ) ]
249257 elif wait :
250258 opponent_options = self .opponent .get_switches ()
251- user_options = [constants .DO_NOTHING_MOVE ]
259+ user_options = [MoveChoice ( id = constants .DO_NOTHING_MOVE ) ]
252260 else :
253261 user_forced_move = self .user .active .forced_move ()
254262 if user_forced_move :
255263 user_options = [user_forced_move ]
256264 else :
257- user_options = [m .name for m in self .user .active .moves if not m .disabled ]
265+ user_options = [
266+ MoveChoice (m .name ) for m in self .user .active .moves if not m .disabled
267+ ]
268+ if self .user .active .can_terastallize and self .tera_possible ():
269+ for mv in user_options [:]:
270+ user_options .append (MoveChoice (mv .id , terastallize = True ))
258271 user_options += self .user .get_switches ()
259272
260273 opponent_forced_move = self .opponent .active .forced_move ()
261274 if opponent_forced_move :
262275 opponent_options = [opponent_forced_move ]
263276 else :
264- opponent_options = [m .name for m in self .opponent .active .moves if not m .disabled ] or [constants .DO_NOTHING_MOVE ]
277+ opponent_options = (
278+ [MoveChoice (m .name ) for m in self .opponent .active .moves if not m .disabled ] or
279+ [MoveChoice (id = constants .DO_NOTHING_MOVE )]
280+ )
281+ if not self .opponent .used_tera and self .tera_possible ():
282+ for mv in opponent_options [:]:
283+ opponent_options .append (MoveChoice (mv .id , terastallize = True ))
265284 opponent_options += self .opponent .get_switches ()
266285
267286 return user_options , opponent_options
@@ -282,6 +301,7 @@ def __init__(self):
282301 self .trapped = False
283302 self .wish = (0 , 0 )
284303 self .future_sight = (0 , 0 )
304+ self .used_tera = False
285305
286306 self .account_name = None
287307
@@ -333,8 +353,6 @@ def from_json(self, user_json, first_turn=False):
333353 self .active .name ,
334354 self .active .boosts ,
335355 self .active .volatile_statuses ,
336- self .active .terastallized ,
337- self .active .types
338356 )
339357
340358 try :
@@ -358,15 +376,17 @@ def from_json(self, user_json, first_turn=False):
358376 pkmn .stats [constants .STAT_ABBREVIATION_LOOKUPS [stat ]] = number
359377
360378 pkmn .item = pkmn_dict [constants .ITEM ] if pkmn_dict [constants .ITEM ] else None
379+ pkmn .tera_type = normalize_name (pkmn_dict .get (constants .PS_TERA_TYPE , pkmn .types [0 ]))
380+ if pkmn_dict .get (constants .TERASTALLIZED ):
381+ pkmn .terastallized = True
382+ pkmn .tera_type = normalize_name (pkmn_dict [constants .TERASTALLIZED ])
383+ pkmn .types = [pkmn .tera_type ]
361384
362385 if pkmn_dict [constants .ACTIVE ]:
363386 self .active = pkmn
364387 if existing_conditions [0 ] == pkmn .name :
365388 pkmn .boosts = existing_conditions [1 ]
366389 pkmn .volatile_statuses = existing_conditions [2 ]
367- if existing_conditions [3 ]:
368- pkmn .terastallized = True
369- pkmn .types = existing_conditions [4 ]
370390 else :
371391 self .reserve .append (pkmn )
372392
@@ -432,7 +452,7 @@ def get_switches(self, reviving=False):
432452 it = filter (lambda p : p .hp > 0 , self .reserve )
433453
434454 for pkmn in it :
435- switches .append ("{} {}" . format ( constants . SWITCH_STRING , pkmn .name ))
455+ switches .append (MoveChoice ( id = pkmn .name , is_switch = True ))
436456 return switches
437457
438458 def to_dict (self ):
@@ -477,7 +497,9 @@ def __init__(self, name: str, level: int, nature="serious", evs=(85,) * 6):
477497 self .types = pokedex [self .name ][constants .TYPES ]
478498 self .item = constants .UNKNOWN_ITEM
479499
500+ self .can_terastallize = False
480501 self .terastallized = False
502+ self .tera_type = self .types [0 ]
481503 self .fainted = False
482504 self .reviving = False
483505 self .moves = []
@@ -679,17 +701,17 @@ def get_possible_moves(self, moves, battle_type=constants.STANDARD_BATTLE):
679701
680702 def forced_move (self ):
681703 if "phantomforce" in self .volatile_statuses :
682- return "phantomforce"
704+ return MoveChoice ( "phantomforce" )
683705 elif "shadowforce" in self .volatile_statuses :
684- return "shadowforce"
706+ return MoveChoice ( "shadowforce" )
685707 elif "dive" in self .volatile_statuses :
686- return "dive"
708+ return MoveChoice ( "dive" )
687709 elif "dig" in self .volatile_statuses :
688- return "dig"
710+ return MoveChoice ( "dig" )
689711 elif "bounce" in self .volatile_statuses :
690- return "bounce"
712+ return MoveChoice ( "bounce" )
691713 elif "fly" in self .volatile_statuses :
692- return "fly"
714+ return MoveChoice ( "fly" )
693715 else :
694716 return None
695717
@@ -710,6 +732,7 @@ def to_dict(self):
710732 constants .BOOSTS : self .boosts ,
711733 constants .STATUS : self .status ,
712734 constants .TERASTALLIZED : self .terastallized ,
735+ constants .TERA_TYPE : self .tera_type ,
713736 constants .VOLATILE_STATUS : set (self .volatile_statuses ),
714737 constants .MOVES : [m .to_dict () for m in self .moves ]
715738 }
0 commit comments