Files
alttpr-python/source/enemizer/Bossmizer.py
2022-10-25 09:14:19 -06:00

213 lines
10 KiB
Python

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.insert(0, 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_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
# todo: flag vitreous key fix (prize on the eyes)
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
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) > 16:
del sprite_list[16:]
data_tables.room_headers[room_id].sprite_sheet = required_boss_sheets[sprite_type]
# 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 becomes a random invisible enemy
data_tables.uw_enemy_table.room_map[0x45][0].kind = EnemySprite.PedestalPlaque
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)
}