1313from poke_env .stats import compute_raw_stats
1414from poke_env .teambuilder .teambuilder_pokemon import TeambuilderPokemon
1515
16- _NO_ABILITY = "NO_ABILITY"
17-
1816
1917class Pokemon :
2018 __slots__ = (
@@ -34,6 +32,7 @@ class Pokemon:
3432 "_last_request" ,
3533 "_level" ,
3634 "_max_hp" ,
35+ "_mega_ability" ,
3736 "_moves" ,
3837 "_must_recharge" ,
3938 "_name" ,
@@ -123,6 +122,7 @@ def __init__(
123122 self ._status : Optional [Status ] = None
124123 self ._status_counter : int = 0
125124 self ._temporary_ability : Optional [str ] = None
125+ self ._mega_ability : Optional [str ] = None
126126 self ._temporary_types : List [PokemonType ] = []
127127
128128 if request_pokemon :
@@ -269,6 +269,7 @@ def end_turn(self):
269269 def faint (self ):
270270 self ._current_hp = 0
271271 self ._status = Status .FNT
272+ self .temporary_ability = None
272273 self ._clear_effects ()
273274
274275 def forme_change (self , species : str ):
@@ -290,6 +291,7 @@ def mega_evolve(self, stone: str):
290291 if not species_id_str .endswith ("mega" )
291292 else species_id_str
292293 )
294+ self .temporary_ability = None
293295 if mega_species in self ._data .pokedex :
294296 self ._update_from_pokedex (mega_species , store_species = False )
295297 elif stone [- 1 ] in "XYxy" :
@@ -398,12 +400,6 @@ def set_hp_status(self, hp_status: str, store=False):
398400 if store :
399401 self ._stats ["hp" ] = self ._max_hp
400402
401- def set_temporary_ability (self , ability : Optional [str ]):
402- if ability is not None :
403- self ._temporary_ability = to_id_str (ability )
404- else :
405- self ._temporary_ability = _NO_ABILITY
406-
407403 def start_effect (self , effect_str : str , details : Optional [Any ] = None ):
408404 effect = Effect .from_showdown_message (effect_str )
409405 if effect not in self ._effects :
@@ -419,11 +415,10 @@ def start_effect(self, effect_str: str, details: Optional[Any] = None):
419415 for type_ in details .split ("/" ):
420416 self ._temporary_types .append (PokemonType .from_name (type_ ))
421417 elif effect == Effect .SKILL_SWAP and details :
422- self .set_temporary_ability (details [0 ])
423-
424418 # Skill Swap reveals a mon's ability
425419 if self .ability is None :
426- self ._ability = to_id_str (details [1 ])
420+ self .ability = details [1 ]
421+ self .temporary_ability = details [0 ]
427422
428423 def _swap_boosts (self ):
429424 self ._boosts ["atk" ], self ._boosts ["spa" ] = (
@@ -459,7 +454,7 @@ def switch_out(self, fields: Dict[Field, int]):
459454 self ._preparing_move = None
460455 self ._preparing_target = None
461456 self ._protect_counter = 0
462- self ._temporary_ability = None
457+ self .temporary_ability = None
463458 self ._temporary_types = []
464459
465460 if self ._status == Status .TOX :
@@ -489,12 +484,16 @@ def _update_from_pokedex(self, species: str, store_species: bool = True):
489484 else :
490485 self ._type_2 = PokemonType .from_name (dex_entry ["types" ][1 ])
491486
492- self ._possible_abilities = [
493- to_id_str (ability ) for ability in dex_entry ["abilities" ].values ()
494- ]
495-
496- if len (self ._possible_abilities ) == 1 :
497- self .ability = self ._possible_abilities [0 ]
487+ if "forme" in dex_entry and dex_entry ["forme" ].startswith ("Mega" ):
488+ self .mega_ability = dex_entry ["abilities" ]["0" ]
489+ elif self .mega_ability is None :
490+ self ._possible_abilities = [
491+ to_id_str (ability ) for ability in dex_entry ["abilities" ].values ()
492+ ]
493+ if len (self ._possible_abilities ) == 1 :
494+ self .ability = self ._possible_abilities [0 ]
495+ else :
496+ self .mega_ability = None
498497
499498 self ._heightm = dex_entry ["heightm" ]
500499 self ._weightkg = dex_entry ["weightkg" ]
@@ -552,10 +551,13 @@ def update_from_request(self, request_pokemon: Dict[str, Any]):
552551 if request_pokemon == self ._last_request :
553552 return
554553
555- if "ability" in request_pokemon :
556- self .ability = request_pokemon ["ability" ]
557- elif "baseAbility" in request_pokemon :
554+ if self .ability is None :
558555 self .ability = request_pokemon ["baseAbility" ]
556+ if (
557+ "ability" in request_pokemon
558+ and request_pokemon ["ability" ] != request_pokemon ["baseAbility" ]
559+ ):
560+ self .temporary_ability = request_pokemon ["ability" ]
559561
560562 self ._last_request = request_pokemon
561563
@@ -634,6 +636,15 @@ def check_consistency(self, pkmn_request: Dict[str, Any], player_role: str):
634636 assert Move .retrieve_id (move_request ) == Move .retrieve_id (
635637 move .id
636638 ), f"{ Move .retrieve_id (move_request )} != { Move .retrieve_id (move .id )} \n request: { pkmn_request } "
639+ if self .ability is None :
640+ self .ability = pkmn_request ["baseAbility" ]
641+ assert pkmn_request ["baseAbility" ] == (
642+ self .base_ability or ""
643+ ), f"{ pkmn_request ['baseAbility' ]} != { self .base_ability or '' } "
644+ if "ability" in pkmn_request :
645+ assert pkmn_request ["ability" ] == (
646+ self .ability or ""
647+ ), f"{ pkmn_request ['ability' ]} != { self .ability or '' } "
637648
638649 def _update_from_teambuilder (self , tb : TeambuilderPokemon ):
639650 if tb .nickname is not None and tb .species is None :
@@ -760,19 +771,16 @@ def ability(self) -> Optional[str]:
760771 :return: The pokemon's ability. None if unknown or removed.
761772 :rtype: str, optional
762773 """
763- if self ._temporary_ability == _NO_ABILITY :
764- return None
765- elif self ._temporary_ability is not None :
774+ if self ._temporary_ability is not None :
766775 return self ._temporary_ability
776+ elif self .mega_ability is not None :
777+ return self .mega_ability
767778 else :
768779 return self ._ability
769780
770781 @ability .setter
771- def ability (self , ability : Optional [str ]):
772- if ability is None :
773- self ._ability = None
774- else :
775- self ._ability = to_id_str (ability )
782+ def ability (self , ability : str ):
783+ self ._ability = to_id_str (ability )
776784
777785 @property
778786 def active (self ) -> Optional [bool ]:
@@ -806,6 +814,14 @@ def available_z_moves(self) -> List[Move]:
806814 return [self ._moves [move ]]
807815 return []
808816
817+ @property
818+ def base_ability (self ) -> Optional [str ]:
819+ """
820+ :return: The pokemon's base ability. None if unknown.
821+ :rtype: str, optional
822+ """
823+ return self ._mega_ability or self ._ability
824+
809825 @property
810826 def base_species (self ) -> str :
811827 """
@@ -961,6 +977,18 @@ def max_hp(self) -> int:
961977 """
962978 return self ._max_hp or 0
963979
980+ @property
981+ def mega_ability (self ) -> Optional [str ]:
982+ """
983+ :return: The pokemon's mega ability. None if the pokemon is not mega evolved.
984+ :rtype: str, optional
985+ """
986+ return self ._mega_ability
987+
988+ @mega_ability .setter
989+ def mega_ability (self , ability : Optional [str ]):
990+ self ._mega_ability = to_id_str (ability ) if ability is not None else None
991+
964992 @property
965993 def moves (self ) -> Dict [str , Move ]:
966994 """
@@ -1135,6 +1163,18 @@ def stab_multiplier(self) -> float:
11351163 return 2
11361164 return 1.5
11371165
1166+ @property
1167+ def temporary_ability (self ) -> str | None :
1168+ """
1169+ :return: The pokemon's temporary ability, None if none is set.
1170+ :rtype: Optional[str]
1171+ """
1172+ return self ._temporary_ability
1173+
1174+ @temporary_ability .setter
1175+ def temporary_ability (self , ability : str | None ):
1176+ self ._temporary_ability = to_id_str (ability ) if ability is not None else None
1177+
11381178 @property
11391179 def tera_type (self ) -> Optional [PokemonType ]:
11401180 """
0 commit comments