2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import logging
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from typing import Optional
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from BaseClasses import Boss
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from Fill import FillError
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def BossFactory(boss: str, player: int) -> Optional[Boss]:
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if boss in boss_table:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        enemizer_name, defeat_rule = boss_table[boss]
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return Boss(boss, enemizer_name, defeat_rule, player)
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    raise Exception('Unknown Boss: %s', boss)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def ArmosKnightsDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Magic amounts are probably a bit overkill
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            state.has_melee_weapon(player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.can_shoot_arrows(player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Cane of Somaria', player) and state.can_extend_magic(player, 10)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Cane of Byrna', player) and state.can_extend_magic(player, 16)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Ice Rod', player) and state.can_extend_magic(player, 32)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Fire Rod', player) and state.can_extend_magic(player, 32)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Blue Boomerang', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Red Boomerang', player))
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def LanmolasDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            state.has_melee_weapon(player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Fire Rod', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Ice Rod', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Cane of Somaria', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.has('Cane of Byrna', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.can_shoot_arrows(player))
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def MoldormDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return state.has_melee_weapon(player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def HelmasaurKingDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-15 14:14:06 +11:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # TODO: technically possible with the hammer
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return state.has_sword(player) or state.can_shoot_arrows(player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def ArrghusDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not state.has('Hookshot', player):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # TODO: ideally we would have a check for bow and silvers, which combined with the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # hookshot is enough. This is not coded yet because the silvers that only work in pyramid feature
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # makes this complicated
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if state.has_melee_weapon(player):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return True
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return ((state.has('Fire Rod', player) and (state.can_shoot_arrows(player) or state.can_extend_magic(player,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                                                                                         12))) or  # assuming mostly gitting two puff with one shot
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            (state.has('Ice Rod', player) and (state.can_shoot_arrows(player) or state.can_extend_magic(player, 16))))
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def MothulaDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            state.has_melee_weapon(player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Fire Rod', player) and state.can_extend_magic(player, 10)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # TODO: Not sure how much (if any) extend magic is needed for these two, since they only apply
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # to non-vanilla locations, so are harder to test, so sticking with what VT has for now:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Cane of Somaria', player) and state.can_extend_magic(player, 16)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (state.has('Cane of Byrna', player) and state.can_extend_magic(player, 16)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            state.can_get_good_bee(player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def BlindDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return state.has_melee_weapon(player) or state.has('Cane of Somaria', player) or state.has('Cane of Byrna', player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def KholdstareDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            (
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    state.has('Fire Rod', player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            state.has('Bombos', player) and
							 | 
						
					
						
							
								
									
										
										
										
											2021-04-09 20:40:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            (state.has_sword(player) or state.world.swordless[player])
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ) and
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    state.has_melee_weapon(player) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    (state.has('Fire Rod', player) and state.can_extend_magic(player, 20)) or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            state.has('Fire Rod', player) and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            state.has('Bombos', player) and
							 | 
						
					
						
							
								
									
										
										
										
											2021-04-09 20:40:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            state.world.swordless[player] and
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            state.can_extend_magic(player, 16)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    )
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def VitreousDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-20 19:17:10 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return state.can_shoot_arrows(player) or state.has_melee_weapon(player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def TrinexxDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not (state.has('Fire Rod', player) and state.has('Ice Rod', player)):
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-15 14:14:06 +11:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return state.has('Hammer', player) or state.has('Tempered Sword', player) or state.has('Golden Sword', player) or \
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								           (state.has('Master Sword', player) and state.can_extend_magic(player, 16)) or \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								           (state.has_sword(player) and state.can_extend_magic(player, 32))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def AgahnimDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2019-04-18 11:23:24 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return state.has_sword(player) or state.has('Hammer', player) or state.has('Bug Catching Net', player)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def GanonDefeatRule(state, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2021-04-09 20:40:45 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if state.world.swordless[player]:
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return state.has('Hammer', player) and \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               state.has_fire_source(player) and \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               state.has('Silver Bow', player) and \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               state.can_shoot_arrows(player)
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-04 22:44:55 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    can_hurt = state.has_beam_sword(player)
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    common = can_hurt and state.has_fire_source(player)
							 | 
						
					
						
							
								
									
										
										
										
											2021-06-14 22:10:26 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # silverless ganon may be needed in anything higher than no glitches
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if state.world.logic[player] != 'noglitches':
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # need to light torch a sufficient amount of times
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return common and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                state.has('Silver Bow', player) and state.can_shoot_arrows(player)) or
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                           state.has('Lamp', player) or state.can_extend_magic(player, 12))
							 | 
						
					
						
							
								
									
										
										
										
											2020-10-07 19:51:46 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return common and state.has('Silver Bow', player) and state.can_shoot_arrows(player)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								boss_table = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Armos Knights': ('Armos', ArmosKnightsDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Lanmolas': ('Lanmola', LanmolasDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Moldorm': ('Moldorm', MoldormDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Helmasaur King': ('Helmasaur', HelmasaurKingDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Arrghus': ('Arrghus', ArrghusDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Mothula': ('Mothula', MothulaDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Blind': ('Blind', BlindDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Kholdstare': ('Kholdstare', KholdstareDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Vitreous': ('Vitreous', VitreousDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Trinexx': ('Trinexx', TrinexxDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Agahnim': ('Agahnim', AgahnimDefeatRule),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    'Agahnim2': ('Agahnim2', AgahnimDefeatRule)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-07 04:36:46 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								boss_location_table = [
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        ('Ganons Tower', 'top'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Tower of Hera', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Skull Woods', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Ganons Tower', 'middle'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Eastern Palace', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Desert Palace', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Palace of Darkness', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Swamp Palace', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Thieves Town', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Ice Palace', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Misery Mire', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Turtle Rock', None),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ('Ganons Tower', 'bottom'),
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-07 04:36:46 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    ]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 00:07:55 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def can_place_boss(boss: str, dungeon_name: str, level: Optional[str] = None) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # blacklist approach
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if boss in {"Agahnim", "Agahnim2", "Ganon"}:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if dungeon_name == 'Ganons Tower':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if level == 'top':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if boss in {"Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"}:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif level == 'middle':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if boss == "Blind":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                return False
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif dungeon_name == 'Tower of Hera':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if boss in {"Armos Knights", "Arrghus", "Blind", "Trinexx", "Lanmolas"}:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            return False
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif dungeon_name == 'Skull Woods':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if boss == "Trinexx":
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return False
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return True
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								restrictive_boss_locations = {}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								for location in boss_location_table:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    restrictive_boss_locations[location] = not all(can_place_boss(boss, *location)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                               for boss in boss_table if not boss.startswith("Agahnim"))
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def place_boss(world, player: int, boss: str, location: str, level: Optional[str]):
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if location == 'Ganons Tower' and world.mode[player] == 'inverted':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        location = 'Inverted Ganons Tower'
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:25:14 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    logging.debug('Placing boss %s at %s', boss, location + (' (' + level + ')' if level else ''))
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    world.get_dungeon(location, player).bosses[level] = BossFactory(boss, player)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def format_boss_location(location, level):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return location + (' (' + level + ')' if level else '')
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def place_bosses(world, player: int):
							 | 
						
					
						
							
								
									
										
										
										
											2019-12-17 15:55:53 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if world.boss_shuffle[player] == 'none':
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Most to least restrictive order
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-07 04:36:46 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    boss_locations = boss_location_table.copy()
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    world.random.shuffle(boss_locations)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boss_locations.sort(key= lambda location: -int(restrictive_boss_locations[location]))
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-18 15:22:13 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    all_bosses = sorted(boss_table.keys())  # sorted to be deterministic on older pythons
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    placeable_bosses = [boss for boss in all_bosses if boss not in ['Agahnim', 'Agahnim2', 'Ganon']]
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    shuffle_mode = world.boss_shuffle[player]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    already_placed_bosses = []
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if ";" in shuffle_mode:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        bosses = shuffle_mode.split(";")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        shuffle_mode = bosses.pop()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for boss in bosses:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if "-" in boss:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                loc, boss = boss.split("-")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                boss = boss.title()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                level = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if loc.split(" ")[-1] in {"top", "middle", "bottom"}:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    # split off level
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    loc = loc.split(" ")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    level = loc[-1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    loc = " ".join(loc[:-1])
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-07 04:02:17 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                loc = loc.title().replace("Of", "of")
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-28 14:07:34 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if can_place_boss(boss, loc, level) and (loc, level) in boss_locations:
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    place_boss(world, player, boss, loc, level)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    already_placed_bosses.append(boss)
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-28 14:07:34 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    boss_locations.remove((loc, level))
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                else:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    raise Exception(f"Cannot place {boss} at {format_boss_location(loc, level)} for player {player}.")
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                boss = boss.title()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                boss_locations, already_placed_bosses = place_where_possible(world, player, boss, boss_locations)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if shuffle_mode == "none":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return  # vanilla bosses come pre-placed
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-04-03 14:47:49 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if shuffle_mode in ["basic", "full"]:
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if world.boss_shuffle[player] == "basic":  # vanilla bosses shuffled
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm']
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else:  # all bosses present, the three duplicates chosen at random
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            bosses = placeable_bosses + world.random.sample(placeable_bosses, 3)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # there is probably a better way to do this
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        while already_placed_bosses:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # remove already manually placed bosses, to prevent for example triple Lanmolas
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            boss = already_placed_bosses.pop()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if boss in bosses:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                bosses.remove(boss)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # there may be more bosses than locations at this point, depending on manual placement
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 00:07:55 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        logging.debug('Bosses chosen %s', bosses)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-14 07:01:51 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        world.random.shuffle(bosses)
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        for loc, level in boss_locations:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            for _ in range(len(bosses)):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                boss = bosses.pop()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if can_place_boss(boss, loc, level):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    break
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                # put the boss back in queue
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                bosses.insert(0, boss)  # this would be faster with deque,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                # but the deque size is small enough that it should not matter
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                raise FillError(f'Could not place boss for location {format_boss_location(loc, level)}')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            place_boss(world, player, boss, loc, level)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif shuffle_mode == "chaos":  # all bosses chosen at random
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        for loc, level in boss_locations:
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            try:
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-14 07:01:51 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                boss = world.random.choice(
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    [b for b in placeable_bosses if can_place_boss(b, loc, level)])
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            except IndexError:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-26 04:05:36 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                raise FillError(f'Could not place boss for location {format_boss_location(loc, level)}')
							 | 
						
					
						
							
								
									
										
										
										
											2020-07-31 21:56:31 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                place_boss(world, player, boss, loc, level)
							 | 
						
					
						
							
								
									
										
										
										
											2018-09-26 13:12:20 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif shuffle_mode == "singularity":
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-19 21:10:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        primary_boss = world.random.choice(placeable_bosses)
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        remaining_boss_locations, _ = place_where_possible(world, player, primary_boss, boss_locations)
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-19 21:10:02 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if remaining_boss_locations:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # pick a boss to go into the remaining locations
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            remaining_boss = world.random.choice([boss for boss in placeable_bosses if all(
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-22 11:39:20 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                can_place_boss(boss, loc, level) for loc, level in remaining_boss_locations)])
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            remaining_boss_locations, _ = place_where_possible(world, player, remaining_boss, remaining_boss_locations)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if remaining_boss_locations:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                raise Exception("Unfilled boss locations!")
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-25 23:53:15 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-31 13:23:32 +01:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        raise FillError(f"Could not find boss shuffle mode {shuffle_mode}")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def place_where_possible(world, player: int, boss: str, boss_locations):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    remainder = []
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    placed_bosses = []
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for loc, level in boss_locations:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # place that boss where it can go
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if can_place_boss(boss, loc, level):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            place_boss(world, player, boss, loc, level)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            placed_bosses.append(boss)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            remainder.append((loc, level))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return remainder, placed_bosses
							 |