Skip to content

Commit ddcfb31

Browse files
got strict tests to pass once
1 parent c2626ea commit ddcfb31

File tree

2 files changed

+114
-45
lines changed

2 files changed

+114
-45
lines changed

src/poke_env/battle/abstract_battle.py

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,9 @@ def _check_damage_message_for_ability(self, split_message: List[str]):
319319
):
320320
ability = split_message[4].split("ability:")[-1]
321321
pkmn = split_message[5].split("[of]")[-1].strip()
322-
self.get_pokemon(pkmn).ability = to_id_str(ability)
322+
pkmn_object = self.get_pokemon(pkmn)
323+
if pkmn_object.ability is None:
324+
pkmn_object.ability = ability
323325

324326
def _check_heal_message_for_item(self, split_message: List[str]):
325327
# Catches when a side heals from it's own item
@@ -346,10 +348,14 @@ def _check_heal_message_for_ability(self, split_message: List[str]):
346348
ability = to_id_str(split_message[4].split("ability:")[-1])
347349
if ability == "hospitality":
348350
pkmn = split_message[5].replace("[of] ", "").strip()
349-
self.get_pokemon(pkmn).ability = ability
351+
pkmn_object = self.get_pokemon(pkmn)
352+
if pkmn_object.ability is None:
353+
pkmn_object.ability = ability
350354
else:
351355
pkmn = split_message[2]
352-
self.get_pokemon(pkmn).ability = ability
356+
pkmn_object = self.get_pokemon(pkmn)
357+
if pkmn_object.ability is None:
358+
pkmn_object.ability = ability
353359

354360
@abstractmethod
355361
def end_illusion(self, pokemon_name: str, details: str):
@@ -529,7 +535,9 @@ def parse_message(self, split_message: List[str]):
529535
revealed_ability = event.pop().split(": ")[-1]
530536

531537
pokemon = event[2]
532-
self.get_pokemon(pokemon).ability = revealed_ability
538+
mon = self.get_pokemon(pokemon)
539+
if mon.ability is None:
540+
mon.ability = revealed_ability
533541

534542
if revealed_ability == "Magic Bounce":
535543
return
@@ -672,6 +680,13 @@ def parse_message(self, split_message: List[str]):
672680
self.get_pokemon(pokemon).boost(stat, -int(amount))
673681
elif event[1] == "-ability":
674682
pokemon, cause = event[2:4]
683+
mon = self.get_pokemon(pokemon)
684+
if (
685+
mon.ability is not None
686+
and mon.ability in ["asoneglastrier", "asonespectrier"]
687+
and event[3] in ["asone", "unnerve"]
688+
):
689+
return
675690
if (
676691
len(event) > 4
677692
and (
@@ -685,11 +700,13 @@ def parse_message(self, split_message: List[str]):
685700
or event[5].startswith("[from] ability: Trace")
686701
)
687702
):
688-
self.get_pokemon(pokemon).set_temporary_ability(cause)
703+
if mon.ability is None or mon._ability == to_id_str(cause):
704+
mon.ability = "trace"
705+
mon.temporary_ability = cause
689706
elif cause == "Neutralizing Gas":
690707
self.field_start(cause)
691-
else:
692-
self.get_pokemon(pokemon).ability = cause
708+
elif mon.ability is None:
709+
mon.ability = cause
693710
elif split_message[1] == "-start":
694711
pokemon, effect = event[2:4]
695712
mon = self.get_pokemon(pokemon)
@@ -720,10 +737,15 @@ def parse_message(self, split_message: List[str]):
720737
if target and effect == "move: Skill Swap":
721738
self.get_pokemon(target).start_effect(effect, event[4:6])
722739
actor = event[6].replace("[of] ", "")
723-
self.get_pokemon(actor).set_temporary_ability(event[5])
740+
self.get_pokemon(actor).temporary_ability = event[5]
724741
elif effect == "ability: Mummy":
725742
target = event[5].replace("[of] ", "")
726-
self.get_pokemon(target).set_temporary_ability("mummy")
743+
self.get_pokemon(target).temporary_ability = "mummy"
744+
elif effect == "ability: Wandering Spirit":
745+
actor = event[2]
746+
target = event[6].replace("[of] ", "")
747+
self.get_pokemon(actor).temporary_ability = event[4]
748+
self.get_pokemon(target).temporary_ability = "wanderingspirit"
727749
elif effect == "ability: Symbiosis":
728750
self.get_pokemon(event[5].replace("[of] ", "")).item = event[4].replace(
729751
"[item] ", ""
@@ -769,7 +791,7 @@ def parse_message(self, split_message: List[str]):
769791
self.get_pokemon(pokemon).end_effect(effect)
770792
elif event[1] == "-endability":
771793
pokemon = event[2]
772-
self.get_pokemon(pokemon).set_temporary_ability(None)
794+
self.get_pokemon(pokemon).temporary_ability = None
773795
elif event[1] == "-enditem":
774796
pokemon, item = event[2:4]
775797
self.get_pokemon(pokemon).end_item(item)
@@ -801,22 +823,27 @@ def parse_message(self, split_message: List[str]):
801823
elif mon == self.opponent_active_pokemon:
802824
self.active_pokemon.item = to_id_str(item)
803825

804-
mon.ability = to_id_str("frisk")
826+
if mon.ability is None:
827+
mon.ability = "frisk"
805828
elif cause == "[from] ability: Pickpocket":
806829
pickpocket = event[2]
807830
pickpocketed = event[5].replace("[of] ", "")
808831
item = event[3]
809832

810-
self.get_pokemon(pickpocket).item = to_id_str(item)
811-
self.get_pokemon(pickpocket).ability = to_id_str("pickpocket")
833+
pickpocket = self.get_pokemon(pickpocket)
834+
pickpocket.item = to_id_str(item)
835+
if pickpocket.ability is None:
836+
pickpocket.ability = "pickpocket"
812837
self.get_pokemon(pickpocketed).item = None
813838
elif cause == "[from] ability: Magician":
814839
magician = event[2]
815840
victim = event[5].replace("[of] ", "")
816841
item = event[3]
817842

818-
self.get_pokemon(magician).item = to_id_str(item)
819-
self.get_pokemon(magician).ability = to_id_str("magician")
843+
magician = self.get_pokemon(magician)
844+
magician.item = to_id_str(item)
845+
if magician.ability is None:
846+
magician.ability = "magician"
820847
self.get_pokemon(victim).item = None
821848
elif cause in {"[from] move: Thief", "[from] move: Covet"}:
822849
thief = event[2]
@@ -994,7 +1021,9 @@ def parse_message(self, split_message: List[str]):
9941021

9951022
if cause.startswith("[from] ability:"):
9961023
cause = cause.replace("[from] ability:", "")
997-
self.get_pokemon(pokemon).ability = to_id_str(cause)
1024+
mon = self.get_pokemon(pokemon)
1025+
if mon.ability is None:
1026+
mon.ability = cause
9981027
elif event[1] == "-swapsideconditions":
9991028
self._side_conditions, self._opponent_side_conditions = (
10001029
self._opponent_side_conditions,

src/poke_env/battle/pokemon.py

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
from poke_env.stats import compute_raw_stats
1414
from poke_env.teambuilder.teambuilder_pokemon import TeambuilderPokemon
1515

16-
_NO_ABILITY = "NO_ABILITY"
17-
1816

1917
class 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)}\nrequest: {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

Comments
 (0)