Skip to content

Commit 1a6dfb7

Browse files
committed
wip: terstallization
1 parent b696df3 commit 1a6dfb7

16 files changed

+2245
-1721
lines changed

constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
MUTATOR_CHANGE_TYPE = "change_type"
6767
MUTATOR_CHANGE_ITEM = "change_item"
6868
MUTATOR_CHANGE_STATS = "change_stats"
69+
MUTATOR_TERASTALLIZE = "terastallize"
6970

7071

7172
DAMAGE = 'damage'
@@ -116,6 +117,8 @@
116117
NATURE = "nature"
117118
EVS = "evs"
118119
TERASTALLIZED = "terastallized"
120+
TERA_TYPE = "tera_type"
121+
PS_TERA_TYPE = "teraType"
119122

120123
SIDE = "side"
121124
POKEMON = "pokemon"
@@ -133,6 +136,9 @@
133136
"gen6",
134137
"gen7"
135138
]
139+
TERASTALLIZE_GENERATIONS = [
140+
"gen9",
141+
]
136142
CAN_MEGA_EVO = "canMegaEvo"
137143
CAN_ULTRA_BURST = "canUltraBurst"
138144
CAN_DYNAMAX = "canDynamax"

showdown/battle.py

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from showdown.engine.objects import State
3131
from showdown.engine.objects import Side
3232
from showdown.engine.objects import Pokemon as TransposePokemon
33+
from showdown.engine.objects import MoveChoice
3334

3435
from showdown.engine.helpers import remove_duplicate_spreads
3536
from 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
}

showdown/battle_bots/helpers.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ def format_decision(battle, decision):
1616
# If the pokemon can mega-evolve, it will
1717
# If the move can be used as a Z-Move, it will be
1818

19-
if decision.startswith(constants.SWITCH_STRING + " "):
20-
switch_pokemon = decision.split("switch ")[-1]
19+
if decision.is_switch:
20+
switch_pokemon = decision.id
2121
for pkmn in battle.user.reserve:
2222
if pkmn.name == switch_pokemon:
2323
message = "/switch {}".format(pkmn.index)
2424
break
2525
else:
2626
raise ValueError("Tried to switch to: {}".format(switch_pokemon))
2727
else:
28-
message = "/choose move {}".format(decision)
28+
message = "/choose move {}".format(decision.id)
2929
if battle.user.active.can_mega_evo:
3030
message = "{} {}".format(message, constants.MEGA)
3131
elif battle.user.active.can_ultra_burst:
@@ -35,11 +35,10 @@ def format_decision(battle, decision):
3535
if battle.user.active.can_dynamax and all(p.hp == 0 for p in battle.user.reserve):
3636
message = "{} {}".format(message, constants.DYNAMAX)
3737

38-
# only terastallize on last pokemon. Come back to this later because this is bad.
39-
elif battle.user.active.can_terastallize and all(p.hp == 0 for p in battle.user.reserve):
38+
elif battle.user.active.can_terastallize and decision.terastallize:
4039
message = "{} {}".format(message, constants.TERASTALLIZE)
4140

42-
if battle.user.active.get_move(decision).can_z:
41+
if battle.user.active.get_move(decision.id).can_z:
4342
message = "{} {}".format(message, constants.ZMOVE)
4443

4544
return [message, str(battle.rqid)]

showdown/battle_bots/team_datasets/main.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ def set_most_likely_pokemon_from_team_datasets(pkmn):
2323
pkmn.ability = predicted_set.ability
2424
pkmn.item = predicted_set.item
2525
pkmn.set_spread(predicted_set.nature, predicted_set.evs)
26+
pkmn.tera_type = predicted_set.tera_type
2627
logger.debug(
27-
"Assumed set for opponent's {}:\t{} {} {} {} {}".format(
28-
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves)
28+
"Assumed set for opponent's {}:\t{} {} {} {} {} {}".format(
29+
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves, pkmn.tera_type)
2930
)
3031
return
3132

@@ -37,18 +38,18 @@ def set_most_likely_pokemon_from_team_datasets(pkmn):
3738
for mv in predicted_set.moves:
3839
pkmn.add_move(mv)
3940
pkmn.set_spread(predicted_set.nature, predicted_set.evs)
41+
pkmn.tera_type = predicted_set.tera_type
4042
logger.debug(
41-
"Assumed set for opponent's {}:\t{} {} {} {} {}".format(
42-
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves)
43+
"Assumed set for opponent's {}:\t{} {} {} {} {} {}".format(
44+
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves, pkmn.tera_type)
4345
)
44-
return
4546

4647
pkmn.guess_most_likely_attributes()
4748

4849
logger.debug(
49-
"Assumed set for opponent's {}:\t{} {} {} {} {}".format(
50-
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves)
51-
)
50+
"Assumed set for opponent's {}:\t{} {} {} {} {} {}".format(
51+
pkmn.name, pkmn.nature, pkmn.evs, pkmn.ability, pkmn.item, pkmn.moves, pkmn.tera_type)
52+
)
5253

5354

5455
def prepare_battles(battle):
@@ -87,6 +88,7 @@ def during_team_preview(self):
8788
for pkmn_obj in self.opponent.reserve:
8889
if pkmn_obj.name == pkmn:
8990
split_info = pkmn_info.split("|")
91+
pkmn_obj.tera_type = split_info[0]
9092
pkmn_obj.ability = split_info[1]
9193
pkmn_obj.item = split_info[2]
9294
pkmn_obj.set_spread(

showdown/battle_modifier.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,12 @@ def prepare(battle, split_msg):
437437
def terastallize(battle, split_msg):
438438
if is_opponent(battle, split_msg):
439439
pkmn = battle.opponent.active
440+
side = battle.opponent
440441
else:
441442
pkmn = battle.user.active
443+
side = battle.user
442444

445+
side.used_tera = True
443446
pkmn.terastallized = True
444447
pkmn.types = [normalize_name(split_msg[3])]
445448
logger.debug("Terastallized {}".format(pkmn.name))

0 commit comments

Comments
 (0)