173 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			173 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from ..logic import Location, PEGASUS_BOOTS, SHOVEL | ||
|  | from .base import LocationBase | ||
|  | from ..tileset import solid_tiles, open_tiles, walkable_tiles | ||
|  | from ...roomEditor import RoomEditor | ||
|  | from ...assembler import ASM | ||
|  | from ...locations.all import Seashell | ||
|  | import random | ||
|  | 
 | ||
|  | 
 | ||
|  | class HiddenSeashell(LocationBase): | ||
|  |     def __init__(self, room, x, y): | ||
|  |         super().__init__(room, x, y) | ||
|  |         if room.tiles[x + y * 10] not in (0x20, 0x5C): | ||
|  |             if random.randint(0, 1): | ||
|  |                 room.tiles[x + y * 10] = 0x20  # rock | ||
|  |             else: | ||
|  |                 room.tiles[x + y * 10] = 0x5C  # bush | ||
|  | 
 | ||
|  |     def update_room(self, rom, re: RoomEditor): | ||
|  |         re.entities.append((self.x, self.y, 0x3D)) | ||
|  | 
 | ||
|  |     def connect_logic(self, logic_location): | ||
|  |         logic_location.add(Seashell(self.room.x + self.room.y * 16)) | ||
|  | 
 | ||
|  |     def get_item_pool(self): | ||
|  |         return {None: 1} | ||
|  | 
 | ||
|  |     @staticmethod | ||
|  |     def check_possible(room, reachable_map): | ||
|  |         # Check if we can potentially place a hidden seashell here | ||
|  |         # First see if we have a nice bush or rock to hide under | ||
|  |         options = [] | ||
|  |         for y in range(1, 7): | ||
|  |             for x in range(1, 9): | ||
|  |                 if room.tiles[x + y * 10] not in {0x20, 0x5C}: | ||
|  |                     continue | ||
|  |                 idx = room.x * 10 + x + (room.y * 8 + y) * reachable_map.w | ||
|  |                 if reachable_map.area[idx] == -1: | ||
|  |                     continue | ||
|  |                 options.append((reachable_map.distance[idx], x, y)) | ||
|  |         if not options: | ||
|  |             # No existing bush, we can always add one. So find a nice spot | ||
|  |             for y in range(1, 7): | ||
|  |                 for x in range(1, 9): | ||
|  |                     if room.tiles[x + y * 10] not in walkable_tiles: | ||
|  |                         continue | ||
|  |                     if room.tiles[x + y * 10] == 0x1E:  # ocean edge | ||
|  |                         continue | ||
|  |                     idx = room.x * 10 + x + (room.y * 8 + y) * reachable_map.w | ||
|  |                     if reachable_map.area[idx] == -1: | ||
|  |                         continue | ||
|  |                     options.append((reachable_map.distance[idx], x, y)) | ||
|  |         if not options: | ||
|  |             return None | ||
|  |         options.sort(reverse=True) | ||
|  |         options = [(x, y) for d, x, y in options if d > options[0][0] - 4] | ||
|  |         return random.choice(options) | ||
|  | 
 | ||
|  | 
 | ||
|  | class DigSeashell(LocationBase): | ||
|  |     MAX_COUNT = 6 | ||
|  | 
 | ||
|  |     def __init__(self, room, x, y): | ||
|  |         super().__init__(room, x, y) | ||
|  |         if room.tileset_id == "beach": | ||
|  |             room.tiles[x + y * 10] = 0x08 | ||
|  |             for ox, oy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: | ||
|  |                 if room.tiles[x + ox + (y + oy) * 10] != 0x1E: | ||
|  |                     room.tiles[x + ox + (y + oy) * 10] = 0x24 | ||
|  |         else: | ||
|  |             room.tiles[x + y * 10] = 0x04 | ||
|  |             for ox, oy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: | ||
|  |                 room.tiles[x + ox + (y + oy) * 10] = 0x0A | ||
|  | 
 | ||
|  |     def update_room(self, rom, re: RoomEditor): | ||
|  |         re.entities.append((self.x, self.y, 0x3D)) | ||
|  |         if rom.banks[0x03][0x2210] == 0xFF: | ||
|  |             rom.patch(0x03, 0x220F, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  |         elif rom.banks[0x03][0x2214] == 0xFF: | ||
|  |             rom.patch(0x03, 0x2213, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  |         elif rom.banks[0x03][0x2218] == 0xFF: | ||
|  |             rom.patch(0x03, 0x2217, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  |         elif rom.banks[0x03][0x221C] == 0xFF: | ||
|  |             rom.patch(0x03, 0x221B, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  |         elif rom.banks[0x03][0x2220] == 0xFF: | ||
|  |             rom.patch(0x03, 0x221F, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  |         elif rom.banks[0x03][0x2224] == 0xFF: | ||
|  |             rom.patch(0x03, 0x2223, ASM("cp $FF"), ASM(f"cp ${self.room.x | (self.room.y << 4):02x}")) | ||
|  | 
 | ||
|  |     def connect_logic(self, logic_location): | ||
|  |         logic_location.connect(Location().add(Seashell(self.room.x + self.room.y * 16)), SHOVEL) | ||
|  | 
 | ||
|  |     def get_item_pool(self): | ||
|  |         return {None: 1} | ||
|  | 
 | ||
|  |     @staticmethod | ||
|  |     def check_possible(room, reachable_map): | ||
|  |         options = [] | ||
|  |         for y in range(1, 7): | ||
|  |             for x in range(1, 9): | ||
|  |                 if room.tiles[x + y * 10] not in walkable_tiles: | ||
|  |                     continue | ||
|  |                 if room.tiles[x - 1 + y * 10] not in walkable_tiles: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + 1 + y * 10] not in walkable_tiles: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + (y - 1) * 10] not in walkable_tiles: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + (y + 1) * 10] not in walkable_tiles: | ||
|  |                     continue | ||
|  |                 idx = room.x * 10 + x + (room.y * 8 + y) * reachable_map.w | ||
|  |                 if reachable_map.area[idx] == -1: | ||
|  |                     continue | ||
|  |                 options.append((x, y)) | ||
|  |         if not options: | ||
|  |             return None | ||
|  |         return random.choice(options) | ||
|  | 
 | ||
|  | 
 | ||
|  | class BonkSeashell(LocationBase): | ||
|  |     MAX_COUNT = 2 | ||
|  | 
 | ||
|  |     def __init__(self, room, x, y): | ||
|  |         super().__init__(room, x, y) | ||
|  |         self.tree_x = x | ||
|  |         self.tree_y = y | ||
|  |         for offsetx, offsety in [(-1, 0), (-1, 1), (2, 0), (2, 1), (0, -1), (1, -1), (0, 2), (1, 2)]: | ||
|  |             if room.tiles[x + offsetx + (y + offsety) * 10] in walkable_tiles: | ||
|  |                 self.x += offsetx | ||
|  |                 self.y += offsety | ||
|  |                 break | ||
|  | 
 | ||
|  |     def update_room(self, rom, re: RoomEditor): | ||
|  |         re.entities.append((self.tree_x, self.tree_y, 0x3D)) | ||
|  |         if rom.banks[0x03][0x0F04] == 0xFF: | ||
|  |             rom.patch(0x03, 0x0F03, ASM("cp $FF"), ASM(f"cp ${self.room.x|(self.room.y<<4):02x}")) | ||
|  |         elif rom.banks[0x03][0x0F08] == 0xFF: | ||
|  |             rom.patch(0x03, 0x0F07, ASM("cp $FF"), ASM(f"cp ${self.room.x|(self.room.y<<4):02x}")) | ||
|  |         else: | ||
|  |             raise RuntimeError("To many bonk seashells") | ||
|  | 
 | ||
|  |     def connect_logic(self, logic_location): | ||
|  |         logic_location.connect(Location().add(Seashell(self.room.x + self.room.y * 16)), PEGASUS_BOOTS) | ||
|  | 
 | ||
|  |     def get_item_pool(self): | ||
|  |         return {None: 1} | ||
|  | 
 | ||
|  |     @staticmethod | ||
|  |     def check_possible(room, reachable_map): | ||
|  |         # Check if we can potentially place a hidden seashell here | ||
|  |         # Find potential trees | ||
|  |         options = [] | ||
|  |         for y in range(1, 6): | ||
|  |             for x in range(1, 8): | ||
|  |                 if room.tiles[x + y * 10] != 0x25: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + y * 10 + 1] != 0x26: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + y * 10 + 10] != 0x27: | ||
|  |                     continue | ||
|  |                 if room.tiles[x + y * 10 + 11] != 0x28: | ||
|  |                     continue | ||
|  |                 idx = room.x * 10 + x + (room.y * 8 + y) * reachable_map.w | ||
|  |                 top_reachable = reachable_map.area[idx - reachable_map.w] != -1 or reachable_map.area[idx - reachable_map.w + 1] != -1 | ||
|  |                 bottom_reachable = reachable_map.area[idx + reachable_map.w * 2] != -1 or reachable_map.area[idx + reachable_map.w * 2 + 1] != -1 | ||
|  |                 left_reachable = reachable_map.area[idx - 1] != -1 or reachable_map.area[idx + reachable_map.w - 1] != -1 | ||
|  |                 right_reachable = reachable_map.area[idx + 2] != -1 or reachable_map.area[idx + reachable_map.w + 2] != -1 | ||
|  |                 if (top_reachable and bottom_reachable) or (left_reachable and right_reachable): | ||
|  |                     options.append((x, y)) | ||
|  |         if not options: | ||
|  |             return None | ||
|  |         return random.choice(options) |