349 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			349 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								from copy import deepcopy
							 | 
						||
| 
								 | 
							
								from . import poke_data
							 | 
						||
| 
								 | 
							
								from .rom_addresses import rom_addresses
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def set_mon_palettes(self, random, data):
							 | 
						||
| 
								 | 
							
								    if self.multiworld.randomize_pokemon_palettes[self.player] == "vanilla":
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								    pallet_map = {
							 | 
						||
| 
								 | 
							
								        "Poison": 0x0F,
							 | 
						||
| 
								 | 
							
								        "Normal": 0x10,
							 | 
						||
| 
								 | 
							
								        "Ice": 0x11,
							 | 
						||
| 
								 | 
							
								        "Fire": 0x12,
							 | 
						||
| 
								 | 
							
								        "Water": 0x13,
							 | 
						||
| 
								 | 
							
								        "Ghost": 0x14,
							 | 
						||
| 
								 | 
							
								        "Ground": 0x15,
							 | 
						||
| 
								 | 
							
								        "Grass": 0x16,
							 | 
						||
| 
								 | 
							
								        "Psychic": 0x17,
							 | 
						||
| 
								 | 
							
								        "Electric": 0x18,
							 | 
						||
| 
								 | 
							
								        "Rock": 0x19,
							 | 
						||
| 
								 | 
							
								        "Dragon": 0x1F,
							 | 
						||
| 
								 | 
							
								        "Flying": 0x20,
							 | 
						||
| 
								 | 
							
								        "Fighting": 0x21,
							 | 
						||
| 
								 | 
							
								        "Bug": 0x22
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    palettes = []
							 | 
						||
| 
								 | 
							
								    for mon in poke_data.pokemon_data:
							 | 
						||
| 
								 | 
							
								        if self.multiworld.randomize_pokemon_palettes[self.player] == "primary_type":
							 | 
						||
| 
								 | 
							
								            pallet = pallet_map[self.local_poke_data[mon]["type1"]]
							 | 
						||
| 
								 | 
							
								        elif (self.multiworld.randomize_pokemon_palettes[self.player] == "follow_evolutions" and mon in
							 | 
						||
| 
								 | 
							
								              poke_data.evolves_from and poke_data.evolves_from[mon] != "Eevee"):
							 | 
						||
| 
								 | 
							
								            pallet = palettes[-1]
							 | 
						||
| 
								 | 
							
								        else:  # completely_random or follow_evolutions and it is not an evolved form (except eeveelutions)
							 | 
						||
| 
								 | 
							
								            pallet = random.choice(list(pallet_map.values()))
							 | 
						||
| 
								 | 
							
								        palettes.append(pallet)
							 | 
						||
| 
								 | 
							
								    address = rom_addresses["Mon_Palettes"]
							 | 
						||
| 
								 | 
							
								    for pallet in palettes:
							 | 
						||
| 
								 | 
							
								        data[address] = pallet
							 | 
						||
| 
								 | 
							
								        address += 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def choose_forced_type(chances, random):
							 | 
						||
| 
								 | 
							
								    n = random.randint(1, 100)
							 | 
						||
| 
								 | 
							
								    for chance in chances:
							 | 
						||
| 
								 | 
							
								        if chance[0] >= n:
							 | 
						||
| 
								 | 
							
								            return chance[1]
							 | 
						||
| 
								 | 
							
								    return None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def filter_moves(local_move_data, moves, type, random):
							 | 
						||
| 
								 | 
							
								    ret = []
							 | 
						||
| 
								 | 
							
								    for move in moves:
							 | 
						||
| 
								 | 
							
								        if local_move_data[move]["type"] == type or type is None:
							 | 
						||
| 
								 | 
							
								            ret.append(move)
							 | 
						||
| 
								 | 
							
								    random.shuffle(ret)
							 | 
						||
| 
								 | 
							
								    return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def get_move(local_move_data, moves, chances, random, starting_move=False):
							 | 
						||
| 
								 | 
							
								    type = choose_forced_type(chances, random)
							 | 
						||
| 
								 | 
							
								    filtered_moves = filter_moves(local_move_data, moves, type, random)
							 | 
						||
| 
								 | 
							
								    for move in filtered_moves:
							 | 
						||
| 
								 | 
							
								        if (not starting_move) or (local_move_data[move]["accuracy"] > 80 and local_move_data[move]["power"] > 0):
							 | 
						||
| 
								 | 
							
								            moves.remove(move)
							 | 
						||
| 
								 | 
							
								            return move
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return get_move(local_move_data, moves, [], random, starting_move)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def move_power(move_data):
							 | 
						||
| 
								 | 
							
								    power = move_data["power"]
							 | 
						||
| 
								 | 
							
								    if move_data["effect"] in (29, 42):
							 | 
						||
| 
								 | 
							
								        # 29: two-to-five attacks. 42: trapping effect, two-to-five turns.
							 | 
						||
| 
								 | 
							
								        power *= 3
							 | 
						||
| 
								 | 
							
								    elif move_data["effect"] in (77, 44):
							 | 
						||
| 
								 | 
							
								        # 77: Twineedle. Two attacks and poison chance. 44: Just two attacks
							 | 
						||
| 
								 | 
							
								        power *= 2
							 | 
						||
| 
								 | 
							
								    elif move_data["effect"] == 48:
							 | 
						||
| 
								 | 
							
								        # 25% recoil damage taken. Reduce power considered by that amount
							 | 
						||
| 
								 | 
							
								        power *= 0.75
							 | 
						||
| 
								 | 
							
								    elif move_data["effect"] == 3:
							 | 
						||
| 
								 | 
							
								        # 50% absorb. Increase power considered by that amount
							 | 
						||
| 
								 | 
							
								        power *= 1.5
							 | 
						||
| 
								 | 
							
								    elif move_data["effect"] == 39 and move_data["id"] != 91:
							 | 
						||
| 
								 | 
							
								        # Takes two turns while vulnerable. Dig uses this effect ID but is semi-invulnerable
							 | 
						||
| 
								 | 
							
								        power *= 0.66
							 | 
						||
| 
								 | 
							
								    elif move_data["effect"] == 7:
							 | 
						||
| 
								 | 
							
								        # Faint user
							 | 
						||
| 
								 | 
							
								        power *= 0.5
							 | 
						||
| 
								 | 
							
								    elif move_data["id"] in (2, 75, 152, 163,):
							 | 
						||
| 
								 | 
							
								        # High critical strike moves: Karate Chop, Razor Leaf, Crabhammer, Slash
							 | 
						||
| 
								 | 
							
								        power *= 2
							 | 
						||
| 
								 | 
							
								    return power
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def process_move_data(self):
							 | 
						||
| 
								 | 
							
								    self.local_move_data = deepcopy(poke_data.moves)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if self.multiworld.randomize_move_types[self.player]:
							 | 
						||
| 
								 | 
							
								        for move, data in self.local_move_data.items():
							 | 
						||
| 
								 | 
							
								            if move == "No Move":
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								            # The chance of randomized moves choosing a normal type move is high, so we want to retain having a higher
							 | 
						||
| 
								 | 
							
								            # rate of normal type moves
							 | 
						||
| 
								 | 
							
								            data["type"] = self.multiworld.random.choice(list(poke_data.type_ids) + (["Normal"] * 4))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if self.multiworld.move_balancing[self.player]:
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Sing"]["accuracy"] = 30
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Sleep Powder"]["accuracy"] = 40
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Spore"]["accuracy"] = 50
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Sonicboom"]["effect"] = 0
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Sonicboom"]["power"] = 50
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Dragon Rage"]["effect"] = 0
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Dragon Rage"]["power"] = 80
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Horn Drill"]["effect"] = 0
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Horn Drill"]["power"] = 70
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Horn Drill"]["accuracy"] = 90
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Guillotine"]["effect"] = 0
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Guillotine"]["power"] = 70
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Guillotine"]["accuracy"] = 90
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Fissure"]["effect"] = 0
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Fissure"]["power"] = 70
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Fissure"]["accuracy"] = 90
							 | 
						||
| 
								 | 
							
								        self.local_move_data["Blizzard"]["accuracy"] = 70
							 | 
						||
| 
								 | 
							
								    if self.multiworld.randomize_tm_moves[self.player]:
							 | 
						||
| 
								 | 
							
								        self.local_tms = self.multiworld.random.sample([move for move in poke_data.moves.keys() if move not in
							 | 
						||
| 
								 | 
							
								                                                        ["No Move"] + poke_data.hm_moves], 50)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        self.local_tms = poke_data.tm_moves.copy()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def process_pokemon_data(self):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    local_poke_data = deepcopy(poke_data.pokemon_data)
							 | 
						||
| 
								 | 
							
								    learnsets = deepcopy(poke_data.learnsets)
							 | 
						||
| 
								 | 
							
								    tms_hms = self.local_tms + poke_data.hm_moves
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    compat_hms = set()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for mon, mon_data in local_poke_data.items():
							 | 
						||
| 
								 | 
							
								        if self.multiworld.randomize_pokemon_stats[self.player] == "shuffle":
							 | 
						||
| 
								 | 
							
								            stats = [mon_data["hp"], mon_data["atk"], mon_data["def"], mon_data["spd"], mon_data["spc"]]
							 | 
						||
| 
								 | 
							
								            if mon in poke_data.evolves_from:
							 | 
						||
| 
								 | 
							
								                stat_shuffle_map = local_poke_data[poke_data.evolves_from[mon]]["stat_shuffle_map"]
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                stat_shuffle_map = self.multiworld.random.sample(range(0, 5), 5)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            mon_data["stat_shuffle_map"] = stat_shuffle_map
							 | 
						||
| 
								 | 
							
								            mon_data["hp"] = stats[stat_shuffle_map[0]]
							 | 
						||
| 
								 | 
							
								            mon_data["atk"] = stats[stat_shuffle_map[1]]
							 | 
						||
| 
								 | 
							
								            mon_data["def"] = stats[stat_shuffle_map[2]]
							 | 
						||
| 
								 | 
							
								            mon_data["spd"] = stats[stat_shuffle_map[3]]
							 | 
						||
| 
								 | 
							
								            mon_data["spc"] = stats[stat_shuffle_map[4]]
							 | 
						||
| 
								 | 
							
								        elif self.multiworld.randomize_pokemon_stats[self.player] == "randomize":
							 | 
						||
| 
								 | 
							
								            first_run = True
							 | 
						||
| 
								 | 
							
								            while (mon_data["hp"] > 255 or mon_data["atk"] > 255 or mon_data["def"] > 255 or mon_data["spd"] > 255
							 | 
						||
| 
								 | 
							
								                   or mon_data["spc"] > 255 or first_run):
							 | 
						||
| 
								 | 
							
								                first_run = False
							 | 
						||
| 
								 | 
							
								                total_stats = mon_data["hp"] + mon_data["atk"] + mon_data["def"] + mon_data["spd"] + mon_data["spc"]
							 | 
						||
| 
								 | 
							
								                for stat in ("hp", "atk", "def", "spd", "spc"):
							 | 
						||
| 
								 | 
							
								                    if mon in poke_data.evolves_from:
							 | 
						||
| 
								 | 
							
								                        mon_data[stat] = local_poke_data[poke_data.evolves_from[mon]][stat]
							 | 
						||
| 
								 | 
							
								                        total_stats -= mon_data[stat]
							 | 
						||
| 
								 | 
							
								                    elif stat == "hp":
							 | 
						||
| 
								 | 
							
								                        mon_data[stat] = 20
							 | 
						||
| 
								 | 
							
								                        total_stats -= 20
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        mon_data[stat] = 10
							 | 
						||
| 
								 | 
							
								                        total_stats -= 10
							 | 
						||
| 
								 | 
							
								                assert total_stats >= 0, f"Error distributing stats for {mon} for player {self.player}"
							 | 
						||
| 
								 | 
							
								                dist = [self.multiworld.random.randint(1, 101) / 100, self.multiworld.random.randint(1, 101) / 100,
							 | 
						||
| 
								 | 
							
								                        self.multiworld.random.randint(1, 101) / 100, self.multiworld.random.randint(1, 101) / 100,
							 | 
						||
| 
								 | 
							
								                        self.multiworld.random.randint(1, 101) / 100]
							 | 
						||
| 
								 | 
							
								                total_dist = sum(dist)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                mon_data["hp"] += int(round(dist[0] / total_dist * total_stats))
							 | 
						||
| 
								 | 
							
								                mon_data["atk"] += int(round(dist[1] / total_dist * total_stats))
							 | 
						||
| 
								 | 
							
								                mon_data["def"] += int(round(dist[2] / total_dist * total_stats))
							 | 
						||
| 
								 | 
							
								                mon_data["spd"] += int(round(dist[3] / total_dist * total_stats))
							 | 
						||
| 
								 | 
							
								                mon_data["spc"] += int(round(dist[4] / total_dist * total_stats))
							 | 
						||
| 
								 | 
							
								        if self.multiworld.randomize_pokemon_types[self.player]:
							 | 
						||
| 
								 | 
							
								            if self.multiworld.randomize_pokemon_types[self.player].value == 1 and mon in poke_data.evolves_from:
							 | 
						||
| 
								 | 
							
								                type1 = local_poke_data[poke_data.evolves_from[mon]]["type1"]
							 | 
						||
| 
								 | 
							
								                type2 = local_poke_data[poke_data.evolves_from[mon]]["type2"]
							 | 
						||
| 
								 | 
							
								                if type1 == type2:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.secondary_type_chance[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        if mon_data["type1"] != mon_data["type2"]:
							 | 
						||
| 
								 | 
							
								                            while type2 == type1:
							 | 
						||
| 
								 | 
							
								                                type2 = self.multiworld.random.choice(list(poke_data.type_names.values()))
							 | 
						||
| 
								 | 
							
								                    elif self.multiworld.random.randint(1, 100) <= self.multiworld.secondary_type_chance[self.player].value:
							 | 
						||
| 
								 | 
							
								                        type2 = self.multiworld.random.choice(list(poke_data.type_names.values()))
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                type1 = self.multiworld.random.choice(list(poke_data.type_names.values()))
							 | 
						||
| 
								 | 
							
								                type2 = type1
							 | 
						||
| 
								 | 
							
								                if ((self.multiworld.secondary_type_chance[self.player].value == -1 and mon_data["type1"]
							 | 
						||
| 
								 | 
							
								                     != mon_data["type2"]) or self.multiworld.random.randint(1, 100)
							 | 
						||
| 
								 | 
							
								                        <= self.multiworld.secondary_type_chance[self.player].value):
							 | 
						||
| 
								 | 
							
								                    while type2 == type1:
							 | 
						||
| 
								 | 
							
								                        type2 = self.multiworld.random.choice(list(poke_data.type_names.values()))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            mon_data["type1"] = type1
							 | 
						||
| 
								 | 
							
								            mon_data["type2"] = type2
							 | 
						||
| 
								 | 
							
								        if self.multiworld.randomize_pokemon_movesets[self.player]:
							 | 
						||
| 
								 | 
							
								            if self.multiworld.randomize_pokemon_movesets[self.player] == "prefer_types":
							 | 
						||
| 
								 | 
							
								                if mon_data["type1"] == "Normal" and mon_data["type2"] == "Normal":
							 | 
						||
| 
								 | 
							
								                    chances = [[75, "Normal"]]
							 | 
						||
| 
								 | 
							
								                elif mon_data["type1"] == "Normal" or mon_data["type2"] == "Normal":
							 | 
						||
| 
								 | 
							
								                    if mon_data["type1"] == "Normal":
							 | 
						||
| 
								 | 
							
								                        second_type = mon_data["type2"]
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        second_type = mon_data["type1"]
							 | 
						||
| 
								 | 
							
								                    chances = [[30, "Normal"], [85, second_type]]
							 | 
						||
| 
								 | 
							
								                elif mon_data["type1"] == mon_data["type2"]:
							 | 
						||
| 
								 | 
							
								                    chances = [[60, mon_data["type1"]], [80, "Normal"]]
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    chances = [[50, mon_data["type1"]], [80, mon_data["type2"]], [85, "Normal"]]
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                chances = []
							 | 
						||
| 
								 | 
							
								            moves = list(poke_data.moves.keys())
							 | 
						||
| 
								 | 
							
								            for move in ["No Move"] + poke_data.hm_moves:
							 | 
						||
| 
								 | 
							
								                moves.remove(move)
							 | 
						||
| 
								 | 
							
								            if self.multiworld.confine_transform_to_ditto[self.player]:
							 | 
						||
| 
								 | 
							
								                moves.remove("Transform")
							 | 
						||
| 
								 | 
							
								            if self.multiworld.start_with_four_moves[self.player]:
							 | 
						||
| 
								 | 
							
								                num_moves = 4
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                num_moves = len([i for i in [mon_data["start move 1"], mon_data["start move 2"],
							 | 
						||
| 
								 | 
							
								                                             mon_data["start move 3"], mon_data["start move 4"]] if i != "No Move"])
							 | 
						||
| 
								 | 
							
								            if mon in learnsets:
							 | 
						||
| 
								 | 
							
								                num_moves += len(learnsets[mon])
							 | 
						||
| 
								 | 
							
								            non_power_moves = []
							 | 
						||
| 
								 | 
							
								            learnsets[mon] = []
							 | 
						||
| 
								 | 
							
								            for i in range(num_moves):
							 | 
						||
| 
								 | 
							
								                if i == 0 and mon == "Ditto" and self.multiworld.confine_transform_to_ditto[self.player]:
							 | 
						||
| 
								 | 
							
								                    move = "Transform"
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    move = get_move(self.local_move_data, moves, chances, self.multiworld.random)
							 | 
						||
| 
								 | 
							
								                    while move == "Transform" and self.multiworld.confine_transform_to_ditto[self.player]:
							 | 
						||
| 
								 | 
							
								                        move = get_move(self.local_move_data, moves, chances, self.multiworld.random)
							 | 
						||
| 
								 | 
							
								                if self.local_move_data[move]["power"] < 5:
							 | 
						||
| 
								 | 
							
								                    non_power_moves.append(move)
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    learnsets[mon].append(move)
							 | 
						||
| 
								 | 
							
								            learnsets[mon].sort(key=lambda move: move_power(self.local_move_data[move]))
							 | 
						||
| 
								 | 
							
								            if learnsets[mon]:
							 | 
						||
| 
								 | 
							
								                for move in non_power_moves:
							 | 
						||
| 
								 | 
							
								                    learnsets[mon].insert(self.multiworld.random.randint(1, len(learnsets[mon])), move)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                learnsets[mon] = non_power_moves
							 | 
						||
| 
								 | 
							
								            for i in range(1, 5):
							 | 
						||
| 
								 | 
							
								                if mon_data[f"start move {i}"] != "No Move" or self.multiworld.start_with_four_moves[self.player]:
							 | 
						||
| 
								 | 
							
								                    mon_data[f"start move {i}"] = learnsets[mon].pop(0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if self.multiworld.randomize_pokemon_catch_rates[self.player]:
							 | 
						||
| 
								 | 
							
								            mon_data["catch rate"] = self.multiworld.random.randint(self.multiworld.minimum_catch_rate[self.player],
							 | 
						||
| 
								 | 
							
								                                                                    255)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            mon_data["catch rate"] = max(self.multiworld.minimum_catch_rate[self.player], mon_data["catch rate"])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def roll_tm_compat(roll_move):
							 | 
						||
| 
								 | 
							
								            if self.local_move_data[roll_move]["type"] in [mon_data["type1"], mon_data["type2"]]:
							 | 
						||
| 
								 | 
							
								                if roll_move in poke_data.hm_moves:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.hm_same_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_same_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								                    if r and mon not in poke_data.legendary_pokemon:
							 | 
						||
| 
								 | 
							
								                        compat_hms.add(roll_move)
							 | 
						||
| 
								 | 
							
								                    return r
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.tm_same_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_same_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								            elif self.local_move_data[roll_move]["type"] == "Normal" and "Normal" not in [mon_data["type1"], mon_data["type2"]]:
							 | 
						||
| 
								 | 
							
								                if roll_move in poke_data.hm_moves:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.hm_normal_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_normal_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								                    if r and mon not in poke_data.legendary_pokemon:
							 | 
						||
| 
								 | 
							
								                        compat_hms.add(roll_move)
							 | 
						||
| 
								 | 
							
								                    return r
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.tm_normal_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_normal_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                if roll_move in poke_data.hm_moves:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.hm_other_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_other_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								                    if r and mon not in poke_data.legendary_pokemon:
							 | 
						||
| 
								 | 
							
								                        compat_hms.add(roll_move)
							 | 
						||
| 
								 | 
							
								                    return r
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    if self.multiworld.tm_other_type_compatibility[self.player].value == -1:
							 | 
						||
| 
								 | 
							
								                        return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								                    return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_other_type_compatibility[self.player].value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for flag, tm_move in enumerate(tms_hms):
							 | 
						||
| 
								 | 
							
								            if mon in poke_data.evolves_from and self.multiworld.inherit_tm_hm_compatibility[self.player]:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if local_poke_data[poke_data.evolves_from[mon]]["tms"][int(flag / 8)] & 1 << (flag % 8):
							 | 
						||
| 
								 | 
							
								                    # always inherit learnable tms/hms
							 | 
						||
| 
								 | 
							
								                    bit = 1
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    if self.local_move_data[tm_move]["type"] in [mon_data["type1"], mon_data["type2"]] and \
							 | 
						||
| 
								 | 
							
								                            self.local_move_data[tm_move]["type"] not in [
							 | 
						||
| 
								 | 
							
								                            local_poke_data[poke_data.evolves_from[mon]]["type1"],
							 | 
						||
| 
								 | 
							
								                            local_poke_data[poke_data.evolves_from[mon]]["type2"]]:
							 | 
						||
| 
								 | 
							
								                        # the tm/hm is for a move whose type matches current mon, but not pre-evolved form
							 | 
						||
| 
								 | 
							
								                        # so this gets full chance roll
							 | 
						||
| 
								 | 
							
								                        bit = roll_tm_compat(tm_move)
							 | 
						||
| 
								 | 
							
								                    # otherwise 50% reduced chance to add compatibility over pre-evolved form
							 | 
						||
| 
								 | 
							
								                    elif self.multiworld.random.randint(1, 100) > 50 and roll_tm_compat(tm_move):
							 | 
						||
| 
								 | 
							
								                        bit = 1
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        bit = 0
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                bit = roll_tm_compat(tm_move)
							 | 
						||
| 
								 | 
							
								            if bit:
							 | 
						||
| 
								 | 
							
								                mon_data["tms"][int(flag / 8)] |= 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                mon_data["tms"][int(flag / 8)] &= ~(1 << (flag % 8))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hm_verify = ["Surf", "Strength"]
							 | 
						||
| 
								 | 
							
								    if self.multiworld.accessibility[self.player] == "locations" or ((not
							 | 
						||
| 
								 | 
							
								            self.multiworld.badgesanity[self.player]) and max(self.multiworld.elite_four_badges_condition[self.player],
							 | 
						||
| 
								 | 
							
								            self.multiworld.route_22_gate_condition[self.player], self.multiworld.victory_road_condition[self.player])
							 | 
						||
| 
								 | 
							
								            > 7) or (self.multiworld.door_shuffle[self.player] not in ("off", "simple")):
							 | 
						||
| 
								 | 
							
								        hm_verify += ["Cut"]
							 | 
						||
| 
								 | 
							
								    if self.multiworld.accessibility[self.player] == "locations" or (not
							 | 
						||
| 
								 | 
							
								            self.multiworld.dark_rock_tunnel_logic[self.player]) and ((self.multiworld.trainersanity[self.player] or
							 | 
						||
| 
								 | 
							
								                                                                       self.multiworld.extra_key_items[self.player])
							 | 
						||
| 
								 | 
							
								                                                                      or self.multiworld.door_shuffle[self.player]):
							 | 
						||
| 
								 | 
							
								        hm_verify += ["Flash"]
							 | 
						||
| 
								 | 
							
								    # Fly does not need to be verified. Full/Insanity door shuffle connects reachable regions to unreachable regions,
							 | 
						||
| 
								 | 
							
								    # so if Fly is available and can be learned, the towns you can fly to would be reachable, but if no Pokémon can
							 | 
						||
| 
								 | 
							
								    # learn it this simply would not occur
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for hm_move in hm_verify:
							 | 
						||
| 
								 | 
							
								        if hm_move not in compat_hms:
							 | 
						||
| 
								 | 
							
								            mon = self.multiworld.random.choice([mon for mon in poke_data.pokemon_data if mon not in
							 | 
						||
| 
								 | 
							
								                                                 poke_data.legendary_pokemon])
							 | 
						||
| 
								 | 
							
								            flag = tms_hms.index(hm_move)
							 | 
						||
| 
								 | 
							
								            local_poke_data[mon]["tms"][int(flag / 8)] |= 1 << (flag % 8)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self.local_poke_data = local_poke_data
							 | 
						||
| 
								 | 
							
								    self.learnsets = learnsets
							 |