Big enemizer updates

Fix sheets
Health + damage rando
Logical kill rooms
This commit is contained in:
aerinon
2023-03-30 16:12:46 -06:00
parent d85a63ece1
commit a0b781521f
22 changed files with 2224 additions and 947 deletions

View File

@@ -1,8 +1,9 @@
from collections import defaultdict
from Utils import snes_to_pc, int24_as_bytes, int16_as_bytes
from Utils import snes_to_pc, int24_as_bytes, int16_as_bytes, load_yaml
from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites, init_enemy_stats
from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites, init_enemy_stats, EnemySprite
from source.dungeon.EnemyList import sprite_translation
from source.dungeon.RoomHeader import init_room_headers
from source.dungeon.RoomList import Room0127
from source.enemizer.OwEnemyList import init_vanilla_sprites_ow, vanilla_sprites_ow
@@ -14,7 +15,7 @@ def convert_area_id_to_offset(area_id):
return area_id
if 0x40 <= area_id < 0x80:
return area_id + 0x40
if 0x90 <= area_id < 0xCF:
if 0x90 <= area_id <= 0xCF:
return area_id - 0x50
raise Exception(f'{hex(area_id)} is not a valid area id for offset math')
@@ -31,12 +32,24 @@ class DataTables:
# associated data
self.sprite_requirements = None
self.room_requirements = None
self.enemy_stats = None
self.enemy_damage = None
self.bush_sprite_table = {}
def write_to_rom(self, rom, colorize_pots=False):
# enemizer conditions
self.uw_enemy_denials = {}
for denial in load_yaml(['source', 'enemizer', 'uw_enemy_deny.yaml']):
self.uw_enemy_denials[denial[0], denial[1]] = {sprite_translation[x] for x in denial[2]}
# todo: ow_denials
weights = load_yaml(['source', 'enemizer', 'enemy_weight.yaml'])
self.uw_weights = {sprite_translation[k]: v for k, v in weights['UW'].items()}
self.ow_weights = {sprite_translation[k]: v for k, v in weights['OW'].items()}
def write_to_rom(self, rom, colorize_pots=False, increase_bush_sprite_chance=False):
if self.pot_secret_table.size() > 0x11c0:
raise Exception('Pot table is too big for current area')
self.pot_secret_table.write_pot_data_to_rom(rom, colorize_pots)
self.pot_secret_table.write_pot_data_to_rom(rom, colorize_pots, self)
for room_id, header in self.room_headers.items():
data_location = (0x30DA00 + room_id * 14) & 0xFFFF
rom.write_bytes(snes_to_pc(0x04F1E2) + room_id * 2, int16_as_bytes(data_location))
@@ -58,19 +71,73 @@ class DataTables:
if self.uw_enemy_table.size() > 0x2800:
raise Exception('Sprite table is too big for current area')
self.uw_enemy_table.write_sprite_data_to_rom(rom)
for area_id, sheet_number in self.overworld_sprite_sheets.items():
for area_id, sheet in self.overworld_sprite_sheets.items():
if area_id in [0x80, 0x81]:
offset = area_id - 0x80 # 02E575 for special areas?
rom.write_byte(snes_to_pc(0x02E576+offset), sheet_number)
rom.write_byte(snes_to_pc(0x02E576+offset), sheet.id)
else:
offset = convert_area_id_to_offset(area_id)
rom.write_byte(snes_to_pc(0x00FA81+offset), sheet_number)
rom.write_byte(snes_to_pc(0x00FA81+offset), sheet.id)
# _00FA81 is LW normal
# _00FAC1 is LW post-aga
# _00FB01 is DW
for area, sprite_list in vanilla_sprites_ow.items():
for area, sprite_list in self.ow_enemy_table.items():
for sprite in sprite_list:
rom.write_bytes(snes_to_pc(sprite.original_address), sprite.sprite_data_ow())
for sprite, stats in self.enemy_stats.items():
# write health to rom
if stats.health is not None:
if isinstance(stats.health, tuple):
if sprite == EnemySprite.Octorok4Way: # skip this one
continue
if sprite in special_health_table:
a1, a2 = special_health_table[sprite]
rom.write_byte(snes_to_pc(a1), stats.health[0])
rom.write_byte(snes_to_pc(a2), stats.health[1])
else:
rom.write_byte(snes_to_pc(0x0DB173+int(sprite)), stats.health)
# write damage class to rom
if stats.damage is not None:
if isinstance(stats.damage, tuple):
if sprite == EnemySprite.Octorok4Way: # skip this one
continue
if sprite in special_damage_table:
a1, a2 = special_damage_table[sprite]
rom.write_byte(snes_to_pc(a1), stats.dmask | stats.damage[0])
rom.write_byte(snes_to_pc(a2), stats.dmask | stats.damage[1])
else:
rom.write_byte(snes_to_pc(0x0DB266+int(sprite)), stats.dmask | stats.damage)
# write damage table to rom
for idx, damage_list in self.enemy_damage.items():
rom.write_bytes(snes_to_pc(0x06F42D + idx * 3), damage_list)
# write bush spawns to rom:
for area_id, bush_sprite in self.bush_sprite_table.items():
rom.write_byte(snes_to_pc(0x368120 + area_id), bush_sprite.sprite)
if increase_bush_sprite_chance:
rom.write_bytes(snes_to_pc(0x1AFBBB), [
0x01, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x12,
0x0F, 0x01, 0x0F, 0x0F, 0x11, 0x0F, 0x0F, 0x03
])
special_health_table = {
EnemySprite.Octorok: (0x068F76, 0x068F77),
EnemySprite.HardhatBeetle: (0x06911F, 0x069120),
EnemySprite.Tektite: (0x068D97, 0x068D98),
EnemySprite.CricketRat: (0x068876, 0x068877),
EnemySprite.Keese: (0x06888A, 0x06888B),
EnemySprite.Snake: (0x0688A6, 0x0688A7),
EnemySprite.Raven: (0x068965, 0x068966)
}
special_damage_table = {
EnemySprite.Octorok: (0x068F74, 0x068F75),
EnemySprite.Tektite: (0x068D99, 0x068D9A),
EnemySprite.CricketRat: (0x068874, 0x068875),
EnemySprite.Keese: (0x068888, 0x068889),
EnemySprite.Snake: (0x0688A4, 0x0688A5),
EnemySprite.Raven: (0x068963, 0x068964)
}
def init_data_tables(world, player):
@@ -93,4 +160,6 @@ def init_data_tables(world, player):
for area, sprite_list in vanilla_sprites_ow.items():
for sprite in sprite_list:
data_tables.ow_enemy_table[area].append(sprite.copy())
data_tables.enemy_damage = {k: list(v) for k, v in world.damage_table[player].enemy_damage.items()}
# todo: more denials based on enemy drops
return data_tables