Merged in DR v1.4.1.6
This commit is contained in:
222
source/enemizer/Bossmizer.py
Normal file
222
source/enemizer/Bossmizer.py
Normal file
@@ -0,0 +1,222 @@
|
||||
import RaceRandom as random
|
||||
from Utils import snes_to_pc
|
||||
|
||||
from source.dungeon.EnemyList import EnemySprite, SpriteType, Sprite
|
||||
from source.dungeon.RoomList import boss_rooms, gt_boss_room, Room0006
|
||||
from source.dungeon.RoomObject import RoomObject
|
||||
from source.enemizer.SpriteSheets import required_boss_sheets
|
||||
|
||||
|
||||
def get_dungeon_boss_room(dungeon_name, level):
|
||||
if level is None:
|
||||
return boss_rooms[dungeon_name]
|
||||
return gt_boss_room[level]
|
||||
|
||||
|
||||
def get_dungeon_boss_default(dungeon_name, level):
|
||||
if level is None:
|
||||
return boss_defaults[dungeon_name]
|
||||
return gt_boss_defaults[level]
|
||||
|
||||
|
||||
def add_shell_to_boss_room(data_tables, dungeon_name, level, shell_id):
|
||||
room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level)
|
||||
if room_id in data_tables.room_list:
|
||||
room = data_tables.room_list[room_id]
|
||||
else:
|
||||
data_tables.room_list[room_id] = room
|
||||
room.layout[0] = 0xF0
|
||||
if clear_layer_2:
|
||||
room.layer2.clear()
|
||||
y_offset = 0 if shell_id == 0xF95 else -2
|
||||
room.layer2.append(RoomObject.subtype3_factory(shell_x, shell_y + y_offset, shell_id))
|
||||
|
||||
|
||||
def remove_shell_from_boss_room(data_tables, dungeon_name, level, shell_id):
|
||||
room_id, room, shell_x, shell_y, clear_layer_2 = get_dungeon_boss_room(dungeon_name, level)
|
||||
if room_id in data_tables.room_list:
|
||||
room = data_tables.room_list[room_id]
|
||||
else:
|
||||
data_tables.room_list[room_id] = room
|
||||
room.layer2[:] = [obj for obj in room.layer2 if not obj.matches_oid(shell_id)]
|
||||
|
||||
|
||||
def remove_water_tiles(data_tables):
|
||||
room = Room0006
|
||||
if 0x6 in data_tables.room_list:
|
||||
room = data_tables.room_list[0x6]
|
||||
else:
|
||||
data_tables.room_list[0x6] = room
|
||||
room.layer1.clear()
|
||||
|
||||
|
||||
def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y):
|
||||
return Sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, None, False, None)
|
||||
|
||||
|
||||
def add_armos_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x05))
|
||||
sprite_list.insert(1, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x05))
|
||||
sprite_list.insert(2, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x05))
|
||||
sprite_list.insert(3, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x0a, 0x08))
|
||||
sprite_list.insert(4, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x07, 0x08))
|
||||
sprite_list.insert(5, create_sprite(room_id, EnemySprite.ArmosKnight, 0x00, 0, 0x04, 0x08))
|
||||
sprite_list.insert(6, create_sprite(room_id, 0x19, SpriteType.Overlord, 0, 0x07, 0x08))
|
||||
|
||||
|
||||
def add_lanmolas_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x06, 0x07))
|
||||
sprite_list.insert(1, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x09, 0x07))
|
||||
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Lanmolas, 0x00, 0, 0x07, 0x09))
|
||||
|
||||
|
||||
def add_moldorm_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Moldorm, 0x00, 0, 0x09, 0x09))
|
||||
|
||||
|
||||
def add_helmasaur_king_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.HelmasaurKing, 0x00, 0, 0x07, 0x06))
|
||||
|
||||
|
||||
def add_arrghus_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Arrghus, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(1, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(3, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(4, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(5, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(6, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(7, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(8, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(9, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(10, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(11, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(12, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
sprite_list.insert(13, create_sprite(room_id, EnemySprite.Arrghi, 0x00, 0, 0x07, 0x07))
|
||||
|
||||
|
||||
def add_mothula_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Mothula, 0x00, 0, 0x08, 0x06))
|
||||
|
||||
|
||||
def add_blind_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.Blind, 0x00, 0, 0x09, 0x05))
|
||||
|
||||
|
||||
def add_kholdstare_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.KholdstareShell, 0x00, 0, 0x07, 0x05))
|
||||
sprite_list.insert(1, create_sprite(room_id, EnemySprite.FallingIce, 0x00, 0, 0x07, 0x05))
|
||||
sprite_list.insert(2, create_sprite(room_id, EnemySprite.Kholdstare, 0x00, 0, 0x07, 0x05))
|
||||
|
||||
|
||||
def add_vitreous_to_list(sprite_list, room_id):
|
||||
sprite_list.clear() # vitreous does not play nice which other sprites on the tile, just kill them
|
||||
sprite_list.append(create_sprite(room_id, EnemySprite.Vitreous, 0x00, 0, 0x07, 0x05))
|
||||
|
||||
|
||||
def add_trinexx_to_list(sprite_list, room_id):
|
||||
sprite_list.insert(0, create_sprite(room_id, EnemySprite.TrinexxRockHead, 0x00, 0, 0x07, 0x05))
|
||||
sprite_list.insert(1, create_sprite(room_id, EnemySprite.TrinexxFireHead, 0x00, 0, 0x07, 0x05))
|
||||
sprite_list.insert(2, create_sprite(room_id, EnemySprite.TrinexxIceHead, 0x00, 0, 0x07, 0x05))
|
||||
|
||||
|
||||
def boss_adjust(world, player):
|
||||
data_tables = world.data_tables[player]
|
||||
for dungeon in world.get_dungeons(player):
|
||||
for level, boss in dungeon.bosses.items():
|
||||
if not boss or boss.name in ['Agahnim', 'Agahnim2']:
|
||||
continue
|
||||
default_boss = get_dungeon_boss_default(dungeon.name, level)
|
||||
room_data = get_dungeon_boss_room(dungeon.name, level)
|
||||
room_id = room_data[0]
|
||||
if default_boss != boss.name:
|
||||
sprite_list = data_tables.uw_enemy_table.room_map[room_id]
|
||||
data = boss_room_remove_data[room_id]
|
||||
del sprite_list[:data]
|
||||
add_func, sprite_type = boss_addition_table[boss.name]
|
||||
add_func(sprite_list, room_id)
|
||||
if len(sprite_list) > 15:
|
||||
del sprite_list[15:]
|
||||
data_tables.room_headers[room_id].sprite_sheet = required_boss_sheets[sprite_type]
|
||||
|
||||
|
||||
def boss_writes(world, player, rom):
|
||||
rom.write_byte(snes_to_pc(0x368107), 1) # centralize drops
|
||||
eye_number = random.randint(0, 8) # randomize moldorm eyes (var + 1)
|
||||
rom.write_byte(snes_to_pc(0x368102), eye_number) # enemizer flag
|
||||
rom.write_byte(snes_to_pc(0x1DDBB3), eye_number) # loop variable
|
||||
data_tables = world.data_tables[player]
|
||||
arrghus_can_swim = True
|
||||
water_tiles_on = True
|
||||
for dungeon in world.get_dungeons(player):
|
||||
for level, boss in dungeon.bosses.items():
|
||||
if not boss or boss.name in ['Agahnim', 'Agahnim2']:
|
||||
continue
|
||||
room_data = get_dungeon_boss_room(dungeon.name, level)
|
||||
room_id = room_data[0]
|
||||
# room changes
|
||||
if boss.name == 'Arrghus' and (dungeon.name != 'Swamp Palace' or level is not None):
|
||||
rom.write_byte(snes_to_pc(0x0DB6BE), 0) # arrghus can stand on ground
|
||||
arrghus_can_swim = False
|
||||
if boss.name != 'Arrghus' and dungeon.name == 'Swamp Palace' and level is None:
|
||||
remove_water_tiles(data_tables)
|
||||
water_tiles_on = False
|
||||
if boss.name == 'Trinexx' and (dungeon.name != 'Turtle Rock' or level is not None):
|
||||
add_shell_to_boss_room(data_tables, dungeon.name, level, 0xFF2)
|
||||
data_tables.room_headers[room_id].byte_0 = 0x60
|
||||
data_tables.room_headers[room_id].effect = 4
|
||||
# $2E, $98, $FF (original shell)
|
||||
if boss.name == 'Kholdstare' and (dungeon.name != 'Ice Palace' or level is not None):
|
||||
add_shell_to_boss_room(data_tables, dungeon.name, level, 0xF95)
|
||||
data_tables.room_headers[room_id].byte_0 = 0xE0
|
||||
data_tables.room_headers[room_id].effect = 1
|
||||
if boss.name != 'Trinexx' and dungeon.name == 'Turtle Rock' and level is None:
|
||||
remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xFF2)
|
||||
# disable trinexx ice breath with No-ops
|
||||
rom.write_bytes(snes_to_pc(0x09B37E), [0xEA, 0xEA, 0xEA, 0xEA])
|
||||
if boss.name != 'Kholdstare' and dungeon.name == 'Ice Palace' and level is None:
|
||||
remove_shell_from_boss_room(data_tables, dungeon.name, level, 0xF95)
|
||||
if boss.name != 'Blind' and dungeon.name == 'Thieves Town' and level is None:
|
||||
rom.write_byte(snes_to_pc(0x368101), 1) # set blind boss door flag
|
||||
# maiden is deleted
|
||||
del data_tables.uw_enemy_table.room_map[0x45][0]
|
||||
if not arrghus_can_swim and water_tiles_on:
|
||||
remove_water_tiles(data_tables)
|
||||
|
||||
|
||||
boss_defaults = {
|
||||
'Eastern Palace': 'Armos Knights',
|
||||
'Desert Palace': 'Lanmolas',
|
||||
'Tower of Hera': 'Moldorm',
|
||||
'Palace of Darkness': 'Helmasaur King',
|
||||
'Swamp Palace': 'Arrghus',
|
||||
'Skull Woods': 'Mothula',
|
||||
'Thieves Town': 'Blind',
|
||||
'Ice Palace': 'Kholdstare',
|
||||
'Misery Mire': 'Vitreous',
|
||||
'Turtle Rock': 'Trinexx',
|
||||
}
|
||||
|
||||
gt_boss_defaults = {
|
||||
'bottom': 'Armos Knights',
|
||||
'middle': 'Lanmolas',
|
||||
'top': 'Moldorm',
|
||||
}
|
||||
|
||||
boss_room_remove_data = {
|
||||
6: 14, 7: 1, 0x1c: 7, 0x29: 1, 0x33: 3, 0x4d: 1, 0x5a: 1,
|
||||
0x6c: 3, 0x90: 1, 0xa4: 2, 0xac: 1, 0xc8: 7, 0xde: 3
|
||||
}
|
||||
|
||||
boss_addition_table = {
|
||||
'Armos Knights': (add_armos_to_list, EnemySprite.ArmosKnight),
|
||||
'Lanmolas': (add_lanmolas_to_list, EnemySprite.Lanmolas),
|
||||
'Moldorm': (add_moldorm_to_list, EnemySprite.Moldorm),
|
||||
'Helmasaur King': (add_helmasaur_king_to_list, EnemySprite.HelmasaurKing),
|
||||
'Arrghus': (add_arrghus_to_list, EnemySprite.Arrghus),
|
||||
'Mothula': (add_mothula_to_list, EnemySprite.Mothula),
|
||||
'Blind': (add_blind_to_list, EnemySprite.Blind),
|
||||
'Kholdstare': (add_kholdstare_to_list, EnemySprite.Kholdstare),
|
||||
'Vitreous': (add_vitreous_to_list, EnemySprite.Vitreous),
|
||||
'Trinexx': (add_trinexx_to_list, EnemySprite.TrinexxRockHead)
|
||||
}
|
||||
8
source/enemizer/DamageTables.py
Normal file
8
source/enemizer/DamageTables.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from Utils import load_cached_yaml
|
||||
|
||||
|
||||
class DamageTable:
|
||||
def __init__(self):
|
||||
self.damage_table = load_cached_yaml(['source', 'enemizer', 'damage_table.yaml'])
|
||||
self.enemy_damage = load_cached_yaml(['source', 'enemizer', 'enemy_damage_table.yaml'])
|
||||
|
||||
539
source/enemizer/Enemizer.py
Normal file
539
source/enemizer/Enemizer.py
Normal file
@@ -0,0 +1,539 @@
|
||||
import RaceRandom as random
|
||||
from Utils import snes_to_pc
|
||||
|
||||
from source.dungeon.EnemyList import SpriteType, EnemySprite, sprite_translation
|
||||
from source.dungeon.RoomList import Room010C
|
||||
from source.enemizer.SpriteSheets import sub_group_choices
|
||||
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets, randomize_overworld_sprite_sheets
|
||||
from source.enemizer.TilePattern import tile_patterns
|
||||
|
||||
shutter_sprites = {
|
||||
0xb8: {0, 1, 2, 3, 4, 5}, 0xb: {4, 5, 6, 7, 8, 9}, 0x1b: {3, 4, 5}, 0x4b: {0, 3, 4}, 0x4: {9, 13, 14},
|
||||
0x24: {3, 4, 5, 6}, # not sure about 6 - bunny beam under pot
|
||||
0x28: {0, 1, 2, 3, 4}, 0xe: {0, 1, 2, 3}, 0x2e: {0, 1, 2, 3, 4, 5}, 0x3e: {1, 2}, 0x6e: {0, 1, 2, 3, 4},
|
||||
0x31: {7, 8, 10}, 0x44: {2, 3, 5}, 0x45: {1, 2, 3}, 0x53: {5, 6, 8, 9, 10}, 0x75: {0, 2, 3, 4, 5},
|
||||
0x85: {2, 3, 4, 5}, 0x5d: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, 0x6b: {5, 6, 7, 8, 9, 10, 11, 12, 13},
|
||||
0x6d: {0, 1, 2, 3, 4, 5, 6, 7, 8}, 0x7b: {2, 3, 4, 5, 8, 9, 10}, 0x7d: {4, 5, 6, 7, 8, 10}, 0x8d: {0, 1, 2, 3, 4},
|
||||
0xa5: {0, 1, 2, 3, 4, 5, 6, 7}, 0x71: {0, 1}, 0xd8: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
0xb0: {0, 1, 2, 3, 4, 5, 7, 8, 9, 10}, 0xc0: {0, 1, 2}, 0xe0: {0, 1, 2, 3}, 0xb2: {5, 6, 7, 10, 11},
|
||||
0xd2: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0xef: {0, 1, 2}, 0x10c: {4, 5, 6, 7}, 0x123: {0, 1, 2, 3},
|
||||
0xee: {0, 1, 2, 3, 4} # low health traversal
|
||||
}
|
||||
|
||||
|
||||
def setup_specific_requirements(data_tables):
|
||||
requirements = data_tables.sprite_requirements
|
||||
water_groups = set()
|
||||
water_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
killable_groups = set()
|
||||
killable_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
key_groups = set()
|
||||
key_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
|
||||
for sid, requirement in requirements.items():
|
||||
if isinstance(requirement, dict):
|
||||
continue
|
||||
if requirement.good_for_uw_water():
|
||||
water_groups.update(requirement.groups)
|
||||
for i in range(0, 4):
|
||||
limited = [x for x in requirement.sub_groups[i] if x in sub_group_choices[i]]
|
||||
water_sub_groups[i].update(limited)
|
||||
if requirement.good_for_shutter([]):
|
||||
killable_groups.update(requirement.groups)
|
||||
for i in range(0, 4):
|
||||
killable_sub_groups[i].update(requirement.sub_groups[i])
|
||||
if requirement.can_drop:
|
||||
key_groups.update(requirement.groups)
|
||||
for i in range(0, 4):
|
||||
key_sub_groups[i].update(requirement.sub_groups[i])
|
||||
return water_groups, water_sub_groups, killable_groups, killable_sub_groups, key_groups, key_sub_groups
|
||||
|
||||
|
||||
def get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets):
|
||||
# forced sprites for room
|
||||
requirements = data_tables.sprite_requirements
|
||||
|
||||
water_groups, water_sub_groups, killable_groups, killable_sub_groups, key_groups, key_sub_groups = specific
|
||||
|
||||
# forced_req = set()
|
||||
key_needed = False
|
||||
killable_needed = room_id in shutter_sprites
|
||||
|
||||
for sheet in all_sheets:
|
||||
if room_id in sheet.room_set:
|
||||
return [sheet]
|
||||
|
||||
match_all_room_groups = set()
|
||||
match_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
# match_all_sub_groups = {0: set(uw_sub_group_choices[0] + [70, 72]), 1: set(uw_sub_group_choices[1] + [13, 73]),
|
||||
# 2: set(uw_sub_group_choices[2] + [19]), 3: set(uw_sub_group_choices[3] + [25, 68])}
|
||||
|
||||
for sprite in data_tables.uw_enemy_table.room_map[room_id]:
|
||||
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
|
||||
key = (sprite.kind, sprite_secondary)
|
||||
if key not in requirements:
|
||||
continue
|
||||
req = requirements[key]
|
||||
if isinstance(req, dict):
|
||||
req = req[room_id]
|
||||
if req.static or not req.can_randomize or sprite.static:
|
||||
if req.groups:
|
||||
match_all_room_groups.intersection_update(req.groups)
|
||||
if not match_all_room_groups:
|
||||
match_all_room_groups = set(req.groups)
|
||||
for i in range(0, 4):
|
||||
if req.sub_groups[i]:
|
||||
match_all_sub_groups[i].intersection_update(req.sub_groups[i])
|
||||
if not match_all_sub_groups[i]:
|
||||
match_all_sub_groups[i] = set(req.sub_groups[i])
|
||||
# forced_req.add(req)
|
||||
if sprite.drops_item:
|
||||
key_needed = True
|
||||
|
||||
match_any_room_groups = set()
|
||||
match_any_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
exclude_all_groups = set()
|
||||
exclude_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
|
||||
if room_id in data_tables.room_requirements:
|
||||
required_groups = data_tables.room_requirements[room_id]
|
||||
for idx, grp in enumerate(required_groups):
|
||||
if grp is not None:
|
||||
if isinstance(grp, tuple):
|
||||
match_any_sub_groups[idx].update(grp)
|
||||
else:
|
||||
match_all_sub_groups[idx] = {grp}
|
||||
|
||||
if key_needed:
|
||||
if key_groups:
|
||||
match_any_room_groups.update(key_groups)
|
||||
for i in range(0, 4):
|
||||
if key_sub_groups[i]:
|
||||
match_any_sub_groups[i].update(key_sub_groups[i])
|
||||
elif killable_needed:
|
||||
if killable_groups:
|
||||
match_any_room_groups.update(killable_groups)
|
||||
for i in range(0, 4):
|
||||
if killable_sub_groups[i]:
|
||||
match_any_sub_groups[i].update(killable_sub_groups[i])
|
||||
|
||||
possible_sheets = []
|
||||
for sheet in uw_sheets:
|
||||
if match_all_room_groups and sheet.id not in match_all_room_groups:
|
||||
continue
|
||||
if any(match_all_sub_groups[i] and sheet.sub_groups[i] not in match_all_sub_groups[i] for i in range(0, 4)):
|
||||
continue
|
||||
if exclude_all_groups and sheet.id in exclude_all_groups:
|
||||
continue
|
||||
if any(exclude_all_sub_groups[i] and sheet.sub_groups[i] in exclude_all_sub_groups[i] for i in range(0, 4)):
|
||||
continue
|
||||
if match_any_room_groups and sheet.id not in match_any_sub_groups:
|
||||
continue
|
||||
test_subs = [i for i in range(0, 4) if match_any_sub_groups[i]]
|
||||
if test_subs and all(sheet.sub_groups[i] not in match_any_sub_groups[i] for i in test_subs):
|
||||
continue
|
||||
possible_sheets.append(sheet)
|
||||
return possible_sheets
|
||||
|
||||
|
||||
def get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables):
|
||||
requirements = data_tables.sprite_requirements
|
||||
|
||||
for sheet in all_sheets:
|
||||
if area_id in sheet.room_set:
|
||||
return [sheet]
|
||||
|
||||
match_all_room_groups = set()
|
||||
match_all_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
|
||||
for sprite in data_tables.ow_enemy_table[area_id]:
|
||||
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
|
||||
key = (sprite.kind, sprite_secondary)
|
||||
if key not in requirements:
|
||||
continue
|
||||
req = requirements[key]
|
||||
if isinstance(req, dict):
|
||||
req = req[area_id]
|
||||
if req.static or not req.can_randomize:
|
||||
if req.groups:
|
||||
match_all_room_groups.intersection_update(req.groups)
|
||||
if not match_all_room_groups:
|
||||
match_all_room_groups = set(req.groups)
|
||||
for i in range(0, 4):
|
||||
if req.sub_groups[i]:
|
||||
match_all_sub_groups[i].intersection_update(req.sub_groups[i])
|
||||
if not match_all_sub_groups[i]:
|
||||
match_all_sub_groups[i] = set(req.sub_groups[i])
|
||||
|
||||
possible_sheets = []
|
||||
for sheet in ow_sheets:
|
||||
if match_all_room_groups and sheet.id not in match_all_room_groups:
|
||||
continue
|
||||
if any(match_all_sub_groups[i] and sheet.sub_groups[i] not in match_all_sub_groups[i] for i in range(0, 4)):
|
||||
continue
|
||||
possible_sheets.append(sheet)
|
||||
return possible_sheets
|
||||
|
||||
|
||||
ignore_sheets_uw = {65, 69, 71, 78, 79, 82, 88, 98}
|
||||
ignore_sheets_ow = {6}
|
||||
|
||||
|
||||
def find_candidate_sprites(data_tables, sheet_range, uw=True):
|
||||
requirements = data_tables.sprite_requirements
|
||||
sprite_candidates = []
|
||||
sheet_candidates = []
|
||||
all_sheets = []
|
||||
|
||||
candidate_groups = set()
|
||||
candidate_sub_groups = {0: set(), 1: set(), 2: set(), 3: set()}
|
||||
|
||||
for k, r in requirements.items():
|
||||
if isinstance(r, dict):
|
||||
continue
|
||||
valid_flag = (uw and r.uw_valid) or (not uw and r.ow_valid)
|
||||
if not r.static and valid_flag and not r.dont_use:
|
||||
candidate_groups.update(r.groups)
|
||||
for i in range(0, 4):
|
||||
candidate_sub_groups[i].update(r.sub_groups[i])
|
||||
sprite_candidates.append(k)
|
||||
|
||||
for num in sheet_range:
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
all_sheets.append(sheet)
|
||||
if (uw and num in ignore_sheets_uw) or (not uw and num in ignore_sheets_ow):
|
||||
continue
|
||||
if candidate_groups and sheet not in candidate_groups:
|
||||
continue
|
||||
test_subs = [i for i in range(0, 4) if candidate_sub_groups[i]]
|
||||
if test_subs and all(sheet.sub_groups[i] not in candidate_sub_groups[i] for i in test_subs):
|
||||
continue
|
||||
sheet_candidates.append(sheet)
|
||||
|
||||
return sprite_candidates, sheet_candidates, all_sheets
|
||||
|
||||
|
||||
def get_possible_enemy_sprites(room_id, sheet, uw_sprites, data_tables):
|
||||
ret = []
|
||||
for sprite in uw_sprites:
|
||||
requirement = data_tables.sprite_requirements[sprite]
|
||||
if isinstance(requirement, dict):
|
||||
requirement = requirement[room_id]
|
||||
if sheet.valid_sprite(requirement) and requirement.can_spawn_in_room(room_id):
|
||||
ret.append(requirement)
|
||||
return ret
|
||||
|
||||
|
||||
def get_possible_enemy_sprites_ow(sheet, sprites, data_tables):
|
||||
ret = []
|
||||
for sprite in sprites:
|
||||
requirement = data_tables.sprite_requirements[sprite]
|
||||
if isinstance(requirement, dict):
|
||||
continue
|
||||
if sheet.valid_sprite(requirement) and requirement.ow_valid:
|
||||
ret.append(requirement)
|
||||
return ret
|
||||
|
||||
|
||||
def get_randomize_able_sprites(room_id, data_tables):
|
||||
sprite_table = {}
|
||||
for idx, sprite in enumerate(data_tables.uw_enemy_table.room_map[room_id]):
|
||||
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
|
||||
key = (sprite.kind, sprite_secondary)
|
||||
if key not in data_tables.sprite_requirements:
|
||||
continue
|
||||
req = data_tables.sprite_requirements[key]
|
||||
if isinstance(req, dict):
|
||||
continue
|
||||
if not req.static and req.can_randomize and not sprite.static:
|
||||
sprite_table[idx] = sprite
|
||||
return sprite_table
|
||||
|
||||
|
||||
def get_randomize_able_sprites_ow(area_id, data_tables):
|
||||
sprite_table = {}
|
||||
for idx, sprite in enumerate(data_tables.ow_enemy_table[area_id]):
|
||||
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
|
||||
key = (sprite.kind, sprite_secondary)
|
||||
if key not in data_tables.sprite_requirements:
|
||||
continue
|
||||
req = data_tables.sprite_requirements[key]
|
||||
if isinstance(req, dict):
|
||||
continue
|
||||
if not req.static and req.can_randomize:
|
||||
sprite_table[idx] = sprite
|
||||
return sprite_table
|
||||
|
||||
|
||||
sprite_limiter = {
|
||||
EnemySprite.Debirando: 2,
|
||||
EnemySprite.DebirandoPit: 2,
|
||||
EnemySprite.Hinox: 2,
|
||||
EnemySprite.Sluggula: 2,
|
||||
EnemySprite.BombGuard: 2,
|
||||
EnemySprite.Beamos: 2,
|
||||
EnemySprite.Gibo: 2,
|
||||
# EnemySprite.CannonTrooper: 2, ??
|
||||
EnemySprite.WallCannonHorzTop: 2,
|
||||
EnemySprite.WallCannonHorzBottom: 2,
|
||||
EnemySprite.WallCannonVertLeft: 2,
|
||||
EnemySprite.WallCannonVertRight: 2,
|
||||
EnemySprite.BlueArcher: 2,
|
||||
EnemySprite.BlueGuard: 2,
|
||||
EnemySprite.GreenGuard: 2,
|
||||
EnemySprite.RedSpearGuard: 2,
|
||||
EnemySprite.RedJavelinGuard: 2,
|
||||
EnemySprite.AntiFairyCircle: 4
|
||||
}
|
||||
|
||||
|
||||
def exceeds_sprite_limit(limit, sprite):
|
||||
return sprite_limiter[sprite.sprite]-1+limit > 15 if sprite.sprite in sprite_limiter else False
|
||||
|
||||
|
||||
def randomize_underworld_rooms(data_tables, world, player, custom_uw):
|
||||
any_enemy_logic = world.any_enemy_logic[player]
|
||||
enemy_drops_active = world.dropshuffle[player] in ['underworld']
|
||||
specific = setup_specific_requirements(data_tables)
|
||||
uw_candidates, uw_sheets, all_sheets = find_candidate_sprites(data_tables, range(65, 124))
|
||||
for room_id in range(0, 0x128):
|
||||
if room_id in {0, 1, 3, 6, 7, 0xd, 0x14, 0x20, 0x29, 0x30, 0x33,
|
||||
0x4d, 0x5a, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
|
||||
continue
|
||||
current_sprites = data_tables.uw_enemy_table.room_map[room_id]
|
||||
sprite_limit = sum(sprite_limiter[x.kind] if x.kind in sprite_limiter else 1 for x in current_sprites)
|
||||
if room_id in {0x3f, 0x44, 0x45, 0x93, 0xce, 0x117}:
|
||||
sprite_limit += 1 # for liftable blocks see PotFlags.Block in PotShuffle
|
||||
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
|
||||
if not randomizeable_sprites:
|
||||
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets)
|
||||
chosen_sheet = random.choice(candidate_sheets)
|
||||
data_tables.room_headers[room_id].sprite_sheet = chosen_sheet.id - 0x40
|
||||
if randomizeable_sprites:
|
||||
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, all_sheets, uw_sheets)
|
||||
done = False
|
||||
while not done:
|
||||
chosen_sheet = random.choice(candidate_sheets)
|
||||
data_tables.room_headers[room_id].sprite_sheet = chosen_sheet.id - 0x40
|
||||
candidate_sprites = get_possible_enemy_sprites(room_id, chosen_sheet, uw_candidates, data_tables)
|
||||
randomized = True
|
||||
# wallmaster in hera basement throws off hera basement key code
|
||||
wallmaster_chosen = room_id in {0x0039, 0x0049, 0x0056, 0x0057, 0x0068, 0x0087, 0x008d}
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
if room_id in custom_uw and i in custom_uw[room_id]:
|
||||
sprite.kind = sprite_translation[custom_uw[room_id][i]]
|
||||
else:
|
||||
# filter out water if necessary
|
||||
candidate_sprites = [x for x in candidate_sprites if not x.water_only or sprite.water]
|
||||
# filter out wallmaster if already on tile
|
||||
if wallmaster_chosen:
|
||||
candidate_sprites = [x for x in candidate_sprites if x.sprite != EnemySprite.Wallmaster]
|
||||
candidate_sprites = [x for x in candidate_sprites if not exceeds_sprite_limit(sprite_limit, x)]
|
||||
if sprite.drops_item:
|
||||
forbidden = determine_forbidden(any_enemy_logic == 'none', room_id, True)
|
||||
choice_list = [x for x in candidate_sprites if x.good_for_key_drop(forbidden)]
|
||||
# terrorpin, deadrock, buzzblob, lynel, redmimic/eyegore
|
||||
elif room_id in shutter_sprites and i in shutter_sprites[room_id]:
|
||||
forbidden = determine_forbidden(any_enemy_logic != 'allow_all', room_id)
|
||||
choice_list = [x for x in candidate_sprites if x.good_for_shutter(forbidden)]
|
||||
else:
|
||||
choice_list = [x for x in candidate_sprites if not x.water_only]
|
||||
choice_list = filter_choices(choice_list, room_id, i, data_tables.uw_enemy_denials)
|
||||
if enemy_drops_active:
|
||||
choice_list = filter_choices(choice_list, room_id, i, data_tables.uw_enemy_drop_denials)
|
||||
if len(choice_list) == 0:
|
||||
randomized = False
|
||||
break
|
||||
weight = [data_tables.uw_weights[r.sprite] for r in choice_list]
|
||||
chosen = random.choices(choice_list, weight, k=1)[0]
|
||||
sprite.kind = chosen.sprite
|
||||
if sprite.kind in sprite_limiter:
|
||||
sprite_limit += sprite_limiter[sprite.kind]-1
|
||||
if sprite.kind == EnemySprite.Wallmaster:
|
||||
wallmaster_chosen = True
|
||||
sprite.kind = 0x09
|
||||
sprite.sub_type = SpriteType.Overlord
|
||||
done = randomized
|
||||
# done with sprites
|
||||
# done with rooms
|
||||
|
||||
|
||||
def determine_forbidden(forbid, room_id, drop_flag=False):
|
||||
forbidden_set = set()
|
||||
if forbid:
|
||||
forbidden_set.update({EnemySprite.Terrorpin, EnemySprite.Deadrock, EnemySprite.Buzzblob,
|
||||
EnemySprite.Lynel})
|
||||
if drop_flag:
|
||||
forbidden_set.add(EnemySprite.RedBari) # requires FireRod to Drop
|
||||
# else: Not yet able to protect triggers, would change default GT tile room behavior
|
||||
# forbidden_set.add(EnemySprite.AntiFairy) # can't drop anyway
|
||||
if room_id not in {0x6b, 0x4b, 0x1b, 0xd8}: # mimics/eyegore are allowed in vanilla rooms
|
||||
forbidden_set.add(EnemySprite.RedEyegoreMimic)
|
||||
forbidden_set.add(EnemySprite.RedMimic)
|
||||
return forbidden_set
|
||||
|
||||
|
||||
def filter_choices(options, room_id, sprite_idx, denials):
|
||||
key = room_id, sprite_idx
|
||||
return [x for x in options if key not in denials or x.sprite not in denials[key]]
|
||||
|
||||
|
||||
def filter_water_phobic(options, sprite):
|
||||
return [x for x in options if not x.water_phobic or not sprite.water]
|
||||
|
||||
|
||||
def randomize_overworld_enemies(data_tables, custom_ow):
|
||||
ow_candidates, ow_sheets, all_sheets = find_candidate_sprites(data_tables, range(1, 64), False)
|
||||
areas_to_randomize = [0, 2, 3, 5, 7, 0xA, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x1a, 0x1b, 0x1d, 0x1e, 0x22, 0x25, 0x28, 0x29, 0x2A, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x32, 0x33, 0x34, 0x35, 0x37, 0x3a, 0x3b, 0x3c, 0x3f]
|
||||
area_list = areas_to_randomize + [x + 0x40 for x in areas_to_randomize] # light world + dark world
|
||||
area_list += [0x80, 0x81] + [x + 0x90 for x in areas_to_randomize] # specials + post aga LW
|
||||
for area_id in area_list:
|
||||
randomizeable_sprites = get_randomize_able_sprites_ow(area_id, data_tables)
|
||||
if not randomizeable_sprites:
|
||||
candidate_sheets = get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables)
|
||||
chosen_sheet = random.choice(candidate_sheets)
|
||||
data_tables.overworld_sprite_sheets[area_id] = chosen_sheet
|
||||
candidate_sprites = get_possible_enemy_sprites_ow(chosen_sheet, ow_candidates, data_tables)
|
||||
else:
|
||||
candidate_sheets = get_possible_ow_sheets(area_id, all_sheets, ow_sheets, data_tables)
|
||||
chosen_sheet = random.choice(candidate_sheets)
|
||||
data_tables.overworld_sprite_sheets[area_id] = chosen_sheet
|
||||
candidate_sprites = get_possible_enemy_sprites_ow(chosen_sheet, ow_candidates, data_tables)
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
if area_id in custom_ow and i in custom_ow[area_id]:
|
||||
sprite.kind = sprite_translation[custom_ow[area_id][i]]
|
||||
else:
|
||||
candidate_sprites = filter_choices(candidate_sprites, area_id, i, data_tables.ow_enemy_denials)
|
||||
candidate_sprites = filter_water_phobic(candidate_sprites, sprite)
|
||||
weight = [data_tables.ow_weights[r.sprite] for r in candidate_sprites]
|
||||
chosen = random.choices(candidate_sprites, weight, k=1)[0]
|
||||
sprite.kind = chosen.sprite
|
||||
# randomize the bush sprite per area
|
||||
weight = [data_tables.ow_weights[r.sprite] for r in candidate_sprites]
|
||||
bush_sprite_choice = random.choices(candidate_sprites, weight, k=1)[0]
|
||||
data_tables.bush_sprite_table[area_id] = bush_sprite_choice
|
||||
|
||||
|
||||
# damage and health tables only go to F2
|
||||
skip_sprites = {
|
||||
EnemySprite.ArmosKnight, EnemySprite.Lanmolas, EnemySprite.Moldorm, EnemySprite.Mothula, EnemySprite.Arrghus,
|
||||
EnemySprite.HelmasaurKing, EnemySprite.Vitreous, EnemySprite.TrinexxRockHead, EnemySprite.TrinexxFireHead,
|
||||
EnemySprite.TrinexxIceHead, EnemySprite.Blind, EnemySprite.Kholdstare, EnemySprite.KholdstareShell,
|
||||
EnemySprite.FallingIce, EnemySprite.Arrghi, EnemySprite.Agahnim, EnemySprite.Ganon,
|
||||
EnemySprite.PositionTarget, EnemySprite.Boulders
|
||||
}
|
||||
|
||||
|
||||
def randomize_enemies(world, player):
|
||||
if world.enemy_shuffle[player] != 'none':
|
||||
data_tables = world.data_tables[player]
|
||||
custom_uw, custom_ow = {}, {}
|
||||
enemy_map = world.customizer.get_enemies() if world.customizer else None
|
||||
if enemy_map and player in enemy_map:
|
||||
if 'Underworld' in enemy_map[player]:
|
||||
custom_uw = enemy_map[player]['Underworld']
|
||||
if 'Overworld' in enemy_map[player]:
|
||||
custom_ow = enemy_map[player]['Overworld']
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables, custom_uw)
|
||||
randomize_underworld_rooms(data_tables, world, player, custom_uw)
|
||||
randomize_overworld_sprite_sheets(data_tables.sprite_sheets, data_tables, custom_ow)
|
||||
randomize_overworld_enemies(data_tables, custom_ow)
|
||||
# fix thief stats
|
||||
# subclass_table = world.damage_table[player].damage_table['SubClassTable']
|
||||
# subclass_table[EnemySprite.Thief] = subclass_table[EnemySprite.GreenEyegoreMimic]
|
||||
# data_tables.enemy_stats[EnemySprite.Thief].health = 4
|
||||
# could turn droppable on here if we wanted for killable theives
|
||||
# health shuffle
|
||||
if world.enemy_health[player] != 'default':
|
||||
stats = world.data_tables[player].enemy_stats
|
||||
min_health = {'easy': 1, 'normal': 2, 'hard': 2, 'expert': 4}
|
||||
max_health = {'easy': 4, 'normal': 15, 'hard': 25, 'expert': 50}
|
||||
min_h = min_health[world.enemy_health[player]]
|
||||
max_h = max_health[world.enemy_health[player]]
|
||||
for sprite, stat in stats.items():
|
||||
if sprite == EnemySprite.Octorok4Way:
|
||||
stat.health = stats[EnemySprite.Octorok].health # these guys share data
|
||||
elif sprite == EnemySprite.GreenMimic:
|
||||
stat.health = stats[EnemySprite.GreenEyegoreMimic].health # these share data
|
||||
elif sprite == EnemySprite.RedMimic:
|
||||
stat.health = stats[EnemySprite.RedEyegoreMimic].health # these share data
|
||||
elif sprite not in skip_sprites:
|
||||
if isinstance(stat.health, tuple):
|
||||
stat.health = random.randint(min_h, max_h), random.randint(min_h, max_h)
|
||||
else:
|
||||
stat.health = random.randint(min_h, max_h)
|
||||
if world.enemy_damage[player] != 'default':
|
||||
stats = world.data_tables[player].enemy_stats
|
||||
# randomize damage groupings
|
||||
for sprite, stat in stats.items():
|
||||
if sprite == EnemySprite.Octorok4Way:
|
||||
stat.damage = stats[EnemySprite.Octorok].damage # these guys share data
|
||||
elif sprite == EnemySprite.GreenMimic:
|
||||
stat.damage = stats[EnemySprite.GreenEyegoreMimic].damage # these share data
|
||||
elif sprite == EnemySprite.RedMimic:
|
||||
stat.damage = stats[EnemySprite.RedEyegoreMimic].damage # these share data
|
||||
elif sprite == EnemySprite.Thief: # always group 0 for 0 damage
|
||||
stat.damage = 0
|
||||
elif sprite not in skip_sprites:
|
||||
if isinstance(stat.damage, tuple):
|
||||
stat.damage = random.randint(0, 8), random.randint(0, 8)
|
||||
else:
|
||||
stat.damage = random.randint(0, 8)
|
||||
# randomize bump table
|
||||
original_table = [
|
||||
(0x02, 0x01, 0x01),
|
||||
(0x04, 0x04, 0x04),
|
||||
(0x00, 0x00, 0x00),
|
||||
(0x08, 0x04, 0x02),
|
||||
(0x08, 0x08, 0x08),
|
||||
(0x10, 0x08, 0x04),
|
||||
(0x20, 0x10, 0x08),
|
||||
(0x20, 0x18, 0x10),
|
||||
(0x18, 0x10, 0x08),
|
||||
(0x40, 0x30, 0x18)]
|
||||
for i in range(0, 10):
|
||||
if i == 0: # group 0 will always be 0 for thieves
|
||||
green_mail, blue_mail, red_mail = 0, 0, 0
|
||||
del original_table[2]
|
||||
else:
|
||||
if world.enemy_damage[player] == 'random':
|
||||
green_mail = random.randint(0, 64)
|
||||
if world.enemy_damage[player] == 'random':
|
||||
blue_mail = random.randint(0, 64)
|
||||
red_mail = random.randint(0, 64)
|
||||
else:
|
||||
idx = random.randint(0, len(original_table)-1)
|
||||
green_mail, blue_mail, red_mail = original_table[idx]
|
||||
del original_table[idx]
|
||||
world.data_tables[player].enemy_damage[i] = [green_mail, blue_mail, red_mail]
|
||||
|
||||
|
||||
def write_enemy_shuffle_settings(world, player, rom):
|
||||
if world.dropshuffle[player] in ['underworld']:
|
||||
rom.write_byte(snes_to_pc(0x368109), 0x01)
|
||||
if world.enemy_shuffle[player] != 'none':
|
||||
# enable new mimics
|
||||
rom.write_byte(snes_to_pc(0x368105), 0x01)
|
||||
|
||||
# killable thief
|
||||
# rom.write_byte(snes_to_pc(0x368108), 0xc4)
|
||||
# rom.write_byte(snes_to_pc(0x0DB237), 4) # health value - randomize it if killable, maybe
|
||||
|
||||
# mimic room barriers
|
||||
data_tables = world.data_tables[player]
|
||||
mimic_room = data_tables.room_list[0x10c] = Room010C
|
||||
mimic_room.layer1[40].data[0] = 0x54 # rail adjust
|
||||
mimic_room.layer1[40].data[1] = 0x9C
|
||||
mimic_room.layer1[45].data[1] = 0xB0 # block adjust 1
|
||||
mimic_room.layer1[47].data[1] = 0xD0 # block adjust 2
|
||||
|
||||
# random tile pattern
|
||||
pattern_name, tile_pattern = random.choice(tile_patterns)
|
||||
rom.write_byte(snes_to_pc(0x9BA1D), len(tile_pattern))
|
||||
for idx, pair in enumerate(tile_pattern):
|
||||
rom.write_byte(snes_to_pc(0x09BA2A + idx), (pair[0] + 3) * 16)
|
||||
rom.write_byte(snes_to_pc(0x09BA40 + idx), (pair[1] + 4) * 16)
|
||||
if world.enemy_shuffle[player] == 'random':
|
||||
rom.write_byte(snes_to_pc(0x368100), 1) # randomize bushes
|
||||
185
source/enemizer/EnemizerTestHarness.py
Normal file
185
source/enemizer/EnemizerTestHarness.py
Normal file
@@ -0,0 +1,185 @@
|
||||
from types import SimpleNamespace
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
from source.dungeon.EnemyList import enemy_names, SpriteType
|
||||
from source.enemizer.Enemizer import randomize_underworld_rooms, randomize_overworld_enemies
|
||||
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets, randomize_overworld_sprite_sheets
|
||||
from source.rom.DataTables import init_data_tables
|
||||
from source.enemizer.DamageTables import DamageTable
|
||||
import RaceRandom as random
|
||||
|
||||
|
||||
def calculate_odds():
|
||||
ctr_uw = Counter()
|
||||
ctr_ow = Counter()
|
||||
for trial in range(0, 100):
|
||||
world = SimpleNamespace(pottery={1: 'none'}, damage_table={1: DamageTable()})
|
||||
data_tables = init_data_tables(world, 1)
|
||||
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables)
|
||||
randomize_overworld_sprite_sheets(data_tables.sprite_sheets)
|
||||
|
||||
for num in range(65, 124):
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
ret = []
|
||||
for req in data_tables.sprite_requirements.values():
|
||||
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
|
||||
ret.append(enemy_names[req.sprite])
|
||||
for x in ret:
|
||||
ctr_uw[x] += 1
|
||||
|
||||
for num in range(1, 64):
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
ret = []
|
||||
for req in data_tables.sprite_requirements.values():
|
||||
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
|
||||
ret.append(enemy_names[req.sprite])
|
||||
for x in ret:
|
||||
ctr_ow[x] += 1
|
||||
ttl = sum(ctr_uw.values())
|
||||
print(f'UW: # Total {ttl}')
|
||||
for k, v in ctr_uw.items():
|
||||
weight = round(.01 * ttl * 100 / v)
|
||||
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v}')
|
||||
ttl = sum(ctr_ow.values())
|
||||
print(f'OW: # Total {ttl}')
|
||||
for k, v in ctr_ow.items():
|
||||
weight = round(.01 * ttl * 100 / v)
|
||||
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# calculate_odds()
|
||||
random.seed(42)
|
||||
#
|
||||
frequency = Counter()
|
||||
sheet_ctr = Counter()
|
||||
ctr_uw = Counter()
|
||||
ctr_ow = Counter()
|
||||
sheet_thing = Counter()
|
||||
sheet_sub_groups = defaultdict(set)
|
||||
|
||||
for trial in range(0, 100):
|
||||
world = SimpleNamespace(pottery={1: 'none'}, damage_table={1: DamageTable()}, any_enemy_logic={1: 'allow_all'},
|
||||
dropshuffle={1: 'none'})
|
||||
data_tables = init_data_tables(world, 1)
|
||||
stats = data_tables.enemy_stats
|
||||
|
||||
def randomize_able_sprite(sprite, stats):
|
||||
if sprite.static:
|
||||
return False
|
||||
if sprite.sub_type == 0x7 and sprite.kind != 0x9:
|
||||
return False
|
||||
if sprite.sub_type == 0x7 and sprite.kind == 0x9:
|
||||
return True
|
||||
return sprite.kind not in stats or not stats[sprite.kind].static
|
||||
|
||||
if trial == 0:
|
||||
print(f' Underworld:')
|
||||
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
|
||||
print(f' {hex(room_id)}:')
|
||||
for i, sprite in enumerate(enemy_list):
|
||||
if randomize_able_sprite(sprite, stats):
|
||||
print(f' {i}: {str(sprite)}')
|
||||
print(f' Overworld:')
|
||||
for area, enemy_list in data_tables.ow_enemy_table.items():
|
||||
print(f' {hex(area)}:')
|
||||
for i, sprite in enumerate(enemy_list):
|
||||
if randomize_able_sprite(sprite, stats):
|
||||
print(f' {i}: {str(sprite)}')
|
||||
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets, data_tables, {})
|
||||
randomize_underworld_rooms(data_tables, world, 1)
|
||||
randomize_overworld_sprite_sheets(data_tables.sprite_sheets, data_tables, {})
|
||||
randomize_overworld_enemies(data_tables)
|
||||
|
||||
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
|
||||
# print(f'Room {hex(room_id)}:')
|
||||
for i, sprite in enumerate(enemy_list):
|
||||
if randomize_able_sprite(sprite, stats):
|
||||
result = str(sprite)
|
||||
frequency[result] += 1
|
||||
for area, enemy_list in data_tables.ow_enemy_table.items():
|
||||
for i, sprite in enumerate(enemy_list):
|
||||
if randomize_able_sprite(sprite, stats):
|
||||
result = str(sprite)
|
||||
frequency[result] += 1
|
||||
|
||||
for num in range(65, 124):
|
||||
if num in {65, 69, 71, 78, 79, 82, 88, 98}:
|
||||
continue
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
ret = []
|
||||
for req in data_tables.sprite_requirements.values():
|
||||
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
|
||||
ret.append(enemy_names[req.sprite])
|
||||
for x in ret:
|
||||
ctr_uw[x] += 1
|
||||
sheet_ctr[x] += 1
|
||||
key = tuple(sorted(ret))
|
||||
sheet_thing[key] += 1
|
||||
sheet_sub_groups[key].add(tuple(sheet.sub_groups))
|
||||
|
||||
for num in range(1, 64):
|
||||
if num == 6:
|
||||
continue
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
ret = []
|
||||
for req in data_tables.sprite_requirements.values():
|
||||
if not isinstance(req, dict) and sheet.valid_sprite(req) and not req.overlord and not req.static:
|
||||
ret.append(enemy_names[req.sprite])
|
||||
for x in ret:
|
||||
ctr_ow[x] += 1
|
||||
sheet_ctr[x] += 1
|
||||
key = tuple(sorted(ret))
|
||||
sheet_thing[key] += 1
|
||||
sheet_sub_groups[key].add(tuple(sheet.sub_groups))
|
||||
|
||||
total_sheets = sum(sheet_thing.values())
|
||||
ttl = sum(ctr_uw.values())
|
||||
print(f'UW: # Total {ttl}')
|
||||
for k in sorted(list(ctr_uw.keys())):
|
||||
v = ctr_uw[k]
|
||||
weight = round(.01 * ttl * 100 / v)
|
||||
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
|
||||
ttl = sum(ctr_ow.values())
|
||||
print(f'OW: # Total {ttl}')
|
||||
for k in sorted(list(ctr_ow.keys())):
|
||||
v = ctr_ow[k]
|
||||
weight = round(.01 * ttl * 100 / v)
|
||||
print(f' {k}: {weight} # {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
|
||||
|
||||
ttl = sum(sheet_ctr.values())
|
||||
print(f'Sheet: # Total {ttl}')
|
||||
for k, v in sheet_ctr.items():
|
||||
print(f' {k} {v*100/ttl:.5f}% raw:{v} {v*100/total_sheets:.5f}%')
|
||||
|
||||
ttl = sum(frequency.values())
|
||||
print(f'Total: {ttl}')
|
||||
for enemy, freq in frequency.items():
|
||||
print(f'{enemy} {freq*100/ttl:.5f}% raw:{freq}')
|
||||
|
||||
ttl = sum(sheet_thing.values())
|
||||
print(f'Total Sheets?: {ttl}')
|
||||
|
||||
def rejoin(list_of_things):
|
||||
return f'[{",".join([str(i) for i in list_of_things])}]'
|
||||
|
||||
for items, cnt in sheet_thing.items():
|
||||
print(f'{",".join(items)} {cnt} {cnt*100/ttl:.5f}% {",".join([rejoin(x) for x in sheet_sub_groups[items]])}')
|
||||
|
||||
# if result not in column_headers:
|
||||
# column_headers[result] = None
|
||||
# stats[(room_id, i)][result] += 1
|
||||
# with open('result.csv', 'w') as result_file:
|
||||
# result_file.write('room_id,slot,')
|
||||
# result_file.write(','.join(column_headers.keys()))
|
||||
# result_file.write('\n')
|
||||
#
|
||||
# for key, counter in stats.items():
|
||||
# rid, slot = key
|
||||
# result_file.write(f'{rid},{slot}')
|
||||
# for result_item in column_headers.keys():
|
||||
# result_file.write(f',{counter[result_item]}')
|
||||
# result_file.write('\n')
|
||||
|
||||
525
source/enemizer/EnemyLogic.py
Normal file
525
source/enemizer/EnemyLogic.py
Normal file
@@ -0,0 +1,525 @@
|
||||
import math
|
||||
from collections import defaultdict
|
||||
|
||||
import RaceRandom as random
|
||||
|
||||
from source.logic.Rule import RuleFactory
|
||||
from source.dungeon.EnemyList import EnemySprite
|
||||
|
||||
|
||||
# these are for drops only
|
||||
def defeat_rule_single(world, player, enemy_sprite, region):
|
||||
if enemy_sprite.kind == EnemySprite.Terrorpin:
|
||||
# must be flipped
|
||||
return has('Hammer', player)
|
||||
elif enemy_sprite.kind == EnemySprite.RedBari:
|
||||
# must be burned to drop
|
||||
return or_rule(has('Fire Rod', player), and_rule(has_sword(player), has('Bombos', player)))
|
||||
vln = enemy_vulnerability(world, player, enemy_sprite, region)
|
||||
rules = []
|
||||
if vln['Blunt'] != 0:
|
||||
rules.append(has_blunt_weapon(player))
|
||||
if vln['Stun'] != 0:
|
||||
rules.append(buzzblob_rule(player))
|
||||
if vln['Somaria'] != 0:
|
||||
rules.append(somaria_rule(world, player, vln['Somaria']))
|
||||
if vln['Byrna'] != 0:
|
||||
rules.append(byrna_rule(world, player, vln['Byrna']))
|
||||
if vln['Master'] != 0:
|
||||
rules.append(has_class_2_weapon(player))
|
||||
if vln['Bow'] != 0:
|
||||
rules.append(bow_rule(world, player, vln['Bow']))
|
||||
if vln['Silvers'] != 0:
|
||||
rules.append(silvers_rule(world, player, vln['Silvers']))
|
||||
if vln['Bomb'] != 0:
|
||||
rules.append(bombs_rule(world, player, vln['Bomb']))
|
||||
if vln['Hookshot'] != 0:
|
||||
rules.append(has('Hookshot', player))
|
||||
if vln['IceRod'] != 0:
|
||||
rules.append(ice_rod_rule(world, player, vln['IceRod']))
|
||||
if vln['FireRod'] != 0:
|
||||
rules.append(fire_rod_rule(world, player, vln['FireRod']))
|
||||
if vln['Boomerang'] != 0:
|
||||
rules.append(has_boomerang(player))
|
||||
if vln['Powder'] not in [0, -3]: # fairy doesn't make it drop
|
||||
rules.append(magic_powder_rule(world, player, vln['Powder']))
|
||||
# skip medallions if vln to Blunt?
|
||||
if vln['Bombos'] != 0 and vln['Blunt'] == 0:
|
||||
rules.append(medallion_rule(world, player, 'Bombos', vln['Bombos']))
|
||||
if vln['Ether'] != 0 and vln['Blunt'] == 0:
|
||||
rules.append(medallion_rule(world, player, 'Ether', vln['Ether']))
|
||||
if vln['Quake'] != 0 and vln['Blunt'] == 0:
|
||||
rules.append(medallion_rule(world, player, 'Quake', vln['Quake']))
|
||||
if enemy_sprite.kind == EnemySprite.StalfosKnight:
|
||||
# must be bombed once made vulnerable
|
||||
return and_rule(can_use_bombs(world, player), or_rule(*rules))
|
||||
return or_rule(*rules)
|
||||
|
||||
|
||||
damage_cost = {
|
||||
'Bomb': 1, 'Bow': 1, 'Silvers': 1,
|
||||
'Powder': .5, 'Somaria': .5, 'Byrna': 1.125,
|
||||
'FireRod': 1, 'IceRod': 1,
|
||||
'Bombos': 2, 'Ether': 2, 'Quake': 2
|
||||
}
|
||||
|
||||
# damage_set = ['Blunt', 'Stun', 'Master', 'Tempered', 'Boomerang', 'Hookshot', 'Bomb', 'Silvers', 'Bow',
|
||||
# 'Somaria', 'Powder', 'FireRod', 'IceRod', 'Byrna', 'Bombos', 'Ether', 'Quake']
|
||||
|
||||
|
||||
# these are for "challenge" rooms
|
||||
def defeat_rule_multiple(world, player, enemy_sprite_region_pairs):
|
||||
vln_list = {}
|
||||
for sprite, region in enemy_sprite_region_pairs:
|
||||
vln_list[(sprite, region)] = enemy_vulnerability(world, player, sprite, region)
|
||||
|
||||
# damage_accounting = {x: list(y) for x, y in damage_types.items()}
|
||||
used_resources = {'Bomb': 0, 'Arrow': 0, 'Magic': 0}
|
||||
required_rules = []
|
||||
picky_enemies = []
|
||||
hammer_required = False
|
||||
bombs_required = False
|
||||
|
||||
for key, vln in vln_list.items():
|
||||
if key[0].kind == EnemySprite.Terrorpin:
|
||||
if not hammer_required:
|
||||
required_rules.append(has('Hammer', player))
|
||||
hammer_required = True
|
||||
picky_enemies.append(key)
|
||||
continue
|
||||
if key[0].kind == EnemySprite.StalfosKnight:
|
||||
if not bombs_required:
|
||||
required_rules.append(bombs_rule(world, player, 1))
|
||||
bombs_required = True
|
||||
used_resources['Bomb'] += 1
|
||||
picky_enemies.append(key)
|
||||
continue
|
||||
vln_types = [k for k in vln.keys() if vln[k] != 0]
|
||||
if len(vln_types) == 1:
|
||||
d_type = vln_types[0]
|
||||
required_rules.append(defeat_rule_single(world, player, key[0], key[1]))
|
||||
picky_enemies.append(key)
|
||||
if d_type in damage_cost:
|
||||
cost = damage_cost[d_type]
|
||||
if d_type == 'Bomb':
|
||||
used_resources['Bomb'] += cost
|
||||
elif d_type in ['Bow', 'Silvers']:
|
||||
used_resources['Arrow'] += cost
|
||||
else:
|
||||
used_resources['Magic'] += cost
|
||||
vln_list = {k: v for k, v in vln_list.items() if k not in picky_enemies}
|
||||
|
||||
while len(vln_list) > 0:
|
||||
|
||||
optional_clears = find_possible_rules(vln_list, used_resources, world, player)
|
||||
if len(optional_clears) == 0:
|
||||
raise Exception('Kill rules seems to be insufficient for this enemy set, please report:'
|
||||
+ ', '.join([str(x) for x, y in enemy_sprite_region_pairs]))
|
||||
|
||||
# find rules which kill the most
|
||||
# idea: this could be multiple criteria: most-constrained then which method kills the most
|
||||
best_rules = {}
|
||||
best_size = 0
|
||||
for vln_option in optional_clears.keys():
|
||||
if len(vln_option) > best_size:
|
||||
best_size = len(vln_option)
|
||||
best_rules.clear()
|
||||
best_rules[vln_option] = optional_clears[vln_option]
|
||||
elif len(vln_option) == best_size: # assumes vln_option is different from prior options
|
||||
best_rules[vln_option] = optional_clears[vln_option]
|
||||
if len(best_rules) == 1:
|
||||
vln_option, rule_pair_list = next(iter(best_rules.items()))
|
||||
else:
|
||||
vln_option, rule_pair_list = random.choice(list(best_rules.items()))
|
||||
if best_size == 0:
|
||||
raise Exception('Invulnerable enemy? rules seems to be insufficient for this enemy set, please report:'
|
||||
+ ', '.join([str(x) for x, y in enemy_sprite_region_pairs]))
|
||||
|
||||
new_vln_list = {vln_kv[0]: vln_kv[1] for idx, vln_kv in enumerate(vln_list.items()) if idx not in vln_option}
|
||||
rules_to_add = [rule for rule, resources in rule_pair_list]
|
||||
resources_to_use = [resources for rule, resources in rule_pair_list]
|
||||
required_rules.append(or_rule(*rules_to_add))
|
||||
for r in resources_to_use:
|
||||
for k, v in r.items():
|
||||
used_resources[k] += v
|
||||
vln_list = new_vln_list
|
||||
|
||||
return and_rule(*required_rules)
|
||||
|
||||
|
||||
def find_possible_rules(vln_list, used_resources, world, player):
|
||||
optional_clears = defaultdict(list)
|
||||
blunt_marker = defaultdict(bool)
|
||||
for damage_type in ['Blunt', 'Stun', 'Master', 'Boomerang', 'Hookshot']:
|
||||
# all_vln = all(vln[damage_type] != 0 for vln in vln_list.values())
|
||||
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
|
||||
if vln_sub_list:
|
||||
if damage_type == 'Blunt':
|
||||
optional_clears[vln_sub_list].append((has_blunt_weapon(player), {}))
|
||||
blunt_marker[vln_sub_list] = True
|
||||
if damage_type == 'Stun':
|
||||
optional_clears[vln_sub_list].append((buzzblob_rule(player), {}))
|
||||
if damage_type == 'Master' and not blunt_marker[vln_sub_list]:
|
||||
optional_clears[vln_sub_list].append((has_class_2_weapon(player), {}))
|
||||
if damage_type == 'Boomerang':
|
||||
optional_clears[vln_sub_list].append((has('Hookshot', player), {}))
|
||||
elif damage_type == 'Hookshot':
|
||||
optional_clears[vln_sub_list].append((has_boomerang(player), {}))
|
||||
damage_type = 'Bomb'
|
||||
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
|
||||
if vln_sub_list:
|
||||
hits = needed_resources(damage_type, vln_list)
|
||||
if hits + used_resources['Bomb'] <= 8:
|
||||
optional_clears[vln_sub_list].append(
|
||||
(bombs_rule(world, player, hits + used_resources['Bomb']), {'Bomb': hits}))
|
||||
for damage_type in ['Bow', 'Silvers']:
|
||||
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
|
||||
if vln_sub_list:
|
||||
hits = needed_resources(damage_type, vln_list)
|
||||
resources = {'Arrow': hits}
|
||||
if damage_type == 'Bow' and hits + used_resources['Arrow'] <= 25:
|
||||
optional_clears[vln_sub_list].append(
|
||||
(bow_rule(world, player, hits + used_resources['Arrow']), resources))
|
||||
if damage_type == 'Silvers' and hits + used_resources['Arrow'] <= 25:
|
||||
optional_clears[vln_sub_list].append(
|
||||
(silvers_rule(world, player, hits + used_resources['Arrow']), resources))
|
||||
for damage_type in ['Powder', 'Somaria', 'Byrna', 'FireRod', 'IceRod', 'Bombos', 'Ether', 'Quake']:
|
||||
vln_sub_list = frozenset({idx for idx, vln in enumerate(vln_list.values()) if vln[damage_type] != 0})
|
||||
if vln_sub_list:
|
||||
hits = needed_resources(damage_type, vln_list)
|
||||
resources = {'Magic': damage_cost[damage_type] * hits}
|
||||
if damage_type == 'Powder' and math.ceil(hits / 16) * 8 + used_resources['Magic'] <= 160:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 2)
|
||||
optional_clears[vln_sub_list].append((magic_powder_rule(world, player, flag), resources))
|
||||
elif damage_type == 'Somaria' and math.ceil(hits / 64) * 8 + used_resources['Magic'] <= 160:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 8)
|
||||
optional_clears[vln_sub_list].append((somaria_rule(world, player, flag), resources))
|
||||
elif damage_type == 'Byrna' and math.ceil(hits / 7) * 8 + used_resources['Magic'] <= 160:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'] * 7 / 8)
|
||||
optional_clears[vln_sub_list].append((byrna_rule(world, player, flag), resources))
|
||||
elif damage_type == 'FireRod' and hits + used_resources['Magic'] <= 160:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'])
|
||||
optional_clears[vln_sub_list].append((fire_rod_rule(world, player, flag), resources))
|
||||
elif damage_type == 'IceRod' and hits + used_resources['Magic'] <= 160:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'])
|
||||
optional_clears[vln_sub_list].append((ice_rod_rule(world, player, flag), resources))
|
||||
elif hits * 2 + used_resources['Magic'] <= 160 and not blunt_marker[vln_sub_list]:
|
||||
flag = min(vln[damage_type] for vln in vln_list.values())
|
||||
flag = flag if flag < 0 else (hits + used_resources['Magic'] / 2)
|
||||
optional_clears[vln_sub_list].append((medallion_rule(world, player, damage_type, flag), resources))
|
||||
return optional_clears
|
||||
|
||||
|
||||
def needed_resources(damage_type, vln_list):
|
||||
return sum(vln[damage_type] if vln[damage_type] >= 0 else 1 for vln in vln_list.values() if vln[damage_type] != 0)
|
||||
|
||||
|
||||
special_rules_check = {
|
||||
'Swamp Waterway': None,
|
||||
'Hera Back': [5, 6],
|
||||
'GT Petting Zoo': [5, 8, 9, 11],
|
||||
'Mimic Cave': [4, 5, 6, 7],
|
||||
'Ice Hookshot Ledge': None,
|
||||
'TR Hub Ledges': [3, 4, 5, 6, 7],
|
||||
'TR Dark Ride': [1, 2, 3],
|
||||
'GT Speed Torch': [11, 13],
|
||||
'Old Man Cave (West)': None,
|
||||
'Old Man Cave (East)': None,
|
||||
'Old Man House': [1, 3],
|
||||
'Old Man House Back': [4, 5, 6],
|
||||
'Death Mountain Return Cave (left)': None,
|
||||
'Death Mountain Return Cave (right)': [1, 2, 3, 6, 7], # 2, 5, 6 are considered embedded
|
||||
'Hookshot Fairy': [0, 1, 2, 3]
|
||||
}
|
||||
|
||||
|
||||
def special_rules_for_region(world, player, region_name, location, original_rule):
|
||||
if region_name == 'Swamp Waterway':
|
||||
return or_rule(medallion_rule(world, player, 'Quake', 1),
|
||||
medallion_rule(world, player, 'Ether', 1),
|
||||
medallion_rule(world, player, 'Bombos', 1))
|
||||
elif region_name in ['Hera Back', 'GT Petting Zoo', 'Mimic Cave']:
|
||||
enemy_number = int(location.name.split('#')[1])
|
||||
if region_name == 'Mimic Cave':
|
||||
if enemy_number in [4, 5]: # these are behind hammer blocks potentially
|
||||
return and_rule(original_rule, has('Hammer', player))
|
||||
elif enemy_number in special_rules_check[region_name]: # these are behind rails
|
||||
return and_rule(original_rule, has_boomerang(player))
|
||||
if enemy_number in special_rules_check[region_name]:
|
||||
return and_rule(original_rule, has_boomerang(player))
|
||||
else:
|
||||
return original_rule
|
||||
elif region_name in ['TR Hub Ledges', 'Ice Hookshot Ledge', 'TR Dark Ride']:
|
||||
enemy_number = int(location.name.split('#')[1])
|
||||
if special_rules_check[region_name] is None or enemy_number in special_rules_check[region_name]:
|
||||
return and_rule(original_rule, or_rule(has_boomerang(player), has('Hookshot', player)))
|
||||
else:
|
||||
return original_rule
|
||||
elif region_name in ['Old Man Cave (West)', 'Old Man Cave (East)', 'Old Man House Back', 'Old Man House',
|
||||
'Death Mountain Return Cave (left)', 'Death Mountain Return Cave (right)',
|
||||
'Hookshot Fairy']:
|
||||
enemy_number = int(location.name.split('#')[1])
|
||||
if region_name == 'Death Mountain Return Cave (left)':
|
||||
if enemy_number in [1, 5]:
|
||||
return and_rule(original_rule, or_rule(has_boomerang(player), has('Hookshot', player)))
|
||||
else:
|
||||
return and_rule(original_rule, has('Hookshot', player))
|
||||
if special_rules_check[region_name] is None or enemy_number in special_rules_check[region_name]:
|
||||
return and_rule(original_rule, has('Hookshot', player))
|
||||
else:
|
||||
return original_rule
|
||||
return original_rule
|
||||
|
||||
|
||||
def has_blunt_weapon(player):
|
||||
return or_rule(has_sword(player), has('Hammer', player))
|
||||
|
||||
|
||||
# Bombs, Arrows, Bombos, FireRod, Somaria, Byrna should be handled by the damage table logic
|
||||
# Powder doesn't work (also handled by damage table)
|
||||
def buzzblob_rule(player):
|
||||
return or_rule(has('Golden Sword', player),
|
||||
and_rule(has_blunt_weapon(player),
|
||||
or_rule(has_boomerang(player), has('Hookshot', player), has('Ice Rod', player))),
|
||||
and_rule(has('Ether', player), has_sword(player)),
|
||||
and_rule(has('Quake', player), has_sword(player)))
|
||||
|
||||
|
||||
def has_class_2_weapon(player):
|
||||
return or_rule(has_beam_sword(player), has('Hammer', player))
|
||||
|
||||
|
||||
def somaria_rule(world, player, somaria_hits):
|
||||
if somaria_hits == -1:
|
||||
return has('Cane of Somaria', player) # insta-kill somaria? - not in vanilla
|
||||
else:
|
||||
magic_needed = math.ceil(somaria_hits / 64) * 8 # 64 hits per magic bar - 80 max?
|
||||
if magic_needed > 8:
|
||||
return and_rule(has('Cane of Somaria', player), can_extend_magic(world, player, magic_needed))
|
||||
else:
|
||||
return has('Cane of Somaria', player)
|
||||
|
||||
|
||||
def byrna_rule(world, player, byrna_hits):
|
||||
if byrna_hits == -1:
|
||||
return has('Cane of Byrna', player) # insta-kill byrna? - not in vanilla
|
||||
else:
|
||||
magic_needed = math.ceil(byrna_hits / 7) * 8 # 7 hits per magic bar - generous?
|
||||
if magic_needed > 8:
|
||||
return and_rule(has('Cane of Byrna', player), can_extend_magic(world, player, magic_needed))
|
||||
else:
|
||||
return has('Cane of Byrna', player)
|
||||
|
||||
|
||||
def bow_rule(world, player, arrows):
|
||||
if arrows == -1 or 0 < arrows <= 25:
|
||||
return can_shoot_normal_arrows(world, player)
|
||||
return RuleFactory.static_rule(False)
|
||||
|
||||
|
||||
def silvers_rule(world, player, arrows):
|
||||
if arrows == -1 or 0 < arrows <= 25:
|
||||
return can_shoot_silver_arrows(world, player)
|
||||
return RuleFactory.static_rule(False)
|
||||
|
||||
|
||||
def bombs_rule(world, player, bombs):
|
||||
if bombs == -1 or 0 < bombs <= 8:
|
||||
return can_use_bombs(world, player)
|
||||
return RuleFactory.static_rule(False)
|
||||
|
||||
|
||||
def ice_rod_rule(world, player, shots):
|
||||
if shots == -1:
|
||||
return has('Ice Rod', player)
|
||||
if shots > 8:
|
||||
return and_rule(has('Ice Rod', player), can_extend_magic(world, player, shots))
|
||||
else:
|
||||
return has('Ice Rod', player)
|
||||
|
||||
|
||||
def fire_rod_rule(world, player, shots):
|
||||
if shots == -1:
|
||||
return has('Fire Rod', player)
|
||||
if shots > 8:
|
||||
return and_rule(has('Fire Rod', player), can_extend_magic(world, player, shots))
|
||||
else:
|
||||
return has('Fire Rod', player)
|
||||
|
||||
|
||||
def magic_powder_rule(world, player, shots):
|
||||
if shots == -1:
|
||||
return has('Magic Powder', player)
|
||||
if shots == -2:
|
||||
# todo: other resources possible I guess - harder to keep track of though
|
||||
return and_rule(has('Magic Powder', player), or_rule(has_blunt_weapon(player), has('Hookshot', player)))
|
||||
magic_needed = math.ceil(shots / 16) * 8 # 16 tries per magic bar, that could be tight...
|
||||
if magic_needed > 8:
|
||||
return and_rule(has('Magic Powder', player), can_extend_magic(world, player, shots))
|
||||
else:
|
||||
return has('Magic Powder', player)
|
||||
|
||||
|
||||
def medallion_rule(world, player, medallion, shots):
|
||||
if shots == -1:
|
||||
return and_rule(has(medallion, player), has_sword(player))
|
||||
if shots == -2:
|
||||
return and_rule(has(medallion, player), has_sword(player))
|
||||
magic_needed = shots * 2
|
||||
if magic_needed > 8:
|
||||
return and_rule(has(medallion, player), has_sword(player), can_extend_magic(world, player, shots))
|
||||
else:
|
||||
return and_rule(has(medallion, player), has_sword(player))
|
||||
|
||||
|
||||
def or_rule(*rules):
|
||||
return RuleFactory.disj(rules)
|
||||
|
||||
|
||||
def and_rule(*rules):
|
||||
return RuleFactory.conj(rules)
|
||||
|
||||
|
||||
def has(item, player, count=1):
|
||||
return RuleFactory.item(item, player, count)
|
||||
|
||||
|
||||
def has_sword(player):
|
||||
return or_rule(
|
||||
has('Fighter Sword', player), has('Master Sword', player),
|
||||
has('Tempered Sword', player), has('Golden Sword', player)
|
||||
)
|
||||
|
||||
|
||||
def has_beam_sword(player):
|
||||
return or_rule(
|
||||
has('Master Sword', player), has('Tempered Sword', player), has('Golden Sword', player)
|
||||
)
|
||||
|
||||
|
||||
def has_class_3_sword(player):
|
||||
return or_rule(
|
||||
has('Tempered Sword', player), has('Golden Sword', player)
|
||||
)
|
||||
|
||||
|
||||
def can_extend_magic(world, player, magic, flag_t=False):
|
||||
potion_shops = (find_shops_that_sell('Blue Potion', world, player) |
|
||||
find_shops_that_sell('Green Potion', world, player))
|
||||
return RuleFactory.extend_magic(player, magic, world.difficulty_adjustments[player], potion_shops, flag_t)
|
||||
|
||||
|
||||
# class 0 damage (subtypes 1 and 2)
|
||||
def has_boomerang(player):
|
||||
return or_rule(has('Blue Boomerang', player), has('Red_Boomerang', player))
|
||||
|
||||
|
||||
def find_shops_that_sell(item, world, player):
|
||||
return {shop.region for shop in world.shops[player] if shop.has_unlimited(item) and shop.region.player == player}
|
||||
|
||||
|
||||
def can_shoot_normal_arrows(world, player):
|
||||
if world.bow_mode[player].startswith('retro'):
|
||||
shops = find_shops_that_sell('Single Arrow', world, player)
|
||||
# retro+shopsanity, shops may not sell the Single Arrow at all
|
||||
if world.bow_mode[player] == 'retro_silvers':
|
||||
# non-progressive silvers grant wooden arrows, so shop may not be needed
|
||||
return and_rule(has('Bow', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
|
||||
has('Single Arrow', player), has('Silver Arrows', player)))
|
||||
else:
|
||||
return and_rule(has('Bow', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
|
||||
has('Single Arrow', player)))
|
||||
return has('Bow', player)
|
||||
|
||||
|
||||
def can_shoot_silver_arrows(world, player):
|
||||
# retro_silver requires the silver arrows item which is sufficient for the quiver
|
||||
if world.bow_mode[player] == 'retro':
|
||||
shops = find_shops_that_sell('Single Arrow', world, player)
|
||||
# retro+shopsanity, shops may not sell the Single Arrow at all
|
||||
return and_rule(has('Silver Arrows', player), or_rule(RuleFactory.unlimited('Single Arrow', player, shops),
|
||||
has('Single Arrow', player)))
|
||||
return and_rule(has('Bow', player), has('Silver Arrows', player))
|
||||
|
||||
|
||||
def can_use_bombs(world, player):
|
||||
return or_rule(RuleFactory.static_rule(not world.bombbag[player]), has('Bomb Upgrade (+10)', player))
|
||||
|
||||
|
||||
def enemy_vulnerability(world, player, enemy_sprite, region):
|
||||
damage_table = world.damage_table[player].damage_table
|
||||
stats = world.data_tables[player].enemy_stats
|
||||
damage_src = damage_table['DamageSource']
|
||||
sub_class_table = damage_table['SubClassTable']
|
||||
|
||||
enemy_sub_class = sub_class_table[enemy_sprite.kind]
|
||||
|
||||
vulnerability = defaultdict(int)
|
||||
|
||||
c1 = number_of_hits('Sword1', damage_src, enemy_sub_class, stats, enemy_sprite, region)
|
||||
if c1 != 0:
|
||||
if enemy_sprite.kind == EnemySprite.Buzzblob:
|
||||
vulnerability['Stun'] = -1
|
||||
else:
|
||||
vulnerability['Blunt'] = -1
|
||||
vulnerability['Master'] = -1
|
||||
vulnerability['Somaria'] = c1
|
||||
vulnerability['Byrna'] = c1
|
||||
else:
|
||||
c2 = number_of_hits('Sword3', damage_src, enemy_sub_class, stats, enemy_sprite, region)
|
||||
if c2 != 0:
|
||||
vulnerability['Master'] = -1 # currently Lynels are only vulnerable to only master spins or above
|
||||
hits = number_of_hits('Arrow', damage_src, enemy_sub_class, stats, enemy_sprite, region)
|
||||
if hits != 0:
|
||||
vulnerability['Bow'] = hits
|
||||
hits = number_of_hits('SilverArrow', damage_src, enemy_sub_class, stats, enemy_sprite, region)
|
||||
if hits != 0:
|
||||
vulnerability['Silvers'] = hits
|
||||
for method in ['Bomb', 'Hookshot', 'FireRod', 'IceRod', 'Boomerang', 'Powder', 'Bombos', 'Ether', 'Quake']:
|
||||
hits = number_of_hits(method, damage_src, enemy_sub_class, stats, enemy_sprite, region)
|
||||
if hits == -3:
|
||||
if enemy_sprite.kind != EnemySprite.Buzzblob: # buzzblobs are special and don't die
|
||||
vulnerability[method] = -1
|
||||
elif hits != 0:
|
||||
vulnerability[method] = hits
|
||||
return vulnerability
|
||||
|
||||
|
||||
def number_of_hits(source_name, damage_src, enemy_sub_class, stats, enemy_sprite, region):
|
||||
damage_class = damage_src[source_name]['class']
|
||||
sub_class = enemy_sub_class[damage_class]
|
||||
damage_amount = damage_src[source_name]['subclass'][sub_class]
|
||||
if damage_amount == 0:
|
||||
return 0
|
||||
elif damage_amount <= 0x64:
|
||||
health = stats[enemy_sprite.kind].health
|
||||
if isinstance(health, tuple):
|
||||
if enemy_sprite.kind in [EnemySprite.Tektite, EnemySprite.HardhatBeetle]:
|
||||
idx = enemy_sprite.tile_x & 0x1
|
||||
health = health[idx]
|
||||
elif region.is_light_world and region.is_dark_world:
|
||||
health = min(health)
|
||||
elif region.is_light_world:
|
||||
health = health[0]
|
||||
elif region.is_dark_world:
|
||||
health = health[1]
|
||||
else:
|
||||
health = max(health)
|
||||
return math.ceil(health / damage_amount)
|
||||
elif damage_amount in [0xF9, 0xFA, 0xFD]:
|
||||
# -1 incinerated; -2 blobbed, -3 fairy-ed (depends on enemy if "killed" or not)
|
||||
# F9: fairy, defeated, but doesn't drop anything: -3
|
||||
# FA: blobbed - can you kill a blob? = -2
|
||||
# FD: incinerated
|
||||
return special_classes[damage_amount]
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
special_classes = {0xF9: -3, 0xFA: -2, 0xFD: -1}
|
||||
|
||||
1038
source/enemizer/OwEnemyList.py
Normal file
1038
source/enemizer/OwEnemyList.py
Normal file
File diff suppressed because it is too large
Load Diff
788
source/enemizer/SpriteSheets.py
Normal file
788
source/enemizer/SpriteSheets.py
Normal file
@@ -0,0 +1,788 @@
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
import RaceRandom as random
|
||||
|
||||
from source.dungeon.EnemyList import EnemySprite, SpriteType, enemy_names, sprite_translation, overlord_names
|
||||
from source.dungeon.RoomConstants import *
|
||||
|
||||
|
||||
class SpriteRequirement:
|
||||
def __init__(self, sprite, overlord=0):
|
||||
self.sprite = sprite
|
||||
self.overlord = overlord
|
||||
|
||||
self.boss = False
|
||||
self.static = False # npcs and do not randomize
|
||||
self.killable = True
|
||||
self.can_drop = True
|
||||
self.water_only = False
|
||||
self.dont_use = False
|
||||
self.ow_valid = True
|
||||
self.uw_valid = True
|
||||
self.can_randomize = True
|
||||
self.water_phobic = False
|
||||
|
||||
self.groups = []
|
||||
self.sub_groups = defaultdict(list)
|
||||
|
||||
self.excluded_rooms = set()
|
||||
self.allowed_rooms = set()
|
||||
|
||||
def can_spawn_in_room(self, room_id):
|
||||
return room_id not in self.excluded_rooms and (self.sprite != EnemySprite.Wallmaster or room_id < 0x100)
|
||||
|
||||
def no_drop(self):
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def sub_group(self, key, subs):
|
||||
if isinstance(subs, list):
|
||||
self.sub_groups[key].extend(subs)
|
||||
else:
|
||||
self.sub_groups[key].append(subs)
|
||||
return self
|
||||
|
||||
def group(self, group_id):
|
||||
self.groups.append(group_id)
|
||||
return self
|
||||
|
||||
def exclude(self, exclusions):
|
||||
self.excluded_rooms.update(exclusions)
|
||||
return self
|
||||
|
||||
def allow(self, allowed):
|
||||
self.allowed_rooms.update(allowed)
|
||||
return self
|
||||
|
||||
def affix(self):
|
||||
self.static = True
|
||||
self.killable = False
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def stasis(self):
|
||||
self.can_randomize = False
|
||||
return self
|
||||
|
||||
def exalt(self):
|
||||
self.boss = True
|
||||
self.static = True # not randomized by sprite sheet
|
||||
return self
|
||||
|
||||
def immune(self):
|
||||
self.killable = False
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def immerse(self):
|
||||
self.water_only = True
|
||||
return self
|
||||
|
||||
def aquaphobia(self):
|
||||
self.water_phobic = True
|
||||
return self
|
||||
|
||||
def skip(self):
|
||||
self.dont_use = True
|
||||
return self
|
||||
|
||||
def ow_skip(self):
|
||||
self.ow_valid = False
|
||||
return self
|
||||
|
||||
def uw_skip(self):
|
||||
self.uw_valid = False
|
||||
return self
|
||||
|
||||
def good_for_uw_water(self):
|
||||
return self.water_only and not self.static and not self.dont_use and self.uw_valid
|
||||
|
||||
def good_for_shutter(self, forbidden):
|
||||
if self.sprite in forbidden:
|
||||
return False
|
||||
return self.killable and not self.static and not self.dont_use and self.uw_valid
|
||||
|
||||
def good_for_key_drop(self, forbidden):
|
||||
return self.good_for_shutter(forbidden) and self.can_drop
|
||||
|
||||
def __str__(self):
|
||||
return f'Req for {enemy_names[self.sprite] if self.overlord != 0x7 else overlord_names[self.sprite]}'
|
||||
|
||||
|
||||
NoFlyingRooms = {0xd2, 0x10c} # Mire 2, Mimic Cave
|
||||
NoBeamosOrTrapRooms = {0xb, 0x16, 0x19, 0x1e, 0x26, 0x27, 0x36, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4b, 0x4e, 0x55, 0x57,
|
||||
0x5f, 0x65, 0x6a, 0x74, 0x76, 0x7d, 0x7f, 0x83, 0x84, 0x85, 0x8c, 0x8d, 0x92, 0x95, 0x98, 0x9b,
|
||||
0x9c, 0x9d, 0x9e, 0xa0, 0xaa, 0xaf, 0xb3, 0xba, 0xbb, 0xbc, 0xc6, 0xcb, 0xce, 0xd0, 0xd2, 0xd5,
|
||||
0xd8, 0xdc, 0xdf, 0xe4, 0xe7, 0xee, 0xf9, 0xfd, 0x10c}
|
||||
LenientTrapsForTesting = {0x16, 0x26, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4e, 0x57,
|
||||
0x65, 0x6a, 0x74, 0x76, 0x7d, 0x98,
|
||||
0x9e, 0xaf, 0xba, 0xc6, 0xcb, 0xce, 0xd2, 0xd5,
|
||||
0xd8, 0xdf, 0xe4, 0xe7, 0xee, 0xfd, 0x10c}
|
||||
# this will have to be dynamic if cave rooms are allowed in dungeons
|
||||
WallmasterValidRooms = {
|
||||
HC_NorthCorridor, HC_SwitchRoom, HoulihanRoom, TR_CrystalRollerRoom,
|
||||
PalaceofDarkness0x09, PoD_StalfosTrapRoom, PoD_TurtleRoom, GT_EntranceRoom, Ice_EntranceRoom,
|
||||
GanonEvacuationRoute, HC_BombableStockRoom, Sanctuary, TR_Hokku_BokkuKeyRoom2, TR_BigKeyRoom, TurtleRock0x15,
|
||||
Swamp_SwimmingTreadmill, Hera_MoldormFallRoom, PoD_DarkMaze, PoD_BigChestRoom, PoD_Mimics_MovingWallRoom,
|
||||
GT_IceArmos, GT_FinalHallway, Ice_BombFloor_BariRoom, Ice_Pengator_BigKeyRoom, Tower_Agahnim, HC_KeyRatRoom,
|
||||
HC_SewerTextTriggerRoom, TR_WestExittoBalcony, TR_DoubleHokku_Bokku_BigchestRoom, Swamp_StatueRoom, Hera_BigChest,
|
||||
Swamp_EntranceRoom, Skull_Mothula, PoD_BigHubRoom, PoD_MapChest_FairyRoom, Ice_CompassRoom, Hera_HardhatBeetlesRoom,
|
||||
HC_SewerKeyChestRoom, Desert_Lanmolas, Swamp_PushBlockPuzzle_Pre_BigKeyRoom, Swamp_BigKey_BSRoom,
|
||||
Swamp_BigChestRoom, Swamp_MapChest_WaterFillRoom, Swamp_KeyPotRoom, Skull_GibdoKey_MothulaHoleRoom,
|
||||
PoD_BombableFloorRoom, PoD_SpikeBlock_ConveyorRoom, GT_TorchRoom2, Ice_StalfosKnights_ConveyorHellway,
|
||||
Ice_MapChestRoom, Tower_FinalBridgeRoom, HC_FirstDarkRoom, HC_6RopesRoom, Desert_TorchPuzzle_MovingWallRoom,
|
||||
TT_BigChestRoom, TT_JailCellsRoom, Swamp_CompassChestRoom, Skull_GibdoTorchPuzzleRoom, PoD_EntranceRoom,
|
||||
PoD_Warps_SouthMimicsRoom, GT_Mini_HelmasaurConveyorRoom, GT_MoldormRoom, Ice_Bomb_JumpRoom,
|
||||
IcePalaceCloneRoom_FairyRoom, HC_WestCorridor, HC_ThroneRoom, HC_EastCorridor, Desert_Popos2_BeamosHellwayRoom,
|
||||
Swamp_UpstairsPitsRoom, CastleSecretEntrance_UncleDeathRoom, Skull_KeyPot_TrapRoom, Skull_BigKeyRoom,
|
||||
Skull_BigChestRoom, Skull_FinalSectionEntranceRoom, PoD_HelmasaurKing, GT_SpikePitRoom, GT_Ganon_BallZ,
|
||||
GT_Gauntlet1_2_3, Ice_LonelyFirebar, Ice_HiddenChest_SpikeFloorRoom, HC_WestEntranceRoom, HC_MainEntranceRoom,
|
||||
HC_EastEntranceRoom, Desert_FinalSectionEntranceRoom, TT_WestAtticRoom, TT_EastAtticRoom,
|
||||
Swamp_HiddenChest_HiddenDoorRoom, Skull_CompassChestRoom, Skull_KeyChest_TrapRoom, PoD_RupeeRoom, GT_MimicsRooms,
|
||||
GT_LanmolasRoom, GT_Gauntlet4_5, Ice_PengatorsRoom, HC_SmallCorridortoJailCells, HC_BoomerangChestRoom,
|
||||
HC_MapChestRoom, Desert_BigChestRoom, Desert_MapChestRoom, Desert_BigKeyChestRoom, Swamp_WaterDrainRoom,
|
||||
Hera_EntranceRoom, GanonsTower, GT_EastSideCollapsingBridge_ExplodingWallRoom, GT_Winder_WarpMazeRoom,
|
||||
Ice_HiddenChest_BombableFloorRoom, Ice_BigSpikeTrapsRoom, HC_JailCellRoom, HC_NextToChasmRoom, HC_BasementChasmRoom,
|
||||
Desert_WestEntranceRoom, Desert_MainEntranceRoom, Desert_EastEntranceRoom, Hera_TileRoom, Eastern_FairyRoom,
|
||||
GT_BlockPuzzle_SpikeSkip_MapChestRoom, GT_EastandWestDownstairs_BigChestRoom, GT_Tile_TorchPuzzleRoom,
|
||||
IcePalace0x8E, Mire_Vitreous, Mire_FinalSwitchRoom, Mire_DarkBombWall_SwitchesRoom,
|
||||
Mire_DarkCaneFloorSwitchPuzzleRoom, GT_FinalCollapsingBridgeRoom, GT_Torches1Room, Mire_TorchPuzzle_MovingWallRoom,
|
||||
Mire_EntranceRoom, Eastern_EyegoreKeyRoom, GT_ManySpikes_WarpMazeRoom, GT_InvisibleFloorMazeRoom,
|
||||
GT_CompassChest_InvisibleFloorRoom, Ice_BigChestRoom, IcePalace0x9F, Mire_Pre_VitreousRoom, Mire_FishRoom,
|
||||
Mire_BridgeKeyChestRoom, MiseryMire0xA3, TR_Trinexx, GT_WizzrobesRooms, GT_MoldormFallRoom, Hera_FairyRoom,
|
||||
Eastern_StalfosSpawnRoom, Eastern_BigChestRoom, Eastern_MapChestRoom, TT_MovingSpikes_KeyPotRoom, TT_BlindTheThief,
|
||||
IcePalace0xAE, Ice_IceBridgeRoom, Tower_CircleofPots, Mire_HourglassRoom, Mire_SlugRoom, Mire_SpikeKeyChestRoom,
|
||||
TR_Pre_TrinexxRoom, TR_DarkMaze, TR_ChainChompsRoom, TR_MapChest_KeyChest_RollerRoom, Eastern_BigKeyRoom,
|
||||
Eastern_LobbyCannonballsRoom, Eastern_DarkAntifairy_KeyPotRoom, TT_Hellway, TT_ConveyorToilet, Ice_BlockPuzzleRoom,
|
||||
IcePalaceCloneRoom_SwitchRoom, Tower_DarkBridgeRoom, Mire_CompassChest_TileRoom, Mire_BigHubRoom, Mire_BigChestRoom,
|
||||
TR_FinalCrystalSwitchPuzzleRoom, TR_LaserBridge, TurtleRock0xC6, TR_TorchPuzzle,
|
||||
Eastern_EntranceRoom, UnknownRoom, TT_NorthWestEntranceRoom, TT_NorthEastEntranceRoom, Ice_HoletoKholdstareRoom,
|
||||
Tower_DarkMaze, Mire_ConveyorSlug_BigKeyRoom, Mire_Mire02_WizzrobesRoom, TR_LaserKeyRoom, TR_EntranceRoom,
|
||||
Eastern_PreArmosKnightsRoom, Eastern_CanonballRoom, EasternPalace, TT_Main_SouthWestEntranceRoom,
|
||||
TT_SouthEastEntranceRoom, Tower_EntranceRoom
|
||||
}
|
||||
|
||||
|
||||
def init_sprite_requirements():
|
||||
reqs = [
|
||||
SpriteRequirement(EnemySprite.Raven).no_drop().sub_group(3, [0x11, 0x19]).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Vulture).no_drop().sub_group(2, 0x12).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.CorrectPullSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.WrongPullSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.Octorok).sub_group(2, [0xc, 0x18]),
|
||||
SpriteRequirement(EnemySprite.Moldorm).exalt().sub_group(2, 0x30),
|
||||
SpriteRequirement(EnemySprite.Octorok4Way).sub_group(2, 0xc),
|
||||
SpriteRequirement(EnemySprite.Cucco).immune().sub_group(3, [0x15, 0x50]).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Buzzblob).sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.Snapdragon).sub_group(0, 0x16).sub_group(2, 0x17),
|
||||
SpriteRequirement(EnemySprite.Octoballoon).no_drop().sub_group(2, 0xc).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Hinox).sub_group(0, 0x16),
|
||||
SpriteRequirement(EnemySprite.Moblin).sub_group(2, 0x17),
|
||||
SpriteRequirement(EnemySprite.MiniHelmasaur).sub_group(1, 0x1e),
|
||||
SpriteRequirement(EnemySprite.AntiFairy).no_drop().sub_group(3, [0x52, 0x53])
|
||||
.exclude(NoFlyingRooms).exclude({0x40}), # no anti-fairies in aga tower bridge room
|
||||
SpriteRequirement(EnemySprite.Wiseman).affix().sub_group(2, 0x4c),
|
||||
SpriteRequirement(EnemySprite.Hoarder).sub_group(3, 0x11).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.MiniMoldorm).sub_group(1, 0x1e),
|
||||
SpriteRequirement(EnemySprite.Poe).no_drop().sub_group(3, 0x15).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Smithy).affix().sub_group(1, 0x1d).sub_group(3, 0x15),
|
||||
SpriteRequirement(EnemySprite.Statue).stasis().immune().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.CrystalSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.SickKid).affix().sub_group(0, 0x51),
|
||||
SpriteRequirement(EnemySprite.Sluggula).sub_group(2, 0x25),
|
||||
SpriteRequirement(EnemySprite.WaterSwitch).affix().sub_group(3, 0x53),
|
||||
SpriteRequirement(EnemySprite.Ropa).sub_group(0, 0x16),
|
||||
SpriteRequirement(EnemySprite.RedBari).sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.BlueBari).sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.TalkingTree).affix().sub_group(3, [0x15, 0x1B]),
|
||||
SpriteRequirement(EnemySprite.HardhatBeetle).sub_group(1, 0x1e),
|
||||
SpriteRequirement(EnemySprite.Deadrock).sub_group(3, 0x10).exclude({0x7f, 0x10c}),
|
||||
SpriteRequirement(EnemySprite.DarkWorldHintNpc).affix(), # no groups?
|
||||
SpriteRequirement(EnemySprite.AdultNpc).affix().sub_group(0, [0xe, 0x4f]),
|
||||
SpriteRequirement(EnemySprite.SweepingLady).affix().group(6), # no sub groups?
|
||||
SpriteRequirement(EnemySprite.Lumberjacks).affix().sub_group(2, 0x4a),
|
||||
SpriteRequirement(EnemySprite.RaceGameLady).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.FortuneTeller).affix().sub_group(0, 0x4b),
|
||||
SpriteRequirement(EnemySprite.ArgueBros).affix().sub_group(0, 0x4f),
|
||||
SpriteRequirement(EnemySprite.RupeePull).affix(),
|
||||
SpriteRequirement(EnemySprite.YoungSnitch).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Innkeeper).affix(), # no groups?
|
||||
SpriteRequirement(EnemySprite.Witch).affix().sub_group(2, 0x7c),
|
||||
SpriteRequirement(EnemySprite.Waterfall).affix(),
|
||||
SpriteRequirement(EnemySprite.EyeStatue).affix(),
|
||||
SpriteRequirement(EnemySprite.Locksmith).affix().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.MagicBat).affix().sub_group(3, 0x1d),
|
||||
SpriteRequirement(EnemySprite.KidInKak).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.OldSnitch).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Hoarder2).sub_group(3, 0x11).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.TutorialGuard).affix(),
|
||||
SpriteRequirement(EnemySprite.LightningGate).affix().sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.BlueGuard).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.GreenGuard).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedSpearGuard).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.BluesainBolt).sub_group(0, 0x46).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.UsainBolt).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.BlueArcher).sub_group(0, 0x48).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.GreenBushGuard).sub_group(0, 0x48).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedJavelinGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedBushGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.BombGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.GreenKnifeGuard).sub_group(1, 0x49).sub_group(2, 0x13),
|
||||
SpriteRequirement(EnemySprite.Geldman).sub_group(2, 0x12).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.Toppo).immune().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.Popo).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.Popo2).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.ArmosStatue).sub_group(3, 0x10).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.KingZora).affix().sub_group(3, 0x44),
|
||||
SpriteRequirement(EnemySprite.ArmosKnight).exalt().sub_group(3, 0x1d),
|
||||
SpriteRequirement(EnemySprite.Lanmolas).exalt().sub_group(3, 0x31),
|
||||
SpriteRequirement(EnemySprite.FireballZora).immerse().no_drop().sub_group(2, [0xc, 0x18]), # .uw_skip() test
|
||||
SpriteRequirement(EnemySprite.Zora).sub_group(2, 0xc).sub_group(3, 0x44), # .uw_skip() test
|
||||
SpriteRequirement(EnemySprite.DesertStatue).affix().sub_group(2, 0x12),
|
||||
SpriteRequirement(EnemySprite.Crab).sub_group(2, 0xc),
|
||||
SpriteRequirement(EnemySprite.LostWoodsBird).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.LostWoodsSquirrel).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.SparkCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.SparkCCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.RollerVerticalUp).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerVerticalDown).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerHorizontalLeft).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerHorizontalRight).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.Beamos).no_drop().sub_group(1, 0x2c).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.MasterSword).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
|
||||
SpriteRequirement(EnemySprite.DebirandoPit).sub_group(0, 0x2f), # skip
|
||||
SpriteRequirement(EnemySprite.Debirando).sub_group(0, 0x2f), # skip
|
||||
SpriteRequirement(EnemySprite.ArcheryNpc).affix().sub_group(0, 0x4b),
|
||||
SpriteRequirement(EnemySprite.WallCannonVertLeft).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonVertRight).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonHorzTop).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonHorzBottom).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.BallNChain).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.CannonTrooper).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.CricketRat).sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Snake).sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Keese).no_drop().sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Leever).sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.FairyPondTrigger).affix().sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.UnclePriest).affix().sub_group(0, [0x47, 0x51]),
|
||||
SpriteRequirement(EnemySprite.RunningNpc).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.BottleMerchant).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Zelda).affix(),
|
||||
SpriteRequirement(EnemySprite.Grandma).affix().sub_group(0, 0x4b).sub_group(1, 0x4d).sub_group(2, 0x4a),
|
||||
SpriteRequirement(EnemySprite.Agahnim).exalt().sub_group(0, 0x55).sub_group(1, [0x1a, 0x3d]).sub_group(2, 0x42)
|
||||
.sub_group(3, 0x43),
|
||||
SpriteRequirement(EnemySprite.FloatingSkull).sub_group(0, 0x1f).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.BigSpike).sub_group(3, [0x52, 0x53]).no_drop(),
|
||||
SpriteRequirement(EnemySprite.FirebarCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.FirebarCCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.Firesnake).no_drop().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.Hover).sub_group(2, 0x22), # .exclude(NoFlyingRooms), might be okay now
|
||||
SpriteRequirement(EnemySprite.AntiFairyCircle).no_drop().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.GreenEyegoreMimic).sub_group(2, 0x2e),
|
||||
SpriteRequirement(EnemySprite.RedEyegoreMimic).sub_group(2, 0x2e),
|
||||
|
||||
SpriteRequirement(EnemySprite.Kodongo).sub_group(2, 0x2a),
|
||||
# SpriteRequirement(EnemySprite.YellowStalfos).sub_group(0, 0x1f), # doesn't spawn
|
||||
SpriteRequirement(EnemySprite.Mothula).exalt().sub_group(2, 0x38).sub_group(3, 0x52),
|
||||
SpriteRequirement(EnemySprite.SpikeBlock).immune().sub_group(3, [0x52, 0x53]).exclude(NoBeamosOrTrapRooms)
|
||||
.exclude({0x28}), # why exclude sp entrance?
|
||||
SpriteRequirement(EnemySprite.Gibdo).sub_group(2, 0x23),
|
||||
SpriteRequirement(EnemySprite.Arrghus).exalt().sub_group(2, 0x39),
|
||||
SpriteRequirement(EnemySprite.Arrghi).exalt().sub_group(2, 0x39),
|
||||
SpriteRequirement(EnemySprite.Terrorpin).sub_group(2, 0x2a).exclude({0x10c}), # probably fine in mimic now
|
||||
SpriteRequirement(EnemySprite.Blob).sub_group(1, 0x20),
|
||||
SpriteRequirement(EnemySprite.Wallmaster).immune().ow_skip().sub_group(2, 0x23)
|
||||
.allow(WallmasterValidRooms),
|
||||
SpriteRequirement(EnemySprite.StalfosKnight).sub_group(1, 0x20).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.HelmasaurKing).exalt().sub_group(2, 0x3a).sub_group(3, 0x3e),
|
||||
SpriteRequirement(EnemySprite.Bumper).immune().aquaphobia().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeLeft).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeRight).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeTop).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeBottom).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.Pengator).sub_group(2, 0x26),
|
||||
SpriteRequirement(EnemySprite.Kyameron).no_drop().immerse().sub_group(2, 0x22),
|
||||
SpriteRequirement(EnemySprite.Wizzrobe).sub_group(2, [0x25, 0x29]),
|
||||
SpriteRequirement(EnemySprite.Zoro).sub_group(1, 0x20),
|
||||
SpriteRequirement(EnemySprite.Babasu).sub_group(1, 0x20),
|
||||
SpriteRequirement(EnemySprite.GroveOstritch).affix().sub_group(2, 0x4e),
|
||||
SpriteRequirement(EnemySprite.GroveRabbit).affix(),
|
||||
SpriteRequirement(EnemySprite.GroveBird).affix().sub_group(2, 0x4e),
|
||||
SpriteRequirement(EnemySprite.Freezor).stasis().skip().sub_group(2, 0x26),
|
||||
SpriteRequirement(EnemySprite.Kholdstare).exalt().sub_group(2, 0x3c),
|
||||
SpriteRequirement(EnemySprite.KholdstareShell).exalt(),
|
||||
SpriteRequirement(EnemySprite.FallingIce).exalt().sub_group(2, 0x3c),
|
||||
SpriteRequirement(EnemySprite.BlueZazak).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.RedZazak).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.Stalfos).sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.GreenZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.BlueZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Pikit).sub_group(3, 0x1b),
|
||||
SpriteRequirement(EnemySprite.CrystalMaiden).affix(),
|
||||
SpriteRequirement(EnemySprite.OldMan).affix().sub_group(0, 0x46).sub_group(1, 0x49).sub_group(2, 0x1c),
|
||||
SpriteRequirement(EnemySprite.PipeDown).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeUp).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeRight).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeLeft).affix(),
|
||||
SpriteRequirement(EnemySprite.GoodBee).affix().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.PurpleChest).affix().sub_group(3, 0x15),
|
||||
SpriteRequirement(EnemySprite.BombShopGuy).affix().sub_group(1, 0x4d),
|
||||
SpriteRequirement(EnemySprite.Kiki).affix().sub_group(3, 0x19),
|
||||
SpriteRequirement(EnemySprite.BlindMaiden).affix(),
|
||||
# dialog tester.sub_group(1, 0x2c)
|
||||
SpriteRequirement(EnemySprite.BullyPinkBall).affix().sub_group(3, 0x14),
|
||||
# shop keepers in complex thing below
|
||||
SpriteRequirement(EnemySprite.Drunkard).affix().sub_group(0, 0x4f).sub_group(1, 0x4d).sub_group(2, 0x4a).
|
||||
sub_group(3, 0x50),
|
||||
SpriteRequirement(EnemySprite.Vitreous).exalt().sub_group(3, 0x3d),
|
||||
SpriteRequirement(EnemySprite.Catfish).affix().sub_group(2, 0x18),
|
||||
SpriteRequirement(EnemySprite.CutsceneAgahnim).affix().sub_group(0, 0x55).sub_group(1, 0x3d)
|
||||
.sub_group(2, 0x42).sub_group(3, 0x43),
|
||||
SpriteRequirement(EnemySprite.Boulder).affix().sub_group(3, 0x10),
|
||||
SpriteRequirement(EnemySprite.Gibo).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.Thief).immune().uw_skip().sub_group(0, [0xe, 0x15]),
|
||||
SpriteRequirement(EnemySprite.Medusa).affix(),
|
||||
SpriteRequirement(EnemySprite.FourWayShooter).affix(),
|
||||
SpriteRequirement(EnemySprite.Pokey).sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.BigFairy).affix().sub_group(2, 0x39).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.Tektite).sub_group(3, 0x10),
|
||||
SpriteRequirement(EnemySprite.Chainchomp).immune().sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.TrinexxRockHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.TrinexxFireHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.TrinexxIceHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.Blind).exalt().sub_group(1, 0x2c).sub_group(2, 0x3b),
|
||||
SpriteRequirement(EnemySprite.Swamola).no_drop().sub_group(3, 0x19),
|
||||
SpriteRequirement(EnemySprite.Lynel).sub_group(3, 0x14),
|
||||
SpriteRequirement(EnemySprite.BunnyBeam).no_drop().ow_skip(),
|
||||
SpriteRequirement(EnemySprite.FloppingFish).uw_skip().immune(),
|
||||
SpriteRequirement(EnemySprite.Stal),
|
||||
SpriteRequirement(EnemySprite.Landmine).skip(),
|
||||
SpriteRequirement(EnemySprite.DiggingGameNPC).affix().sub_group(1, 0x2a),
|
||||
SpriteRequirement(EnemySprite.Ganon).exalt().sub_group(0, 0x21).sub_group(1, 0x41)
|
||||
.sub_group(2, 0x45).sub_group(3, 0x33),
|
||||
SpriteRequirement(EnemySprite.Faerie).immune(),
|
||||
SpriteRequirement(EnemySprite.FakeMasterSword).immune().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.MagicShopAssistant).affix().sub_group(0, 0x4b).sub_group(3, 0x5a),
|
||||
SpriteRequirement(EnemySprite.SomariaPlatform).affix().sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.CastleMantle).affix().sub_group(0, 0x5d),
|
||||
SpriteRequirement(EnemySprite.GreenMimic).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.RedMimic).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.MedallionTablet).affix().sub_group(2, 0x12),
|
||||
|
||||
# overlord requirements - encapsulated mostly in the required sheets
|
||||
SpriteRequirement(2, 7).affix().sub_group(2, 46),
|
||||
SpriteRequirement(3, 7).affix().sub_group(2, 46),
|
||||
SpriteRequirement(5, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(6, 7).affix().sub_group(2, [28, 36]),
|
||||
SpriteRequirement(7, 7).affix(),
|
||||
SpriteRequirement(8, 7).affix().sub_group(1, 32),
|
||||
SpriteRequirement(9, 7).affix().sub_group(2, 35),
|
||||
SpriteRequirement(0xa, 7).affix().sub_group(3, 82),
|
||||
SpriteRequirement(0xb, 7).affix().sub_group(3, 82),
|
||||
SpriteRequirement(0x10, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x11, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x12, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x13, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x14, 7).affix(),
|
||||
SpriteRequirement(0x15, 7).affix().sub_group(2, [37, 41]),
|
||||
SpriteRequirement(0x16, 7).affix().sub_group(1, 32),
|
||||
SpriteRequirement(0x17, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(0x18, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(0x19, 7).affix(),
|
||||
SpriteRequirement(0x1a, 7).affix(),
|
||||
]
|
||||
simple = {(r.sprite, r.overlord): r for r in reqs}
|
||||
shopkeeper = [
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0xff, 0x112, 0x11f}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(1, 77).sub_group(2, 74)
|
||||
.sub_group(3, 90).allow({0x10f, 0x110, 0x11f}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 79).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0x118}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0x123, 0x124}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 80)
|
||||
.allow({0x125, 0x100}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 21).allow({0x11e}),
|
||||
]
|
||||
complex_r = {}
|
||||
for req in shopkeeper:
|
||||
for r in req.allowed_rooms:
|
||||
complex_r[r] = req
|
||||
simple[(EnemySprite.Shopkeeper, 0)] = complex_r
|
||||
return simple
|
||||
|
||||
|
||||
# sheet 1 and 1c have group 4 modified from vanilla for murahdahla
|
||||
vanilla_sheets = [
|
||||
(0x00, 0x49, 0x00, 0x00), (0x46, 0x49, 0x0C, 0x3F), (0x48, 0x49, 0x13, 0x3F), (0x46, 0x49, 0x13, 0x0E),
|
||||
(0x48, 0x49, 0x0C, 0x11), (0x48, 0x49, 0x0C, 0x10), (0x4F, 0x49, 0x4A, 0x50), (0x0E, 0x49, 0x4A, 0x11),
|
||||
(0x46, 0x49, 0x12, 0x00), (0x00, 0x49, 0x00, 0x50), (0x00, 0x49, 0x00, 0x11), (0x48, 0x49, 0x0C, 0x00),
|
||||
(0x00, 0x00, 0x37, 0x36), (0x48, 0x49, 0x4C, 0x11), (0x5D, 0x2C, 0x0C, 0x44), (0x00, 0x00, 0x4E, 0x00),
|
||||
|
||||
(0x0F, 0x00, 0x12, 0x10), (0x00, 0x00, 0x00, 0x4C), (0x00, 0x0D, 0x17, 0x00), (0x16, 0x0D, 0x17, 0x1B),
|
||||
(0x16, 0x0D, 0x17, 0x14), (0x15, 0x0D, 0x17, 0x15), (0x16, 0x0D, 0x18, 0x19), (0x16, 0x0D, 0x17, 0x19),
|
||||
(0x16, 0x0D, 0x00, 0x00), (0x16, 0x0D, 0x18, 0x1B), (0x0F, 0x49, 0x4A, 0x11), (0x4B, 0x2A, 0x5C, 0x15),
|
||||
(0x16, 0x49, 0x17, 0x3F), (0x00, 0x00, 0x00, 0x15), (0x16, 0x0D, 0x17, 0x10), (0x16, 0x49, 0x12, 0x00),
|
||||
|
||||
(0x16, 0x49, 0x0C, 0x11), (0x00, 0x00, 0x12, 0x10), (0x16, 0x0D, 0x00, 0x11), (0x16, 0x49, 0x0C, 0x00),
|
||||
(0x16, 0x0D, 0x4C, 0x11), (0x0E, 0x0D, 0x4A, 0x11), (0x16, 0x1A, 0x17, 0x1B), (0x4F, 0x34, 0x4A, 0x50),
|
||||
(0x35, 0x4D, 0x65, 0x36), (0x4A, 0x34, 0x4E, 0x00), (0x0E, 0x34, 0x4A, 0x11), (0x51, 0x34, 0x5D, 0x59),
|
||||
(0x4B, 0x49, 0x4C, 0x11), (0x2D, 0x00, 0x00, 0x00), (0x5D, 0x00, 0x12, 0x59), (0x00, 0x00, 0x00, 0x00),
|
||||
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
|
||||
(0x47, 0x49, 0x2B, 0x2D), (0x46, 0x49, 0x1C, 0x52), (0x00, 0x49, 0x1C, 0x52), (0x5D, 0x49, 0x00, 0x52),
|
||||
(0x46, 0x49, 0x13, 0x52), (0x4B, 0x4D, 0x4A, 0x5A), (0x47, 0x49, 0x1C, 0x52), (0x4B, 0x4D, 0x39, 0x36),
|
||||
(0x1F, 0x2C, 0x2E, 0x52), (0x1F, 0x2C, 0x2E, 0x1D), (0x2F, 0x2C, 0x2E, 0x52), (0x2F, 0x2C, 0x2E, 0x31),
|
||||
(0x1F, 0x1E, 0x30, 0x52), (0x51, 0x49, 0x13, 0x00), (0x4F, 0x49, 0x13, 0x50), (0x4F, 0x4D, 0x4A, 0x50),
|
||||
|
||||
(0x4B, 0x49, 0x4C, 0x2B), (0x1F, 0x20, 0x22, 0x53), (0x55, 0x3D, 0x42, 0x43), (0x1F, 0x1E, 0x23, 0x52),
|
||||
(0x1F, 0x1E, 0x39, 0x3A), (0x1F, 0x1E, 0x3A, 0x3E), (0x1F, 0x1E, 0x3C, 0x3D), (0x40, 0x1E, 0x27, 0x3F),
|
||||
(0x55, 0x1A, 0x42, 0x43), (0x1F, 0x1E, 0x2A, 0x52), (0x1F, 0x1E, 0x38, 0x52), (0x1F, 0x20, 0x28, 0x52),
|
||||
(0x1F, 0x20, 0x26, 0x52), (0x1F, 0x2C, 0x25, 0x52), (0x1F, 0x20, 0x27, 0x52), (0x1F, 0x1E, 0x29, 0x52),
|
||||
|
||||
(0x1F, 0x2C, 0x3B, 0x52), (0x46, 0x49, 0x24, 0x52), (0x21, 0x41, 0x45, 0x33), (0x1F, 0x2C, 0x28, 0x31),
|
||||
(0x1F, 0x0D, 0x29, 0x52), (0x1F, 0x1E, 0x27, 0x52), (0x1F, 0x20, 0x27, 0x53), (0x48, 0x49, 0x13, 0x52),
|
||||
(0x0E, 0x1E, 0x4A, 0x50), (0x1F, 0x20, 0x26, 0x53), (0x15, 0x00, 0x00, 0x00), (0x1F, 0x00, 0x2A, 0x52),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x08), (0x5D, 0x49, 0x00, 0x52), (0x55, 0x49, 0x42, 0x43),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x56, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50),
|
||||
(0x61, 0x56, 0x33, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50)
|
||||
]
|
||||
|
||||
required_boss_sheets = {EnemySprite.ArmosKnight: 9, EnemySprite.Lanmolas: 11, EnemySprite.Moldorm: 12,
|
||||
EnemySprite.HelmasaurKing: 21, EnemySprite.Arrghus: 20, EnemySprite.Mothula: 26,
|
||||
EnemySprite.Blind: 32, EnemySprite.Kholdstare: 22, EnemySprite.Vitreous: 22,
|
||||
EnemySprite.TrinexxRockHead: 23}
|
||||
|
||||
|
||||
class SpriteSheet:
|
||||
def __init__(self, id, default_sub_groups):
|
||||
self.id = id
|
||||
self.sub_groups = list(default_sub_groups)
|
||||
self.locked = [False] * 4
|
||||
self.room_set = set()
|
||||
|
||||
def dungeon_id(self):
|
||||
return self.id + 0x40
|
||||
|
||||
def valid_sprite(self, requirement):
|
||||
if requirement.groups and self.id not in requirement.groups:
|
||||
return False
|
||||
for idx, sub in enumerate(self.sub_groups):
|
||||
if requirement.sub_groups[idx] and sub not in requirement.sub_groups[idx]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def lock_sprite_in(self, sprite):
|
||||
for i, options in sprite.sub_groups.items():
|
||||
self.locked[i] = len(options) > 0
|
||||
|
||||
def add_sprite_to_sheet(self, groups, rooms=None):
|
||||
for idx, g in enumerate(groups):
|
||||
if g is not None:
|
||||
self.sub_groups[idx] = g
|
||||
self.locked[idx] = True
|
||||
if rooms is not None:
|
||||
self.room_set.update(rooms)
|
||||
|
||||
def write_to_rom(self, rom, base_address):
|
||||
rom.write_bytes(base_address + self.id * 4, self.sub_groups)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.id} => [{", ".join([str(x) for x in self.sub_groups])}]'
|
||||
|
||||
|
||||
# convert to dungeon id
|
||||
def did(n):
|
||||
return n + 0x40
|
||||
|
||||
|
||||
def init_sprite_sheets(requirements):
|
||||
sheets = {id: SpriteSheet(id, def_sheet) for id, def_sheet in enumerate(vanilla_sheets)}
|
||||
# wait until bosses are randomized to determine which are randomized
|
||||
for sprite, sheet_num in required_boss_sheets.items():
|
||||
sheet = sheets[did(sheet_num)] # convert to dungeon sheet id
|
||||
boss_sprite = requirements[(sprite, 0)]
|
||||
sheet.lock_sprite_in(boss_sprite)
|
||||
return sheets
|
||||
|
||||
|
||||
def setup_required_dungeon_groups(sheets, data_tables):
|
||||
|
||||
sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man
|
||||
# various npcs
|
||||
sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x112,
|
||||
0x11a, 0x11c, 0x11f, 0x122})
|
||||
sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115, 0x116}) # big fairies
|
||||
sheets[did(13)].add_sprite_to_sheet([81, None, None, None], {0x55, 0x102, 0x104}) # uncle, sick kid
|
||||
sheets[did(14)].add_sprite_to_sheet([71, 73, 76, 80], {0x12, 0x105, 0x10a}) # wisemen
|
||||
sheets[did(15)].add_sprite_to_sheet([79, 77, 74, 80], {0xf4, 0xf5, 0x101, 0x103, 0x106, 0x118, 0x119}) # more npcs
|
||||
sheets[did(18)].add_sprite_to_sheet([85, 61, 66, 67], {0x20, 0x30}) # aga alter, aga1
|
||||
sheets[did(24)].add_sprite_to_sheet([85, 26, 66, 67], {0xd}) # aga2
|
||||
sheets[did(34)].add_sprite_to_sheet([33, 65, 69, 51], {0}) # ganon
|
||||
sheets[did(40)].add_sprite_to_sheet([14, None, 74, 80], {0x124, 0x125, 0x126}) # fairy + rupee npcs
|
||||
sheets[did(9)].add_sprite_to_sheet([None, None, None, 29], {0xe3}) # magic bat
|
||||
sheets[did(28)].add_sprite_to_sheet([None, None, 38, 82], {0xe, 0x7e, 0x8e, 0x9e}) # freezors
|
||||
sheets[did(3)].add_sprite_to_sheet([93, None, None, None], {0x51}) # mantle
|
||||
sheets[did(42)].add_sprite_to_sheet([21, None, None, None], {0x11e}) # hype cave
|
||||
sheets[did(10)].add_sprite_to_sheet([47, None, 46, None], {0x5c, 0x75, 0xb9, 0xd9}) # cannonballs
|
||||
sheets[did(37)].add_sprite_to_sheet([31, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms
|
||||
# not sure 31 is needed above
|
||||
|
||||
free_sheet_reqs = [
|
||||
([75, None, None, None], [0xff, 0x11f]), # shopkeepers
|
||||
([None, 77, None, 21], [0x121]), # smithy
|
||||
([None, None, None, 80], [0x108]), # chicken house
|
||||
([14, 30, None, None], [0x123]), # mini moldorm (shutter door)
|
||||
([None, None, 34, None], [0x36, 0x46, 0x66, 0x76]), # pirogusu spawners
|
||||
([None, 32, None, None], [0x9f]), # babasu spawners
|
||||
([31, None, None, None], [0x7f]), # force baris
|
||||
([None, None, 35, None], [0x39, 0x49]), # wallmasters
|
||||
# bumpers - why the split - because of other requirements -
|
||||
([None, None, None, (82, 83)], [0x17, 0x2a, 0x4c, 0x59, 0x67, 0x7e, 0x8b, 0xeb, 0xfb]),
|
||||
# crystal switches - split for some reason
|
||||
([None, None, None, (82, 83)], [0xb, 0x13, 0x1b, 0x1e, 0x2a, 0x2b, 0x31, 0x5b, 0x6b, 0x77, 0x8b,
|
||||
0x91, 0x92, 0x9b, 0x9d, 0xa1, 0xab, 0xbf, 0xc4, 0xef]),
|
||||
# laser eyes - split for some reason
|
||||
([None, None, None, (82, 83)], [0x13, 0x23, 0x96, 0xa5, 0xc5, 0xd5]),
|
||||
# statues - split for some reason
|
||||
([None, None, None, (82, 83)], [0x26, 0x2b, 0x40, 0x4a, 0x6b, 0x7b]),
|
||||
([None, None, None, 83], [0x43, 0x63, 0x87]), # tile rooms
|
||||
|
||||
# non-optional
|
||||
([None, None, None, 82], [0x58, 0x8c, 0x10b]), # pull switches
|
||||
([None, None, (28, 36), 82], [0x2, 0x64]), # pull switches (snakes)
|
||||
([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x5e, 0x7c, 0x95, 0xc3]), # collapsing bridges
|
||||
([None, None, None, 83], [0x3f, 0xce]), # pull tongue
|
||||
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
|
||||
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
|
||||
([None, None, 37, None], [0x97]), # wizzrobe spawner - in middle of room...
|
||||
|
||||
# combined
|
||||
([None, 32, None, (82, 83)], [0x3e]), # babasu spawners + crystal switch
|
||||
([None, 32, None, 83], [0x4]), # zoro spawners + crystal switch + pull switch
|
||||
([None, None, 35, 82], [0x56]), # wallmaster + collasping bridge
|
||||
([None, None, 35, (82, 83)], [0x57, 0x68]), # wallmaster + statue and wallmaster + bumpers
|
||||
([None, None, 34, 83], [0x76]), # swamp drain + pirogusu spawners
|
||||
([None, None, 35, 83], [0x8d]), # wallmaster + tile room
|
||||
([None, None, None, 83], [0xb6, 0xc1]), # tile room + crystal switch
|
||||
|
||||
# allow some sprites / increase odds:
|
||||
([72, 73, None, None], []), # allow for blue archer + greenbush
|
||||
([None, 73, 19, None], []), # allow for green knife guard
|
||||
([None, None, 12, 68], []), # increase odds for zora
|
||||
([22, None, 23, None], []), # increase odds for snapdragon
|
||||
]
|
||||
|
||||
data_tables.room_requirements = {}
|
||||
# find home for the free_sheet_reqs
|
||||
for pair in free_sheet_reqs:
|
||||
groups, room_list = pair
|
||||
for room in room_list:
|
||||
data_tables.room_requirements[room] = groups
|
||||
find_matching_sheet(groups, sheets, range(65, 124), room_list)
|
||||
|
||||
|
||||
# RandomizeRooms(optionFlags);
|
||||
# roomCollection.LoadRooms()
|
||||
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
|
||||
# more stuff
|
||||
sub_group_choices = {
|
||||
0: [22, 31, 47, 14],
|
||||
1: [44, 30, 32], # 73, 13
|
||||
2: [12, 18, 23, 24, 28, 46, 34, 35, 39, 40, 38, 41, 36, 37, 42],
|
||||
3: [17, 16, 27, 20, 82, 83, 25] # 25 for Swamola
|
||||
}
|
||||
# 70, 72 for guards
|
||||
# 0: 72 specifically for BlueArcher/GreenBush (but needs combination)
|
||||
# 0: 70 for guards but needs combination
|
||||
# 2: 19 for green knife guard, but needs combination
|
||||
# 3: 68 for Zora, but needs combination
|
||||
|
||||
|
||||
def combine_req(sub_groups, requirement):
|
||||
for i in range(0, 4):
|
||||
if requirement.sub_groups[i]:
|
||||
if len(sub_groups[i]) == 0:
|
||||
sub_groups[i].update(requirement.sub_groups[i])
|
||||
else:
|
||||
if len(sub_groups[i].intersection(requirement.sub_groups[i])) == 0:
|
||||
raise IncompatibleEnemyException
|
||||
sub_groups[i].intersection_update(requirement.sub_groups[i])
|
||||
|
||||
|
||||
def setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, sheet_range, uw=True):
|
||||
requirements = data_tables.sprite_requirements
|
||||
for room_id, enemy_map in custom_enemies.items():
|
||||
if uw:
|
||||
original_list = data_tables.uw_enemy_table.room_map[room_id]
|
||||
else:
|
||||
original_list = data_tables.ow_enemy_table[room_id]
|
||||
sub_groups_choices = [set(), set(), set(), set()]
|
||||
for idx, sprite in enumerate(original_list):
|
||||
if idx in enemy_map:
|
||||
key = (sprite_translation[enemy_map[idx]], 0)
|
||||
if key not in requirements:
|
||||
continue
|
||||
req = requirements[key]
|
||||
try:
|
||||
combine_req(sub_groups_choices, req)
|
||||
except IncompatibleEnemyException:
|
||||
logging.getLogger('').warning(f'Incompatible enemy: {hex(room_id)}:{idx} {enemy_map[idx]}')
|
||||
else:
|
||||
sprite_secondary = 0 if sprite.sub_type != SpriteType.Overlord else sprite.sub_type
|
||||
key = (sprite.kind, sprite_secondary)
|
||||
if key not in requirements:
|
||||
continue
|
||||
req = requirements[key]
|
||||
if isinstance(req, dict):
|
||||
req = req[room_id]
|
||||
if req.static or not req.can_randomize:
|
||||
try:
|
||||
combine_req(sub_groups_choices, req)
|
||||
except IncompatibleEnemyException:
|
||||
raise IncompatibleEnemyException(f'Incompatible enemy: {hex(room_id)}:{idx} {str(req)}')
|
||||
sheet_req = [None if not x else tuple(x) for x in sub_groups_choices]
|
||||
find_matching_sheet(sheet_req, sheets, sheet_range, [room_id], True)
|
||||
|
||||
|
||||
def randomize_underworld_sprite_sheets(sheets, data_tables, custom_enemies):
|
||||
setup_required_dungeon_groups(sheets, data_tables)
|
||||
|
||||
setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, range(65, 124), True)
|
||||
|
||||
for num in range(65, 124): # sheets 0x41 to 0x7B inclusive
|
||||
sheet = sheets[num]
|
||||
# if not sheet.locked[1] and num in [65, 66, 67, 68]: # guard stuff, kind of
|
||||
# sheet.locked[1] = True
|
||||
# sheet.sub_groups[1] = random.choice([13, 73])
|
||||
|
||||
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
|
||||
while free_slots:
|
||||
choices = [c for c in data_tables.sheet_choices if all(slot in free_slots for slot in c.slots)]
|
||||
weights = [c.weight for c in choices]
|
||||
choice = random.choices(choices, weights, k=1)[0]
|
||||
for idx, val in choice.assignments.items():
|
||||
v = random.choice(val) if isinstance(val, list) else val
|
||||
sheet.sub_groups[idx] = v
|
||||
sheet.locked[idx] = True
|
||||
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
|
||||
|
||||
|
||||
def setup_required_overworld_groups(sheets):
|
||||
sheets[7].add_sprite_to_sheet([None, None, 74, None], {0x2}) # lumberjacks
|
||||
sheets[16].add_sprite_to_sheet([None, None, 18, 16], {0x3, 0x93}) # WDM (pre/post-Aga)
|
||||
sheets[7].add_sprite_to_sheet([None, None, None, 17], {0xA, 0x9A}) # DM Foothills? (pre/post-Aga)
|
||||
sheets[4].add_sprite_to_sheet([None, None, None, None], {0xF, 0x9F}) # Waterfall of wishing (pre/post-Aga)
|
||||
sheets[3].add_sprite_to_sheet([None, None, None, 14], {0x14, 0xA4}) # Graveyard (pre/post-Aga)
|
||||
sheets[1].add_sprite_to_sheet([None, None, 76, 0x3F], {0x1B, 0xAB}) # Hyrule Castle (pre/post-Aga)
|
||||
sheets[2].add_sprite_to_sheet([None, None, None, 0x3F], {}) # Hyrule Castle - rain state
|
||||
# Smithy/Race/Kak (pre/post-Aga)
|
||||
sheets[6].add_sprite_to_sheet([0x4F, 0x49, 0x4A, 0x50], {0x18, 0x22, 0x28, 0xA8, 0xB2, 0xB8})
|
||||
sheets[8].add_sprite_to_sheet([None, None, 18, None], {0x30, 0xC0}) # Desert (pre/post-Aga)
|
||||
sheets[10].add_sprite_to_sheet([None, None, None, 17], {0x3A, 0xCA}) # M-rock (pre/post-Aga)
|
||||
sheets[22].add_sprite_to_sheet([None, None, 24, None], {0x4F, 0xDF}) # Catfish (pre/post-Aga)
|
||||
sheets[21].add_sprite_to_sheet([21, None, None, 21], {0x62, 0xF2}) # Smith DW (pre/post-Aga)
|
||||
sheets[27].add_sprite_to_sheet([None, 42, None, None], {0x68, 0xF8}) # Dig Game (pre/post-Aga)
|
||||
sheets[13].add_sprite_to_sheet([None, None, 76, None], {0x16, 0xA6}) # Witch hut (pre/post-Aga)
|
||||
sheets[29].add_sprite_to_sheet([None, 77, None, 21], {0x69, 0xF9}) # VoO South (pre/post-Aga)
|
||||
sheets[15].add_sprite_to_sheet([None, None, 78, None], {0x2A, 0xBA}) # Haunted Grove (pre/post-Aga)
|
||||
sheets[17].add_sprite_to_sheet([None, None, None, 76], {0x6A, 0xFA}) # Stumpy (pre/post-Aga)
|
||||
sheets[12].add_sprite_to_sheet([None, None, 55, 54], {0x80, 0x110}) # Specials (pre/post-Aga)
|
||||
sheets[14].add_sprite_to_sheet([None, None, 12, 68], {0x81, 0x111}) # Zora's Domain (pre/post-Aga)
|
||||
sheets[26].add_sprite_to_sheet([15, None, None, None], {0x92}) # Lumberjacks post-Aga
|
||||
sheets[23].add_sprite_to_sheet([None, None, None, 25], {0x5E, 0xEE}) # PoD pre/post-Aga
|
||||
|
||||
free_sheet_reqs = [
|
||||
[None, None, None, 0x14], # bully+pink ball needs this
|
||||
[72, 73, None, None], # allow for blue archer + green bush
|
||||
[None, 73, 19, None], # allow for green knife guard
|
||||
[22, None, 23, None], # increase odds for snapdragon
|
||||
[70, 73, None, None], # guards group (ballnchain, redbush, redjav, cannon, bomb, bluesain
|
||||
[None, None, None, 0x15], # an option for talking trees
|
||||
[None, None, None, 0x1B], # an option for talking trees
|
||||
]
|
||||
|
||||
for group in free_sheet_reqs:
|
||||
find_matching_sheet(group, sheets, range(1, 64))
|
||||
|
||||
|
||||
class NoMatchingSheetException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class IncompatibleEnemyException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def find_matching_sheet(groups, sheets, search_sheets, room_list=None, lock_match=False):
|
||||
possible_sheets = []
|
||||
found_match = False
|
||||
for num in search_sheets:
|
||||
if num in {6, 65, 69, 71, 78, 79, 82, 88, 98}: # these are not useful sheets for randomization
|
||||
continue
|
||||
sheet = sheets[num]
|
||||
valid = True
|
||||
match = True
|
||||
for idx, value in enumerate(groups):
|
||||
if value is not None and sheet.locked[idx]:
|
||||
valid = False
|
||||
if (sheet.sub_groups[idx] not in value if isinstance(value, tuple)
|
||||
else value != sheet.sub_groups[idx]):
|
||||
match = False
|
||||
elif value is not None:
|
||||
match = False
|
||||
if match:
|
||||
found_match = True
|
||||
if lock_match and room_list is not None:
|
||||
sheet.room_set.update(room_list)
|
||||
break
|
||||
if valid:
|
||||
possible_sheets.append(sheet)
|
||||
if not found_match:
|
||||
if len(possible_sheets) == 0:
|
||||
raise NoMatchingSheetException
|
||||
chosen_sheet = random.choice(possible_sheets)
|
||||
chosen_groups = [(random.choice(g) if isinstance(g, tuple) else g) for g in groups]
|
||||
chosen_sheet.add_sprite_to_sheet(chosen_groups, room_list)
|
||||
|
||||
|
||||
def randomize_overworld_sprite_sheets(sheets, data_tables, custom_enemies):
|
||||
setup_required_overworld_groups(sheets)
|
||||
|
||||
setup_custom_enemy_sheets(custom_enemies, sheets, data_tables, range(1, 64), False)
|
||||
|
||||
for num in range(1, 64): # sheets 0x1 to 0x3F inclusive
|
||||
sheet = sheets[num]
|
||||
if num == 6: # skip this group - it is locked for kakariko
|
||||
continue
|
||||
|
||||
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
|
||||
while free_slots:
|
||||
choices = [c for c in data_tables.sheet_choices if all(slot in free_slots for slot in c.slots)]
|
||||
weights = [c.weight for c in choices]
|
||||
choice = random.choices(choices, weights, k=1)[0]
|
||||
for idx, val in choice.assignments.items():
|
||||
v = random.choice(val) if isinstance(val, list) else val
|
||||
sheet.sub_groups[idx] = v
|
||||
sheet.locked[idx] = True
|
||||
free_slots = [idx for idx in range(0, 4) if not sheet.locked[idx]]
|
||||
|
||||
|
||||
class SheetChoice:
|
||||
|
||||
def __init__(self, slots, assignments, weight):
|
||||
self.slots = slots
|
||||
self.assignments = assignments
|
||||
self.weight = weight
|
||||
102
source/enemizer/TilePattern.py
Normal file
102
source/enemizer/TilePattern.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import os
|
||||
import json
|
||||
import codecs
|
||||
|
||||
if __name__ == '__main__':
|
||||
directory = './EnemizerCLI.Core/tiles'
|
||||
for filename in os.listdir(directory):
|
||||
with codecs.open(directory+'/'+filename, 'r', 'utf-8-sig') as fin:
|
||||
pattern = json.load(fin)
|
||||
pairs = [f'({x["x"]}, {x["y"]})' for x in pattern["Items"]]
|
||||
print(f'(\'{filename}\', [{", ".join(pairs)}]),')
|
||||
|
||||
tile_patterns = [
|
||||
('heart soft', [(3, 1), (5, 2), (4, 7), (2, 5), (7, 1), (7, 5), (8, 4), (1, 2), (2, 1), (1, 4), (5, 7), (6, 1),
|
||||
(6, 6), (4, 2), (8, 3), (1, 3), (3, 6), (8, 2)]),
|
||||
('metroid', [(2, 7), (7, 7), (1, 3), (3, 1), (8, 3), (1, 6), (4, 5), (5, 3), (1, 4), (6, 1), (6, 4), (8, 6), (3, 4),
|
||||
(7, 5), (4, 1), (5, 5), (2, 2), (2, 5), (7, 2), (5, 1), (4, 3), (8, 4)]),
|
||||
# ('moldorm vertical', [(5, 1), (6, 0), (7, 2), (5, 4), (4, 4), (4, 1), (3, 5), (5, 6), (3, 2), (6, 6), (7, 5),
|
||||
# (6, 1), (4, 8), (3, 3), (5, 7), (3, 8), (2, 7), (6, 4), (4, 0), (3, 6), (7, 3), (4, 6)]),
|
||||
# ('scream emoji', [(2, 2), (7, 2), (2, 3), (7, 3), (1, 7), (8, 7), (3, 2), (6, 2), (2, 6), (7, 6), (3, 3), (6, 3),
|
||||
# (2, 7), (7, 7), (4, 5), (5, 7), (5, 5), (4, 7), (4, 6), (5, 6), (2, 5), (7, 5)]),
|
||||
('mario mushroom', [(3, 7), (4, 7), (5, 7), (3, 4), (4, 4), (5, 4), (3, 1), (4, 1), (5, 1), (2, 2), (6, 6), (6, 2),
|
||||
(2, 6), (1, 3), (7, 5), (7, 3), (1, 5), (1, 4), (6, 5), (7, 4), (2, 5)]),
|
||||
('moldorm', [(1, 3), (2, 5), (3, 6), (5, 5), (7, 5), (7, 2), (5, 3), (3, 2), (2, 4), (1, 5), (5, 4), (6, 2), (7, 4),
|
||||
(8, 1), (8, 4), (4, 2), (9, 2), (2, 3), (4, 6), (9, 3), (7, 3), (6, 6)]),
|
||||
# ('thinking emoji', [(5, 6), (6, 4), (4, 3), (3, 1), (2, 6), (5, 3), (6, 6), (6, 1), (3, 0), (4, 7), (2, 4),
|
||||
# (3, 8), (6, 0), (3, 7), (3, 3)]),
|
||||
('triangle', [(1, 5), (7, 5), (4, 2), (3, 5), (5, 5), (4, 3), (2, 4), (6, 4), (5, 3), (2, 5), (6, 5), (3, 3),
|
||||
(4, 5), (5, 4), (3, 4), (4, 4)]),
|
||||
('heart', [(8, 3), (2, 3), (5, 7), (2, 4), (8, 4), (4, 6), (6, 6), (8, 2), (2, 2), (5, 2), (7, 1), (3, 1), (3, 5),
|
||||
(6, 1), (7, 5), (4, 1)]),
|
||||
('arrghus', [(4, 1), (6, 2), (2, 3), (4, 3), (3, 4), (4, 5), (5, 6), (3, 7), (1, 4), (2, 5), (5, 1), (6, 3), (2, 2),
|
||||
(7, 4), (5, 4), (4, 4), (6, 5), (3, 6), (5, 7), (3, 1), (3, 5), (5, 5)]),
|
||||
# ('cowboy smile', [(1, 2), (3, 3), (4, 1), (3, 5), (5, 8), (6, 7), (5, 2), (7, 2), (1, 3), (2, 7), (5, 5), (5, 3),
|
||||
# (3, 2), (4, 3), (7, 3), (2, 3), (4, 2), (3, 8), (4, 8), (6, 3)]),
|
||||
('clown face happy', [(2, 2), (7, 6), (7, 2), (2, 6), (3, 3), (6, 7), (6, 3), (3, 7), (2, 3), (5, 6), (7, 3),
|
||||
(4, 6), (2, 5), (6, 6), (7, 5), (3, 6), (4, 5), (5, 7), (5, 5), (4, 7), (3, 2), (6, 2)]),
|
||||
('generic happy face', [(2, 1), (6, 3), (6, 5), (4, 6), (2, 2), (6, 6), (2, 3), (3, 5), (3, 2), (3, 3), (6, 2),
|
||||
(5, 5), (1, 2), (3, 6), (7, 5), (7, 1), (4, 5), (8, 2), (5, 6), (2, 5), (7, 3), (7, 2)]),
|
||||
# ('YMCA', [(1, 2), (2, 3), (5, 2), (7, 2), (6, 3), (7, 4), (2, 4), (5, 4), (6, 2), (3, 2), (5, 3), (7, 3), (7, 6),
|
||||
# (4, 8), (2, 7), (6, 7), (4, 6), (8, 8), (8, 7), (3, 8), (3, 6), (6, 8)]),
|
||||
# ('ze', [(5, 7), (6, 7), (7, 7), (1, 3), (2, 3), (3, 3), (5, 5), (6, 5), (7, 5), (1, 7), (2, 7), (3, 7), (5, 3),
|
||||
# (6, 3), (7, 3), (3, 4), (2, 5), (1, 6), (5, 4), (5, 6)]),
|
||||
# ('space invader metroid', [(4, 1), (2, 3), (3, 5), (5, 6), (7, 6), (7, 3), (2, 8), (3, 2), (1, 7), (1, 4), (6, 2),
|
||||
# (8, 5), (7, 8), (4, 6), (8, 7), (5, 1), (2, 6), (8, 4), (1, 5), (6, 5)]),
|
||||
('screw attack', [(2, 7), (7, 4), (6, 1), (3, 7), (2, 4), (5, 6), (4, 2), (5, 4), (3, 6), (7, 1), (3, 3), (6, 4),
|
||||
(4, 6), (4, 3), (6, 2), (3, 4), (6, 5), (5, 2), (4, 5), (4, 4), (5, 3), (5, 5)]),
|
||||
('vanilla wrong order', [(7, 2), (7, 4), (7, 5), (7, 7), (6, 3), (6, 5), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6),
|
||||
(4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (3, 3), (3, 5), (2, 2), (2, 4), (2, 5), (2, 7)]),
|
||||
('tile shaped tiles', [(2, 7), (2, 6), (2, 5), (2, 4), (2, 3), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2),
|
||||
(7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (6, 7), (5, 7), (4, 7), (3, 7), (4, 5), (5, 4)]),
|
||||
# ('panda shocked emoji', [(7, 3), (7, 4), (3, 3), (3, 4), (5, 5), (5, 6), (5, 7), (4, 6), (4, 7), (6, 7), (6, 6),
|
||||
# (8, 6), (8, 7), (8, 8), (2, 8), (2, 7), (2, 6), (2, 1), (3, 1), (7, 1), (8, 1), (5, 8)]),
|
||||
('JK', [(1, 5), (3, 4), (5, 3), (7, 3), (3, 2), (7, 5), (6, 4), (2, 6), (5, 6), (5, 5), (8, 2), (3, 5), (8, 6),
|
||||
(5, 2), (3, 3), (5, 4)]),
|
||||
('dollar sign', [(6, 2), (5, 1), (4, 1), (3, 1), (2, 2), (2, 6), (3, 7), (4, 7), (5, 7), (6, 6), (2, 3), (6, 5),
|
||||
(3, 4), (5, 4), (4, 4), (4, 0), (4, 2), (4, 3), (4, 5), (4, 6), (4, 8)]),
|
||||
# ('rupee diagonal', [(1, 4), (1, 5), (1, 6), (1, 7), (2, 7), (3, 7), (4, 7), (5, 6), (6, 5), (7, 4), (7, 3),
|
||||
# (7, 2), (7, 1), (6, 1), (5, 1), (4, 1), (3, 2), (2, 3), (3, 5), (4, 4), (5, 3)]),
|
||||
# ('sword', [(1, 8), (8, 1), (8, 2), (1, 4), (7, 1), (5, 8), (7, 3), (2, 4), (6, 2), (5, 7), (6, 4), (2, 5), (5, 3),
|
||||
# (4, 7), (5, 5), (3, 6), (4, 4), (2, 7), (4, 6), (3, 5)]),
|
||||
('z1 dungeon1', [(4, 6), (6, 4), (2, 4), (3, 7), (4, 3), (5, 7), (3, 2), (5, 4), (3, 5), (5, 5), (4, 2), (6, 3),
|
||||
(4, 7), (3, 4), (7, 3), (4, 5), (4, 4)]),
|
||||
# ('z1 dungeon 4', [(4, 8), (3, 6), (4, 4), (5, 2), (3, 1), (4, 3), (6, 2), (4, 1), (3, 3), (5, 4), (3, 5), (4, 7),
|
||||
# (6, 1), (3, 8), (5, 7), (3, 2), (4, 6), (3, 4), (5, 1)]),
|
||||
# ('LTTP', [(3, 4), (2, 3), (6, 2), (6, 4), (2, 2), (5, 2), (6, 3), (2, 4), (7, 2), (3, 6), (4, 8), (8, 7), (7, 6),
|
||||
# (7, 8), (5, 6), (7, 7), (4, 6), (4, 7), (8, 6)]),
|
||||
('triple triforce', [(4, 2), (3, 3), (4, 3), (5, 3), (6, 5), (5, 6), (6, 6), (7, 6), (3, 6), (2, 6), (2, 5),
|
||||
(1, 6)]),
|
||||
# ('TILE', [(2, 2), (5, 4), (3, 2), (2, 4), (5, 2), (2, 3), (1, 2), (5, 3), (3, 6), (6, 6), (7, 8), (8, 6), (6, 7),
|
||||
# (3, 8), (4, 8), (3, 7), (6, 8), (7, 6), (7, 7), (8, 8)]),
|
||||
# ('panda thinking emoji', [(2, 1), (3, 1), (6, 2), (7, 2), (6, 3), (3, 2), (3, 3), (3, 5), (4, 5), (5, 5), (2, 6),
|
||||
# (2, 7), (1, 7), (2, 8), (1, 8), (3, 7), (4, 7), (3, 8)]),
|
||||
# ('pokata key', [(3, 1), (4, 2), (5, 3), (4, 4), (4, 6), (5, 7), (6, 8), (4, 8), (6, 6), (3, 3), (5, 1), (4, 5),
|
||||
# (3, 2), (4, 3), (5, 4), (5, 6), (4, 7), (5, 8), (3, 4), (5, 2), (4, 1)]),
|
||||
('tile shaped tiles randomish', [(4, 2), (2, 2), (7, 5), (5, 4), (3, 2), (4, 5), (4, 7), (7, 7), (2, 7), (2, 4),
|
||||
(7, 2), (2, 5), (5, 7), (7, 4), (5, 2), (6, 2), (3, 7), (2, 3), (7, 6), (6, 7),
|
||||
(7, 3), (2, 6)]),
|
||||
('NO', [(1, 5), (4, 4), (3, 4), (6, 2), (8, 4), (1, 2), (8, 5), (7, 5), (1, 3), (6, 5), (6, 4), (1, 4), (4, 5),
|
||||
(4, 2), (2, 3), (7, 2), (8, 2), (8, 3), (4, 3), (6, 3)]),
|
||||
('bomb', [(3, 3), (5, 7), (6, 4), (2, 6), (5, 3), (3, 7), (6, 6), (2, 4), (7, 2), (2, 5), (4, 7), (5, 1), (4, 2),
|
||||
(6, 5), (6, 1), (4, 3), (8, 2)]),
|
||||
# ('boot', [(6, 7), (8, 6), (5, 5), (5, 3), (8, 2), (3, 6), (4, 8), (7, 8), (8, 4), (6, 2), (2, 7), (3, 8), (4, 5),
|
||||
# (5, 4), (7, 2), (8, 7), (8, 8), (8, 3), (5, 8), (2, 8), (5, 2), (8, 5)]),
|
||||
# ('javalogo', [(5, 8), (4, 8), (3, 8), (2, 8), (1, 7), (5, 6), (4, 6), (3, 6), (2, 6), (1, 5), (7, 7), (8, 6),
|
||||
# (7, 5), (3, 4), (3, 3), (2, 2), (3, 1), (5, 4), (5, 3), (6, 2)]),
|
||||
# ('pokata and ender key', [(3, 1), (5, 3), (4, 4), (4, 6), (5, 7), (6, 8), (4, 8), (6, 6), (3, 3), (5, 1), (4, 5),
|
||||
# (3, 2), (4, 7), (4, 1), (5, 8), (5, 2), (3, 4), (5, 6), (5, 4)]),
|
||||
('kitty', [(3, 1), (6, 4), (7, 6), (8, 3), (1, 4), (3, 7), (3, 4), (2, 2), (5, 2), (6, 1), (6, 5), (6, 7), (2, 6),
|
||||
(7, 2), (8, 5), (1, 3), (1, 5), (4, 2), (3, 5), (4, 6), (8, 4), (5, 6)]),
|
||||
('creeper face', [(3, 7), (4, 5), (5, 4), (5, 6), (3, 3), (2, 2), (3, 2), (7, 3), (6, 7), (4, 6), (6, 3), (7, 2),
|
||||
(2, 3), (4, 4), (3, 6), (6, 2), (6, 6), (5, 5)]),
|
||||
('fast', [(7, 7)])
|
||||
]
|
||||
|
||||
|
||||
banned_tiles = {
|
||||
# these are pots in tower of hera, only ban if pottery is on?
|
||||
(1, 8), (1, 7), (3, 8), (5, 8), (7, 8),
|
||||
# these are crystal barrier tiles
|
||||
# (8, 3), (8, 4), (8, 5) # should I ban these too? bypasses barrier logic? regex \(8, [345]\)
|
||||
}
|
||||
1
source/enemizer/__init__.py
Normal file
1
source/enemizer/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# do nothing, just exist to make "source" package
|
||||
304
source/enemizer/damage_table.yaml
Normal file
304
source/enemizer/damage_table.yaml
Normal file
@@ -0,0 +1,304 @@
|
||||
# From: https://spannerisms.github.io/damage
|
||||
# There are 16 damage classes, each with 8 subclasses.
|
||||
# These subclasses determine the damage or effect inflicted on a sprite.
|
||||
# Subclass data is stored as a table in ROM at $0D:B8F1
|
||||
|
||||
# DamageSource and SubClassTable
|
||||
|
||||
#_0DB8F1: db $00, $01, $20, $FF, $FC, $FB, $00, $00 ; 0x00 - Boomerang
|
||||
#_0DB8F9: db $00, $02, $40, $04, $00, $00, $00, $00 ; 0x01 - Sword 1
|
||||
#_0DB901: db $00, $04, $40, $02, $03, $00, $00, $00 ; 0x02 - Sword 2
|
||||
#_0DB909: db $00, $08, $40, $04, $00, $00, $00, $00 ; 0x03 - Sword 3
|
||||
#_0DB911: db $00, $10, $40, $08, $00, $00, $00, $00 ; 0x04 - Sword 4
|
||||
#_0DB919: db $00, $10, $40, $08, $00, $00, $00, $00 ; 0x05 - Sword 5
|
||||
#_0DB921: db $00, $04, $40, $10, $00, $00, $00, $00 ; 0x06 - Arrow
|
||||
#_0DB929: db $00, $FF, $40, $FF, $FC, $FB, $00, $00 ; 0x07 - Hookshot
|
||||
#_0DB931: db $00, $04, $40, $FF, $FC, $FB, $20, $00 ; 0x08 - Bomb
|
||||
#_0DB939: db $00, $64, $18, $64, $00, $00, $00, $00 ; 0x09 - Silver arrow
|
||||
#_0DB941: db $00, $F9, $FA, $FF, $64, $00, $00, $00 ; 0x0A - Powder
|
||||
#_0DB949: db $00, $08, $40, $FD, $04, $10, $00, $00 ; 0x0B - Fire rod
|
||||
#_0DB951: db $00, $08, $40, $FE, $04, $00, $00, $00 ; 0x0C - Ice rod
|
||||
#_0DB959: db $00, $10, $40, $FD, $00, $00, $00, $00 ; 0x0D - Bombos
|
||||
#_0DB961: db $00, $FE, $40, $10, $00, $00, $00, $00 ; 0x0E - Ether
|
||||
#_0DB969: db $00, $20, $40, $FF, $00, $00, $00, $FA ; 0x0F - Quake
|
||||
|
||||
# Special Values:
|
||||
# $F9 Target becomes a faerie
|
||||
# $FA Target becomes a blob
|
||||
# $FB Target stunned for 32 frames
|
||||
# $FC Target stunned for 128 frames
|
||||
# $FD Target incinerated
|
||||
# $FE Target becomes frozen
|
||||
# $FF Target stunned for 255 frames
|
||||
|
||||
DamageSource:
|
||||
Boomerang:
|
||||
class: 0x00
|
||||
subclass: [0x00, 0x01, 0x20, 0xFF, 0xFC, 0xFB, 0x00, 0x00]
|
||||
Sword1:
|
||||
class: 0x01
|
||||
subclass: [0x00, 0x02, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00]
|
||||
Sword2:
|
||||
class: 0x02
|
||||
subclass: [0x00, 0x04, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00]
|
||||
Sword3:
|
||||
class: 0x03
|
||||
subclass: [0x00, 0x08, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00]
|
||||
Sword4:
|
||||
class: 0x04
|
||||
subclass: [0x00, 0x10, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00]
|
||||
Sword5:
|
||||
class: 0x05
|
||||
subclass: [0x00, 0x10, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00]
|
||||
Arrow:
|
||||
class: 0x06
|
||||
subclass: [0x00, 0x04, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00]
|
||||
Hookshot:
|
||||
class: 0x07
|
||||
subclass: [0x00, 0xFF, 0x40, 0xFF, 0xFC, 0xFB, 0x00, 0x00]
|
||||
Bomb:
|
||||
class: 0x08
|
||||
subclass: [0x00, 0x04, 0x40, 0xFF, 0xFC, 0xFB, 0x20, 0x00]
|
||||
SilverArrow:
|
||||
class: 0x09
|
||||
subclass: [0x00, 0x64, 0x18, 0x64, 0x00, 0x00, 0x00, 0x00]
|
||||
Powder:
|
||||
class: 0x0A
|
||||
subclass: [0x00, 0xF9, 0xFA, 0xFF, 0x64, 0x00, 0x00, 0x00]
|
||||
FireRod:
|
||||
class: 0x0B
|
||||
subclass: [0x00, 0x08, 0x40, 0xFD, 0x04, 0x10, 0x00, 0x00]
|
||||
IceRod:
|
||||
class: 0x0C
|
||||
subclass: [0x00, 0x08, 0x40, 0xFE, 0x04, 0x00, 0x00, 0x00]
|
||||
Bombos:
|
||||
class: 0x0D
|
||||
subclass: [0x00, 0x10, 0x40, 0xFD, 0x00, 0x00, 0x00, 0x00]
|
||||
Ether:
|
||||
class: 0x0E
|
||||
subclass: [0x00, 0xFE, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00]
|
||||
Quake:
|
||||
class: 0x0F
|
||||
subclass: [0x00, 0x20, 0x40, 0xFF, 0x00, 0x00, 0x00, 0xFA]
|
||||
|
||||
# The subclass that each sprite should look for in each damage class is in a table in WRAM at $7F:6000
|
||||
# Rando migrated it to $31:C800
|
||||
SubClassTable:
|
||||
0x0: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 1, 1]
|
||||
0x1: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 1, 1]
|
||||
0x2: [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x8: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x9: [0, 1, 3, 3, 3, 3, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0xA: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0xB: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0xC: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 3, 1]
|
||||
0xD: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3]
|
||||
0xE: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 2, 7]
|
||||
0xF: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 3, 2]
|
||||
0x10: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 3, 1]
|
||||
0x11: [4, 1, 1, 1, 1, 2, 1, 0, 2, 1, 0, 1, 3, 3, 1, 7]
|
||||
0x12: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x13: [0, 1, 1, 1, 1, 1, 1, 3, 2, 3, 2, 0, 0, 3, 2, 7]
|
||||
0x14: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x15: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
|
||||
0x16: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x17: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 7]
|
||||
0x18: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 1, 3, 3, 7]
|
||||
0x19: [1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, 1, 3, 2, 3]
|
||||
0x1A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x1B: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 3, 2]
|
||||
0x1C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x1D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x1E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x1F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x20: [3, 1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x21: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x22: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 2, 7]
|
||||
0x23: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 3]
|
||||
0x24: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 3]
|
||||
0x25: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x26: [0, 1, 1, 1, 1, 1, 0, 3, 3, 1, 0, 0, 0, 3, 1, 3]
|
||||
0x27: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7]
|
||||
0x28: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x29: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x2A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
|
||||
0x2B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x2C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x2D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x2E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x2F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x30: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x31: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x32: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x33: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x34: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x35: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x36: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x37: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x38: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x39: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x3E: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 7]
|
||||
0x3F: [0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
|
||||
0x40: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x41: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 1, 7]
|
||||
0x42: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x43: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
|
||||
0x44: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
|
||||
0x45: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
|
||||
0x46: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 3, 3, 1, 7]
|
||||
0x47: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 7]
|
||||
0x48: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
|
||||
0x49: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 2, 7]
|
||||
0x4A: [3, 1, 4, 3, 1, 1, 1, 1, 1, 1, 0, 3, 3, 3, 1, 7]
|
||||
0x4B: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x4C: [1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 3, 3, 3]
|
||||
0x4D: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 2, 3, 2, 3]
|
||||
0x4E: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x4F: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x50: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x51: [3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 3, 3, 3, 3]
|
||||
0x52: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x53: [1, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0x54: [0, 1, 3, 3, 3, 3, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0x55: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 1]
|
||||
0x56: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 2, 1]
|
||||
0x57: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x58: [3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 3, 3, 1, 7]
|
||||
0x59: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x5A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x5B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3]
|
||||
0x5C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3]
|
||||
0x5D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x5E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x5F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x60: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x61: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x62: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x63: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 3, 3] # the pit spawns the 0x64
|
||||
0x64: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 3, 3]
|
||||
0x65: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x66: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x67: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x68: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x69: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x6A: [5, 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 3, 1, 7]
|
||||
0x6B: [3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
|
||||
0x6C: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x6D: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x6E: [3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 3, 3, 3, 1, 7]
|
||||
0x6F: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 3]
|
||||
0x70: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x71: [3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 3, 3, 3, 1, 3]
|
||||
0x72: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x73: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x74: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x75: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x76: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x77: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x78: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x79: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1]
|
||||
0x7A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x7B: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x7C: [0, 1, 1, 1, 1, 1, 1, 0, 2, 1, 0, 3, 3, 3, 3, 3]
|
||||
0x7D: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x7E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x7F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x80: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x81: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 2, 3, 2]
|
||||
0x82: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x83: [0, 1, 1, 2, 2, 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0]
|
||||
0x84: [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
|
||||
0x85: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 3, 2, 3]
|
||||
0x86: [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 3, 3, 1, 7]
|
||||
0x87: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x88: [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0] # mothula
|
||||
0x89: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x8A: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x8B: [3, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 3, 3, 3, 2, 3]
|
||||
0x8C: [0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0]
|
||||
0x8D: [0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0x8E: [1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 1, 3, 2, 2, 3]
|
||||
0x8F: [3, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, 3, 3, 3, 1, 2]
|
||||
0x90: [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 3, 3, 2]
|
||||
0x91: [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x92: [0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0]
|
||||
0x93: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x94: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 1, 3, 2, 3]
|
||||
0x95: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x96: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x97: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x98: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x99: [1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, 1, 0, 3, 1, 2]
|
||||
0x9A: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 2, 3, 2, 1, 1]
|
||||
0x9B: [0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 2, 3, 2]
|
||||
0x9C: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 2]
|
||||
0x9D: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 2, 3, 2, 2]
|
||||
0x9E: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0x9F: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xA0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xA1: [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0]
|
||||
0xA2: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0]
|
||||
0xA3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0]
|
||||
0xA4: [0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 3, 0, 1, 3, 1]
|
||||
0xA5: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 3, 3, 3, 1, 3]
|
||||
0xA6: [3, 1, 1, 1, 1, 1, 1, 1, 2, 1, 0, 3, 3, 3, 1, 3]
|
||||
0xA7: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 2, 7]
|
||||
0xA8: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 1]
|
||||
0xA9: [0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 3, 3, 3, 1, 1]
|
||||
0xAA: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 3, 1, 3]
|
||||
0xAB: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0]
|
||||
0xAC: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xAD: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xAE: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xAF: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB2: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 3, 1]
|
||||
0xB3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xB9: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xBA: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xBB: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xBC: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xBD: [0, 0, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
|
||||
0xBE: [0, 0, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
|
||||
0xBF: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC0: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC3: [0, 1, 1, 1, 1, 1, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0]
|
||||
0xC4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1]
|
||||
0xC6: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1]
|
||||
0xC7: [0, 1, 1, 1, 1, 1, 1, 0, 1, 2, 0, 3, 1, 3, 1, 3]
|
||||
0xC8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xC9: [5, 1, 1, 1, 1, 1, 3, 0, 2, 1, 0, 3, 3, 1, 3, 1]
|
||||
0xCA: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xCB: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xCC: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0]
|
||||
0xCD: [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0]
|
||||
0xCE: [0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xCF: [1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 2, 1]
|
||||
0xD0: [0, 0, 0, 1, 1, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0]
|
||||
0xD1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, 2]
|
||||
0xD2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 7]
|
||||
0xD3: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 7]
|
||||
0xD4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xD5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xD6: [0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
0xD7: [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0]
|
||||
0xEF: [0, 1, 1, 2, 2, 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0]
|
||||
0xF0: [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
|
||||
10
source/enemizer/enemy_damage_table.yaml
Normal file
10
source/enemizer/enemy_damage_table.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
0x00: [0x02, 0x01, 0x01]
|
||||
0x01: [0x04, 0x04, 0x04]
|
||||
0x02: [0x00, 0x00, 0x00]
|
||||
0x03: [0x08, 0x04, 0x02]
|
||||
0x04: [0x08, 0x08, 0x08]
|
||||
0x05: [0x10, 0x08, 0x04]
|
||||
0x06: [0x20, 0x10, 0x08]
|
||||
0x07: [0x20, 0x18, 0x10]
|
||||
0x08: [0x18, 0x10, 0x08] # Roller class damage
|
||||
0x09: [0x40, 0x30, 0x18] # Ganon class damage - max 8 hearts
|
||||
@@ -17,9 +17,9 @@ UwGeneralDeny:
|
||||
- [ 0x000e, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Entrance - Freezor"
|
||||
- [ 0x000e, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Top Bari"
|
||||
- [ 0x000e, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Middle Bari"
|
||||
- [ 0x0016, 0, [ "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 1"
|
||||
- [ 0x0016, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 2"
|
||||
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Blue Bari"
|
||||
- [ 0x0016, 0, [ "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit"] ] #"Swamp Palace - Pool - Zol 1"
|
||||
- [ 0x0016, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Zol 2"
|
||||
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Blue Bari"
|
||||
- [ 0x0016, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 3"
|
||||
- [ 0x0017, 5, [ "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower Of Hera - Bumper Room - Fire Bar (Clockwise)"
|
||||
- [ 0x0019, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Dark Maze - Kodongo 1"
|
||||
@@ -52,7 +52,7 @@ UwGeneralDeny:
|
||||
- [ 0x0028, 4, [ "RollerVerticalUp" ] ] #"Swamp Palace - Entrance Ledge - Spike Trap"
|
||||
- [ 0x002a, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]] #"Palace of Darkness - Arena Main - Hardhat Beetle 1"
|
||||
- [ 0x002a, 3, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 2"
|
||||
- [ 0x002a, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ]]
|
||||
- [ 0x002a, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "RollerHorizontalRight", "RollerHorizontalLeft"]]
|
||||
- [ 0x002a, 6, [ "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 5"
|
||||
- [ 0x002b, 5, [ "RollerHorizontalRight" ] ] #"Palace of Darkness - Fairies - Red Bari 2"
|
||||
- [ 0x002e, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 1"
|
||||
@@ -67,6 +67,7 @@ UwGeneralDeny:
|
||||
- [ 0x0034, 4, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Zol"
|
||||
- [ 0x0035, 6, [ "RollerHorizontalRight" ] ] #"Swamp Palace - West Lever - Stalfos 2"
|
||||
- [ 0x0035, 9, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Swamp Palace - West Lever - Blue Bari"
|
||||
- [0x0036, 5, ["AntiFairyCircle", "Bumper"]]
|
||||
- [ 0x0036, 7, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Lobby - Hover 3"
|
||||
- [ 0x0037, 7, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Water 1 - Blue Bari"
|
||||
- [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2"
|
||||
@@ -90,12 +91,12 @@ UwGeneralDeny:
|
||||
- [ 0x0041, 0, [ "RollerHorizontalLeft" ] ] #"Sewers - Dark Cactus - Rat 1"
|
||||
- [ 0x0041, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Sewers - Dark Cactus - Rat 2"
|
||||
- [ 0x0041, 2, [ "RollerVerticalUp" ] ] #"Sewers - Dark Cactus - Rat 3"
|
||||
- [ 0x0042, 0, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 1"
|
||||
- [ 0x0042, 1, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 2"
|
||||
- [ 0x0042, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 3"
|
||||
- [ 0x0042, 3, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 4"
|
||||
- [ 0x0042, 4, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 5"
|
||||
- [ 0x0042, 5, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 6"
|
||||
- [ 0x0042, 0, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 1"
|
||||
- [ 0x0042, 1, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 2"
|
||||
- [ 0x0042, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 3"
|
||||
- [ 0x0042, 3, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 4"
|
||||
- [ 0x0042, 4, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 5"
|
||||
- [ 0x0042, 5, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper", "Chainchomp" ] ] #"Sewers - Dark Rope Corridor - Rope 6"
|
||||
- [ 0x0044, 4, [ "RollerVerticalUp", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Zol"
|
||||
- [ 0x0044, 6, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "BigSpike" ] ] #"Thieves' Town - Joke Room - Red Bari"
|
||||
- [ 0x0044, 8, [ "Statue", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Blue Bari 4"
|
||||
@@ -125,7 +126,7 @@ UwGeneralDeny:
|
||||
- [ 0x0052, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 2"
|
||||
- [ 0x0053, 1, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Beamos 1"
|
||||
- [ 0x0053, 5, [ "RollerVerticalDown" ] ] #"Desert Palace - Popo Genocide - Popo TL"
|
||||
- [ 0x0053, 7, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Popo 5"
|
||||
- [ 0x0053, 7, ["Beamos", "AntiFairyCircle", "Bumper", "RollerVerticalUp", "RollerVerticalDown"]] #"Desert Palace - Bridge - Popo 5"
|
||||
- [ 0x0055, 1, [ "RollerVerticalUp", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Secret Passage Exit - Green Knife Guard 1"
|
||||
- [ 0x0057, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
|
||||
- [ 0x0057, 1, ["Statue"]] # Statue switch issues
|
||||
@@ -139,8 +140,8 @@ UwGeneralDeny:
|
||||
- [ 0x0057, 10, ["Statue"]] # Statue switch issues
|
||||
- [ 0x0057, 11, ["Statue"]] # Statue switch issues
|
||||
- [ 0x0057, 12, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "BigSpike", "SpikeBlock", "Statue"]] #"Skull Woods - Big Key Room - Gibdo 6"
|
||||
- [ 0x0057, 13, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 1"
|
||||
- [ 0x0057, 14, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 2"
|
||||
- [ 0x0057, 13, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue", "BigSpike"]] #"Skull Woods - Big Key Room - Blue Bari 1"
|
||||
- [ 0x0057, 14, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue", "BigSpike"]] #"Skull Woods - Big Key Room - Blue Bari 2"
|
||||
- [ 0x0058, 0, ["Statue"]]
|
||||
- [ 0x0058, 1, ["Statue"]]
|
||||
- [ 0x0058, 2, ["Statue"]]
|
||||
@@ -156,7 +157,7 @@ UwGeneralDeny:
|
||||
- [ 0x005e, 4, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ice Palace - Pit Trap - Fire Bar (Clockwise)"
|
||||
- [ 0x005f, 0, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari University - Blue Bari 1"
|
||||
- [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2"
|
||||
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Hyrule Castle - West - Blue Guard"
|
||||
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Beamos" ] ] #"Hyrule Castle - West - Blue Guard"
|
||||
- [ 0x0062, 0, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Hyrule Castle - East - Blue Guard"
|
||||
- [ 0x0064, 2, [ "Bumper" , "Beamos" ] ] #"Thieves' Town - Attic Hall Left - Keese 2"
|
||||
- [ 0x0064, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
|
||||
@@ -170,7 +171,7 @@ UwGeneralDeny:
|
||||
- [ 0x0067, 2, ["Bumper"]] #"Skull Woods - Firebar Pits - Blue Bari 2"
|
||||
- [ 0x0067, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 1"
|
||||
- [ 0x0067, 4, [ "AntiFairyCircle", "Bumper" ]]
|
||||
- [ 0x0067, 5, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 3"
|
||||
- [ 0x0067, 5, ["RollerVerticalDown", "Beamos"]] #"Skull Woods - Firebar Pits - Hardhat Beetle 3"
|
||||
- [ 0x0067, 6, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 4"
|
||||
- [ 0x0067, 7, [ "Beamos", "AntiFairyCircle", "Bumper", "BunnyBeam" ] ] #"Skull Woods - Firebar Pits - Fire Bar (Clockwise)"
|
||||
- [ 0x006a, 0, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 1"
|
||||
@@ -195,7 +196,7 @@ UwGeneralDeny:
|
||||
- [ 0x007b, 7, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - DMs Room - Hardhat Beetle"
|
||||
- [ 0x007c, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Counterclockwise)"
|
||||
- [ 0x007c, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Spike Trap"
|
||||
- [ 0x007c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Clockwise)"
|
||||
- [ 0x007c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper", "Statue"]] #"Ganon's Tower - Randomizer Room - Fire Bar (Clockwise)"
|
||||
- [ 0x007c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Hardhat Beetle"
|
||||
- [ 0x007d, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 1"
|
||||
- [ 0x007d, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 2"
|
||||
@@ -244,6 +245,7 @@ UwGeneralDeny:
|
||||
- [ 0x0098, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 3"
|
||||
- [ 0x0098, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 4"
|
||||
- [ 0x0098, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 5"
|
||||
- [0x0099, 8, ["RollerHorizontalLeft", "RollerHorizontalRight"]]
|
||||
- [ 0x009b, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 1"
|
||||
- [ 0x009b, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 2"
|
||||
- [ 0x009b, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ]
|
||||
@@ -288,7 +290,8 @@ UwGeneralDeny:
|
||||
- [ 0x00b2, 9, [ "RollerVerticalUp" ] ] #"Misery Mire - Sluggula Cross - Sluggula BL"
|
||||
- [ 0x00b3, 0, [ "RollerVerticalUp", "RollerHorizontalRight", "BigSpike", "SpikeBlock" ] ] #"Misery Mire - Spike Room - Stalfos 1"
|
||||
- [ 0x00b3, 2, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "Bumper" ] ] #"Misery Mire - Spike Room - Beamos"
|
||||
- [ 0x00b3, 3, [ "AntiFairyCircle", "Bumper" ] ] #"Misery Mire - Spike Room - Yomo Medusa"
|
||||
- [ 0x00b3, 3, ["AntiFairyCircle", "Bumper" ]] #"Misery Mire - Spike Room - Yomo Medusa"
|
||||
- [ 0x00b3, 4, ["AntiFairyCircle", "Bumper"]]
|
||||
- [ 0x00b6, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 1"
|
||||
- [ 0x00b6, 8, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 2"
|
||||
- [ 0x00ba, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Antifairy 1"
|
||||
@@ -347,6 +350,7 @@ UwGeneralDeny:
|
||||
- [ 0x00d8, 8, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Kill Room 1 - Red Eyegore"
|
||||
- [ 0x00d9, 1, [ "RollerHorizontalRight" ] ] #"Eastern Palace - Dodgeball - Green Eyegore 1"
|
||||
- [ 0x00db, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
|
||||
- [ 0x00db, 3, [ "Bumper" ] ] # Okay in vanilla
|
||||
- [ 0x00dc, 2, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ]
|
||||
- [ 0x00dc, 9, [ "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Thieves' Town - Grand Room SE - Fire Snake 2"
|
||||
- [ 0x00df, 0, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Paradox Cave - Top - Mini Moldorm 1"
|
||||
@@ -398,10 +402,10 @@ OwGeneralDeny:
|
||||
- [0x40, 13, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
||||
- [0x40, 14, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
||||
- [0x5e, 0, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 1, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 1, ["Gibo", "RollerVerticalUp", "RollerVerticalDown"]] # kiki eating Gibo
|
||||
- [0x5e, 2, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 3, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 4, ["RollerVerticalUp", "Gibo"]] # forbid that one roller for kiki pod, and the kiki eating Gibo
|
||||
- [0x5e, 4, ["RollerVerticalUp", "RollerVerticalDown", "Gibo"]] # forbid that one roller for kiki pod, and the kiki eating Gibo
|
||||
- [0x5e, 5, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 6, ["Gibo"]] # kiki eating Gibo
|
||||
- [0x5e, 7, ["Gibo"]] # kiki eating Gibo
|
||||
@@ -435,94 +439,97 @@ UwEnemyDrop:
|
||||
- [0x00b0, 8, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
|
||||
# the following are not allowed at certain pits (or on conveyors near pits)
|
||||
# because they despawned or clipped away or immediately fell, etc
|
||||
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x003d, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x003d, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x0044, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0044, 8, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0049, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x007b, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x007b, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
- [0x007f, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x007f, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x007f, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x007f, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x007f, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x007f, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x007f, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x007f, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x0095, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
- [0x0095, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x0095, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x0095, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x0095, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x0095, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
|
||||
- [0x00b5, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x00af, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "Hover"]]
|
||||
- [0x00b5, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00b5, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00b5, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00b5, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00b5, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00c6, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00c6, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00c6, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00c6, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00c6, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00c6, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Bumper", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
- [0x00e6, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
|
||||
- [0x00e6, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
|
||||
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
|
||||
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
|
||||
# wizzrobe despawn issues - on pots/blocks - too close to some object
|
||||
@@ -577,7 +584,6 @@ UwEnemyDrop:
|
||||
- [0x009f, 5, ["Wizzrobe", "Stal"]]
|
||||
- [0x00a1, 1, ["Wizzrobe"]]
|
||||
- [0x00aa, 5, ["Wizzrobe"]]
|
||||
- [0x00af, 0, ["Wizzrobe", "Stal"]]
|
||||
- [0x00b0, 1, ["Wizzrobe"]]
|
||||
- [0x00b0, 2, ["Wizzrobe"]]
|
||||
- [0x00b2, 4, ["Wizzrobe"]]
|
||||
|
||||
206
source/enemizer/enemy_weight.yaml
Normal file
206
source/enemizer/enemy_weight.yaml
Normal file
@@ -0,0 +1,206 @@
|
||||
UW: # Total 94431
|
||||
AntiFairy: 40 # 1.82885% raw:1727 15.28319%
|
||||
AntiFairyCircle: 40 # 1.82885% raw:1727 15.28319%
|
||||
ArmosStatue: 186 # 0.53796% raw:508 4.49558%
|
||||
Babasu: 80 # 1.15428% raw:1090 9.64602%
|
||||
BallNChain: 163 # 0.61526% raw:581 5.14159%
|
||||
Beamos: 155 # 0.64703% raw:611 5.40708%
|
||||
BigSpike: 40 # 1.82885% raw:1727 15.28319%
|
||||
Blob: 87 # 1.15428% raw:1090 9.64602%
|
||||
BlueArcher: 325 # 0.30816% raw:291 2.57522%
|
||||
BlueBari: 49 # 2.02688% raw:1914 16.93805%
|
||||
BlueGuard: 44 # 2.28527% raw:2158 19.09735%
|
||||
BlueZazak: 294 # 0.33993% raw:321 2.84071%
|
||||
BlueZirro: 180 # 0.55702% raw:526 4.65487%
|
||||
BluesainBolt: 150 # 0.66821% raw:631 5.58407%
|
||||
BombGuard: 163 # 0.61526% raw:581 5.14159%
|
||||
Bumper: 55 # 1.82885% raw:1727 15.28319%
|
||||
BunnyBeam: 19 # 5.40077% raw:5100 45.13274%
|
||||
Buzzblob: 123 # 0.81223% raw:767 6.78761%
|
||||
CannonTrooper: 163 # 0.61526% raw:581 5.14159%
|
||||
Chainchomp: 238 # 0.42041% raw:397 3.51327%
|
||||
Crab: 204 # 0.48925% raw:462 4.08850%
|
||||
CricketRat: 212 # 0.47230% raw:446 3.94690%
|
||||
Cucco: 120 # 0.54325% raw:513 4.53982%
|
||||
Deadrock: 186 # 0.53796% raw:508 4.49558%
|
||||
Debirando: 154 # 0.65127% raw:615 5.44248%
|
||||
DebirandoPit: 154 # 0.65127% raw:615 5.44248%
|
||||
Faerie: 19
|
||||
FakeMasterSword: 120 # 0.81223% raw:767 6.78761%
|
||||
FireballZora: 165 # 0.60679% raw:573 5.07080%
|
||||
FirebarCCW: 49 # 2.02688% raw:1914 16.93805%
|
||||
FirebarCW: 49 # 2.02688% raw:1914 16.93805%
|
||||
Firesnake: 49 # 2.02688% raw:1914 16.93805%
|
||||
FloatingSkull: 49 # 2.02688% raw:1914 16.93805%
|
||||
FloppingFish: 30 # 5.40077% raw:5100 45.13274%
|
||||
Freezor: 454 # 0.22027% raw:208 1.84071%
|
||||
Geldman: 445 # 0.22450% raw:212 1.87611%
|
||||
Gibdo: 150 # 0.40453% raw:382 3.38053%
|
||||
Gibo: 294 # 0.33993% raw:321 2.84071%
|
||||
GreenBushGuard: 325 # 0.30816% raw:291 2.57522%
|
||||
GreenEyegoreMimic: 175 # 0.57291% raw:541 4.78761%
|
||||
GreenMimic: 175 # 0.57291% raw:541 4.78761%
|
||||
GreenGuard: 55 # 1.80237% raw:1702 15.06195%
|
||||
GreenKnifeGuard: 621 # 0.16096% raw:152 1.34513%
|
||||
GreenZirro: 180 # 0.55702% raw:526 4.65487%
|
||||
HardhatBeetle: 109 # 0.91495% raw:864 7.64602%
|
||||
Hinox: 140 # 0.71269% raw:673 5.95575%
|
||||
Hoarder: 123 # 0.81223% raw:767 6.78761%
|
||||
Hoarder2: 123 # 0.81223% raw:767 6.78761%
|
||||
Hover: 150 # 0.42147% raw:398 3.52212%
|
||||
Keese: 212 # 0.47230% raw:446 3.94690%
|
||||
Kodongo: 463 # 0.21603% raw:204 1.80531%
|
||||
Kyameron: 237 # 0.42147% raw:398 3.52212%
|
||||
Landmine: 19 # 5.40077% raw:5100 45.13274%
|
||||
Leever: 154 # 0.65127% raw:615 5.44248%
|
||||
Lynel: 400 # 0.17897% raw:169 1.49558%
|
||||
MiniHelmasaur: 109 # 0.91495% raw:864 7.64602%
|
||||
MiniMoldorm: 109 # 0.91495% raw:864 7.64602%
|
||||
Moblin: 367 # 0.27216% raw:257 2.27434%
|
||||
Octoballoon: 204 # 0.48925% raw:462 4.08850%
|
||||
Octorok: 165 # 0.60679% raw:573 5.07080%
|
||||
Octorok4Way: 204 # 0.48925% raw:462 4.08850%
|
||||
Pengator: 300 # 0.22027% raw:208 1.84071%
|
||||
Pikit: 180 # 0.55702% raw:526 4.65487%
|
||||
Poe: 284 # 0.35264% raw:333 2.94690%
|
||||
Pokey: 238 # 0.42041% raw:397 3.51327%
|
||||
Popo: 155 # 0.64703% raw:611 5.40708%
|
||||
Popo2: 155 # 0.64703% raw:611 5.40708%
|
||||
Raven: 94 # 1.06109% raw:1002 8.86726%
|
||||
RedBari: 49 # 2.02688% raw:1914 16.93805%
|
||||
RedBushGuard: 163 # 0.61526% raw:581 5.14159%
|
||||
RedEyegoreMimic: 175 # 0.57291% raw:541 4.78761%
|
||||
RedMimic: 175 # 0.57291% raw:541 4.78761%
|
||||
RedJavelinGuard: 163 # 0.61526% raw:581 5.14159%
|
||||
RedSpearGuard: 44 # 2.28527% raw:2158 19.09735%
|
||||
RedZazak: 294 # 0.33993% raw:321 2.84071%
|
||||
RollerHorizontalLeft: 238 # 0.42041% raw:397 3.51327%
|
||||
RollerHorizontalRight: 238 # 0.42041% raw:397 3.51327%
|
||||
RollerVerticalDown: 238 # 0.42041% raw:397 3.51327%
|
||||
RollerVerticalUp: 238 # 0.42041% raw:397 3.51327%
|
||||
Ropa: 140 # 0.71269% raw:673 5.95575%
|
||||
Sluggula: 360 # 0.27745% raw:262 2.31858%
|
||||
Snake: 212 # 0.47230% raw:446 3.94690%
|
||||
Snapdragon: 562 # 0.17791% raw:168 1.48673%
|
||||
SparkCCW: 49 # 2.02688% raw:1914 16.93805%
|
||||
SparkCW: 49 # 2.02688% raw:1914 16.93805%
|
||||
SpikeBlock: 55 # 1.82885% raw:1727 15.28319%
|
||||
Stal: 19 # 5.40077% raw:5100 45.13274%
|
||||
Stalfos: 49 # 2.02688% raw:1914 16.93805%
|
||||
StalfosKnight: 87 # 1.15428% raw:1090 9.64602%
|
||||
Statue: 30 # 1.82885% raw:1727 15.28319%
|
||||
Swamola: 402 # 0.24886% raw:235 2.07965%
|
||||
Tektite: 186 # 0.53796% raw:508 4.49558%
|
||||
Terrorpin: 463 # 0.21603% raw:204 1.80531%
|
||||
Thief: 100 # 0.60997% raw:576 5.09735%
|
||||
Toppo: 123 # 0.81223% raw:767 6.78761%
|
||||
UsainBolt: 44 # 2.28527% raw:2158 19.09735%
|
||||
Vulture: 445 # 0.22450% raw:212 1.87611%
|
||||
Wallmaster: 247 # 0.40453% raw:382 3.38053%
|
||||
Wizzrobe: 306 # 0.32722% raw:309 2.73451%
|
||||
# YellowStalfos: 49
|
||||
Zora: 609 # 0.16414% raw:155 1.37168%
|
||||
Zoro: 80 # 1.15428% raw:1090 9.64602%
|
||||
OW: # Total 117724
|
||||
AntiFairy: 60 # 0.97346% raw:1146 10.14159%
|
||||
AntiFairyCircle: 60 # 0.97346% raw:1146 10.14159%
|
||||
ArmosStatue: 144 # 0.69570% raw:819 7.24779%
|
||||
Babasu: 100 # 0.84605% raw:996 8.81416%
|
||||
BallNChain: 121 # 0.82651% raw:973 8.61062%
|
||||
Beamos: 184 # 0.54364% raw:640 5.66372%
|
||||
BigSpike: 70 # 0.97346% raw:1146 10.14159%
|
||||
Blob: 118 # 0.84605% raw:996 8.81416%
|
||||
BlueArcher: 291 # 0.34403% raw:405 3.58407%
|
||||
BlueBari: 47 # 2.11767% raw:2493 22.06195%
|
||||
BlueGuard: 39 # 2.56617% raw:3021 26.73451%
|
||||
BlueZazak: 247 # 0.40519% raw:477 4.22124%
|
||||
BlueZirro: 158 # 0.63369% raw:746 6.60177%
|
||||
BluesainBolt: 111 # 0.90381% raw:1064 9.41593%
|
||||
BombGuard: 121 # 0.82651% raw:973 8.61062%
|
||||
Bumper: 103 # 0.97346% raw:1146 10.14159%
|
||||
BunnyBeam: 19 # 5.26656% raw:6200 54.86726%
|
||||
Buzzblob: 86 # 1.15609% raw:1361 12.04425%
|
||||
CannonTrooper: 121 # 0.82651% raw:973 8.61062%
|
||||
Chainchomp: 226 # 0.44341% raw:522 4.61947%
|
||||
Crab: 163 # 0.61500% raw:724 6.40708%
|
||||
CricketRat: 236 # 0.42387% raw:499 4.41593%
|
||||
Cucco: 140 # 0.60396% raw:711 6.29204%
|
||||
Deadrock: 144 # 0.69570% raw:819 7.24779%
|
||||
Debirando: 164 # 0.60905% raw:717 6.34513%
|
||||
DebirandoPit: 164 # 0.60905% raw:717 6.34513%
|
||||
Faerie: 19
|
||||
FakeMasterSword: 120 # 1.15609% raw:1361 12.04425%
|
||||
FireballZora: 119 # 0.84350% raw:993 8.78761%
|
||||
FirebarCCW: 47 # 2.11767% raw:2493 22.06195%
|
||||
FirebarCW: 47 # 2.11767% raw:2493 22.06195%
|
||||
Firesnake: 47 # 2.11767% raw:2493 22.06195%
|
||||
FloatingSkull: 47 # 2.11767% raw:2493 22.06195%
|
||||
FloppingFish: 30 # 5.26656% raw:6200 54.86726%
|
||||
Freezor: 692 # 0.14441% raw:170 1.50442%
|
||||
Geldman: 229 # 0.43746% raw:515 4.55752%
|
||||
Gibdo: 300 # 0.15545% raw:183 1.61947%
|
||||
Gibo: 247 # 0.40519% raw:477 4.22124%
|
||||
GreenBushGuard: 291 # 0.34403% raw:405 3.58407%
|
||||
GreenEyegoreMimic: 171 # 0.58527% raw:689 6.09735%
|
||||
GreenMimic: 171 # 0.58527% raw:689 6.09735%
|
||||
GreenGuard: 48 # 2.06330% raw:2429 21.49558%
|
||||
GreenKnifeGuard: 589 # 0.16989% raw:200 1.76991%
|
||||
GreenZirro: 158 # 0.63369% raw:746 6.60177%
|
||||
HardhatBeetle: 113 # 0.88682% raw:1044 9.23894%
|
||||
Hinox: 123 # 0.81462% raw:959 8.48673%
|
||||
Hoarder: 86 # 1.15609% raw:1361 12.04425%
|
||||
Hoarder2: 86 # 1.15609% raw:1361 12.04425%
|
||||
Hover: 200 # 0.32449% raw:382 3.38053%
|
||||
Keese: 236 # 0.42387% raw:499 4.41593%
|
||||
Kodongo: 346 # 0.28881% raw:340 3.00885%
|
||||
Kyameron: 308 # 0.32449% raw:382 3.38053%
|
||||
Landmine: 19 # 5.26656% raw:6200 54.86726%
|
||||
Leever: 164 # 0.60905% raw:717 6.34513%
|
||||
Lynel: 325 # 0.30750% raw:362 3.20354%
|
||||
MiniHelmasaur: 113 # 0.88682% raw:1044 9.23894%
|
||||
MiniMoldorm: 113 # 0.88682% raw:1044 9.23894%
|
||||
Moblin: 303 # 0.33043% raw:389 3.44248%
|
||||
Octoballoon: 163 # 0.61500% raw:724 6.40708%
|
||||
Octorok: 119 # 0.84350% raw:993 8.78761%
|
||||
Octorok4Way: 163 # 0.61500% raw:724 6.40708%
|
||||
Pengator: 400 # 0.14441% raw:170 1.50442%
|
||||
Pikit: 158 # 0.63369% raw:746 6.60177%
|
||||
Poe: 202 # 0.49608% raw:584 5.16814%
|
||||
Pokey: 226 # 0.44341% raw:522 4.61947%
|
||||
Popo: 184 # 0.54364% raw:640 5.66372%
|
||||
Popo2: 184 # 0.54364% raw:640 5.66372%
|
||||
Raven: 65 # 1.53325% raw:1805 15.97345%
|
||||
RedBari: 47 # 2.11767% raw:2493 22.06195%
|
||||
RedBushGuard: 121 # 0.82651% raw:973 8.61062%
|
||||
RedEyegoreMimic: 171 # 0.58527% raw:689 6.09735%
|
||||
RedMimic: 171 # 0.58527% raw:689 6.09735%
|
||||
RedJavelinGuard: 121 # 0.82651% raw:973 8.61062%
|
||||
RedSpearGuard: 39 # 2.56617% raw:3021 26.73451%
|
||||
RedZazak: 247 # 0.40519% raw:477 4.22124%
|
||||
RollerHorizontalLeft: 226 # 0.44341% raw:522 4.61947%
|
||||
RollerHorizontalRight: 226 # 0.44341% raw:522 4.61947%
|
||||
RollerVerticalDown: 226 # 0.44341% raw:522 4.61947%
|
||||
RollerVerticalUp: 226 # 0.44341% raw:522 4.61947%
|
||||
Ropa: 123 # 0.81462% raw:959 8.48673%
|
||||
Sluggula: 443 # 0.22595% raw:266 2.35398%
|
||||
Snake: 236 # 0.42387% raw:499 4.41593%
|
||||
Snapdragon: 526 # 0.19028% raw:224 1.98230%
|
||||
SparkCCW: 47 # 2.11767% raw:2493 22.06195%
|
||||
SparkCW: 47 # 2.11767% raw:2493 22.06195%
|
||||
SpikeBlock: 103 # 0.97346% raw:1146 10.14159%
|
||||
Stal: 19 # 5.26656% raw:6200 54.86726%
|
||||
Stalfos: 47 # 2.11767% raw:2493 22.06195%
|
||||
StalfosKnight: 118 # 0.84605% raw:996 8.81416%
|
||||
Statue: 60 # 0.97346% raw:1146 10.14159%
|
||||
Swamola: 265 # 0.37715% raw:444 3.92920%
|
||||
Tektite: 144 # 0.69570% raw:819 7.24779%
|
||||
Terrorpin: 346 # 0.28881% raw:340 3.00885%
|
||||
Thief: 100 # 0.39244% raw:462 4.08850%
|
||||
Toppo: 86 # 1.15609% raw:1361 12.04425%
|
||||
UsainBolt: 39 # 2.56617% raw:3021 26.73451%
|
||||
Vulture: 229 # 0.43746% raw:515 4.55752%
|
||||
Wallmaster: 643 # 0.15545% raw:183 1.61947%
|
||||
Wizzrobe: 345 # 0.28966% raw:341 3.01770%
|
||||
# YellowStalfos: 47
|
||||
Zora: 558 # 0.17923% raw:211 1.86726%
|
||||
Zoro: 100 # 0.84605% raw:996 8.81416%
|
||||
168
source/enemizer/sheet_weight.yaml
Normal file
168
source/enemizer/sheet_weight.yaml
Normal file
@@ -0,0 +1,168 @@
|
||||
SheetChoices:
|
||||
# Complex
|
||||
- slots: [0, 1]
|
||||
assignments:
|
||||
0: 0x46
|
||||
1: 0xd
|
||||
weight: .5 # BluesainBolt(1/2) - 2 types
|
||||
- slots: [0, 1]
|
||||
assignments:
|
||||
0: 0x46
|
||||
1: 0x49
|
||||
weight: 5.5 # CannonTrooper, BallNChain, RedBushGuard, RedJavelinGuard, BombGuard, BluesainBolt(1/2)
|
||||
- slots: [0, 1]
|
||||
assignments:
|
||||
0: 0x48
|
||||
1: 0x49
|
||||
weight: 2 # GreenBushGuard, BlueArcher
|
||||
- slots: [1, 2]
|
||||
assignments:
|
||||
1: 0x49
|
||||
2: 0x13
|
||||
weight: 1 # GreenKnifeGuard
|
||||
- slots: [0, 2]
|
||||
assignments:
|
||||
0: 0x16
|
||||
2: 0x17
|
||||
weight: 1 # Snapdragon
|
||||
- slots: [2, 3]
|
||||
assignments:
|
||||
2: 0xc
|
||||
3: 0x44
|
||||
weight: 1 # Zora (walking)
|
||||
|
||||
# Slot 0 (21 enemy types require slot 0)
|
||||
- slots: [0]
|
||||
assignments:
|
||||
0: [0xe, 0x15]
|
||||
weight: 1 # Thief
|
||||
- slots: [0]
|
||||
assignments:
|
||||
0: 0x16
|
||||
weight: 2 # Ropa, Hinox
|
||||
- slots: [0]
|
||||
assignments:
|
||||
0: 0x1f
|
||||
weight: 7 # Sparks, Firebars, FloatingSkull, RedBari, BlueBari, Firesnake, Stalfos, ~~YellowStalfos~~
|
||||
- slots: [0]
|
||||
assignments:
|
||||
0: 0x2f
|
||||
weight: 2 # Debirandos, Leever
|
||||
|
||||
# Slot 1 (24 enemy types require slot 1)
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0x1e
|
||||
weight: 3 # MiniMoldorm, MiniHelmasaur, Hardhat
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0x20
|
||||
weight: 3 # StalfosKnight, Blob, Babasus
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0x23
|
||||
weight: 1 # Wallmaster
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0x2c
|
||||
weight: 4 # Beamos, Popos, Mimics (2)
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0x49
|
||||
weight: 2.5 # GreenGuard, RedSpearGuard, BlueGuard, UsainBolt (1/2)
|
||||
- slots: [1]
|
||||
assignments:
|
||||
1: 0xd
|
||||
weight: 1.5 # RedSpearGuard, BlueGuard, UsainBolt (1/2)
|
||||
|
||||
# Slot 2 (29 enemy types require slot 2)
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0xc
|
||||
weight: 3 # Crab, Octoballon, FireballZora(1/2), Octorocks(1/2) (4Way is 0xC only?)
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x12
|
||||
weight: 2 # Vulture, Geldman
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x17
|
||||
weight: 1 # Moblin
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x18
|
||||
weight: 1 # FireballZora(1/2) (note: immersible only), Octoroks(1/2)
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: [0x1c, 0x24]
|
||||
weight: 3 # Keese, CricketRat, Snake
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x22
|
||||
weight: 2 # Kyameron (note: immersible only), Hover
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x23
|
||||
weight: 1 # Gibdo
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x25
|
||||
weight: 1.5 # Sluggula, Wizzrobe (half)
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x26
|
||||
weight: 1 # Pengator
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x27
|
||||
weight: 3 # Rollers4, Chainchomp, Pokey
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x28
|
||||
weight: 3 # Gibo, BlueZazak, RedZazak
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x29
|
||||
weight: .5 # Wizzrobe (half)
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x2a
|
||||
weight: 2 # Kodongo, Terrorpin
|
||||
- slots: [2]
|
||||
assignments:
|
||||
2: 0x2e
|
||||
weight: 2 # GreenEyeGoreMimic, RedEyeGoreMimic (Eyegores only)
|
||||
|
||||
# Slot 3 (21 enemy types require slot 3)
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x10
|
||||
weight: 3 # Deadrock, Tektite, ArmosStatue
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x11
|
||||
weight: 4.5 # FakeMasterSword, Hoarder, Buzzblob, Toppo, Raven(1/2)
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x14
|
||||
weight: 1 # Lynel
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x15
|
||||
weight: 1.5 # Poe, Cucco(1/2)
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x19
|
||||
weight: 1.5 # Swamola, Raven(1/2)
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: 0x1b
|
||||
weight: 3 # GreenZirro, BlueZirro, Pikit
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: [0x50]
|
||||
weight: .5 # Cucco(1/2)
|
||||
- slots: [3]
|
||||
assignments:
|
||||
3: [0x52, 0x53]
|
||||
weight: 5 # SpikeBlock, Bumper, BigSpike, AntiFairy, Statue (AntiFairyCircle?)
|
||||
Reference in New Issue
Block a user