Overworld enemizer work
This commit is contained in:
@@ -37,8 +37,6 @@ class EnemyStats:
|
||||
# Raven light/dark world
|
||||
|
||||
|
||||
|
||||
|
||||
class EnemySprite(FastEnum):
|
||||
Raven = 0x00
|
||||
Vulture = 0x01
|
||||
@@ -84,7 +82,7 @@ class EnemySprite(FastEnum):
|
||||
TelepathicTile = 0x2d
|
||||
FluteKid = 0x2e
|
||||
RaceGameLady = 0x2f
|
||||
|
||||
RaceGameGuy = 0x30
|
||||
FortuneTeller = 0x31
|
||||
ArgueBros = 0x32
|
||||
RupeePull = 0x33
|
||||
@@ -156,6 +154,7 @@ class EnemySprite(FastEnum):
|
||||
BottleMerchant = 0x75
|
||||
Zelda = 0x76
|
||||
Grandma = 0x78
|
||||
Bee = 0x79
|
||||
Agahnim = 0x7a
|
||||
FloatingSkull = 0x7c
|
||||
BigSpike = 0x7d
|
||||
@@ -203,7 +202,7 @@ class EnemySprite(FastEnum):
|
||||
BlueZirro = 0xa9
|
||||
Pikit = 0xaa
|
||||
CrystalMaiden = 0xab
|
||||
# ... OW
|
||||
Apple = 0xac
|
||||
OldMan = 0xad
|
||||
PipeDown = 0xae
|
||||
PipeUp = 0xaf
|
||||
@@ -242,17 +241,29 @@ class EnemySprite(FastEnum):
|
||||
BunnyBeam = 0xd1
|
||||
FloppingFish = 0xd2
|
||||
Stal = 0xd3 # alive skull rock?
|
||||
Landmine = 0xd4
|
||||
DiggingGameNPC = 0xd5
|
||||
Ganon = 0xd6
|
||||
|
||||
SmallHeart = 0xd8
|
||||
BlueRupee = 0xda
|
||||
RedRupee = 0xdb
|
||||
BombRefill1 = 0xdc
|
||||
BombRefill4 = 0xdd
|
||||
BombRefill8 = 0xde
|
||||
|
||||
LargeMagic = 0xe0
|
||||
Faerie = 0xe3
|
||||
SmallKey = 0xe4
|
||||
Mushroom = 0xe7
|
||||
FakeMasterSword = 0xe8
|
||||
MagicShopAssistant = 0xe9
|
||||
HeartPiece = 0xeb
|
||||
SomariaPlatform = 0xed
|
||||
CastleMantle = 0xee
|
||||
MedallionTablet = 0xf2
|
||||
PositionTarget = 0xf3
|
||||
Boulders = 0xf4
|
||||
|
||||
|
||||
class SpriteType(FastEnum):
|
||||
@@ -488,10 +499,13 @@ class Sprite(object):
|
||||
self.drop_item_kind = drop_item_kind
|
||||
|
||||
self.location = None
|
||||
self.original_address = None
|
||||
|
||||
def copy(self):
|
||||
return Sprite(self.super_tile, self.kind, self.sub_type, self.layer, self.tile_x, self.tile_y, self.region,
|
||||
self.drops_item, self.drop_item_kind)
|
||||
sprite = Sprite(self.super_tile, self.kind, self.sub_type, self.layer, self.tile_x, self.tile_y, self.region,
|
||||
self.drops_item, self.drop_item_kind)
|
||||
sprite.original_address = self.original_address
|
||||
return sprite
|
||||
|
||||
def sprite_data(self):
|
||||
data = [(self.layer << 7) | ((self.sub_type & 0x18) << 2) | self.tile_y,
|
||||
@@ -506,6 +520,9 @@ class Sprite(object):
|
||||
data.append(code)
|
||||
return data
|
||||
|
||||
def sprite_data_ow(self):
|
||||
return [self.tile_y, self.tile_x, self.kind]
|
||||
|
||||
|
||||
# map of super_tile to list of Sprite objects:
|
||||
vanilla_sprites = {}
|
||||
@@ -519,6 +536,8 @@ def create_sprite(super_tile, kind, sub_type, layer, tile_x, tile_y, region=None
|
||||
|
||||
|
||||
def init_vanilla_sprites():
|
||||
if vanilla_sprites:
|
||||
return
|
||||
create_sprite(0x0000, EnemySprite.Ganon, 0x00, 0, 0x17, 0x05, 'Pyramid')
|
||||
create_sprite(0x0002, EnemySprite.CricketRat, 0x00, 1, 0x12, 0x05, 'Sewers Yet More Rats')
|
||||
create_sprite(0x0002, EnemySprite.CricketRat, 0x00, 1, 0x15, 0x06, 'Sewers Yet More Rats')
|
||||
@@ -2066,7 +2085,6 @@ layered_oam_rooms = {
|
||||
class EnemyTable:
|
||||
def __init__(self):
|
||||
self.room_map = defaultdict(list)
|
||||
self.multiworld_count = 0
|
||||
|
||||
def write_sprite_data_to_rom(self, rom):
|
||||
pointer_address = snes_to_pc(0x09D62E)
|
||||
|
||||
@@ -44,6 +44,14 @@ class Room:
|
||||
rom.write_bytes(address + offset, [0xFF, 0xFF])
|
||||
return door_start, offset + 2 # how many bytes were written
|
||||
|
||||
def find_all_pots(self):
|
||||
pots = []
|
||||
pots.extend([x for x in self.layer1 if x.data[2] == 0xFA])
|
||||
pots.extend([x for x in self.layer2 if x.data[2] == 0xFA])
|
||||
pots.extend([x for x in self.layer3 if x.data[2] == 0xFA])
|
||||
return pots
|
||||
|
||||
|
||||
|
||||
Room0006 = Room([0xE1, 0x00],
|
||||
[RoomObject(0x1FA15C, [0x1B, 0xA3, 0xC8]),
|
||||
@@ -405,6 +413,93 @@ Room00C8 = Room([0xE1, 0x00],
|
||||
|
||||
Room00DE = Room([0xE4, 0x00], [], [RoomObject(0x1FCAE5, [0xAD, 0x21, 0xF9])], [])
|
||||
|
||||
Room010C = Room([0xE0, 0x08],
|
||||
[RoomObject(0x03F25D, [0xFC, 0x62, 0x00]),
|
||||
RoomObject(0x03F260, [0x19, 0x33, 0x61]),
|
||||
RoomObject(0x03F263, [0xFC, 0x66, 0x81]),
|
||||
RoomObject(0x03F266, [0x29, 0x22, 0x01]),
|
||||
RoomObject(0x03F269, [0xFD, 0x62, 0x02]),
|
||||
RoomObject(0x03F26C, [0x59, 0x33, 0x62]),
|
||||
RoomObject(0x03F26F, [0xFD, 0x66, 0x83]),
|
||||
RoomObject(0x03F272, [0xFC, 0x89, 0x00]),
|
||||
RoomObject(0x03F275, [0x22, 0xA1, 0x61]),
|
||||
RoomObject(0x03F278, [0xFC, 0x8E, 0x81]),
|
||||
RoomObject(0x03F27B, [0x90, 0xCA, 0x0E]),
|
||||
RoomObject(0x03F27E, [0xD0, 0xE6, 0x10]),
|
||||
RoomObject(0x03F281, [0xFE, 0x41, 0x00]),
|
||||
RoomObject(0x03F284, [0x93, 0x23, 0x61]),
|
||||
RoomObject(0x03F287, [0x92, 0x98, 0x61]),
|
||||
RoomObject(0x03F28A, [0xFF, 0x81, 0x02]),
|
||||
RoomObject(0x03F28D, [0xE3, 0x23, 0x62]),
|
||||
RoomObject(0x03F290, [0xE2, 0x98, 0x62]),
|
||||
RoomObject(0x03F293, [0xFE, 0x71, 0xC8]),
|
||||
RoomObject(0x03F296, [0xAD, 0x1C, 0x03]),
|
||||
RoomObject(0x03F299, [0xFF, 0x51, 0xCA]),
|
||||
RoomObject(0x03F29C, [0x9D, 0x2D, 0x63]),
|
||||
RoomObject(0x03F29F, [0xFE, 0x75, 0x89]),
|
||||
RoomObject(0x03F2A2, [0xAD, 0x58, 0x04]),
|
||||
RoomObject(0x03F2A5, [0xD5, 0x2D, 0x64]),
|
||||
RoomObject(0x03F2A8, [0xFF, 0x55, 0x8B]),
|
||||
RoomObject(0x03F2AB, [0xFE, 0x78, 0x08]),
|
||||
RoomObject(0x03F2AE, [0xAD, 0x80, 0x03]),
|
||||
RoomObject(0x03F2B1, [0xFF, 0x58, 0x0A]),
|
||||
RoomObject(0x03F2B4, [0x9C, 0x91, 0x63]),
|
||||
RoomObject(0x03F2B7, [0xFE, 0x7A, 0x09]),
|
||||
RoomObject(0x03F2BA, [0xAD, 0xA0, 0x04]),
|
||||
RoomObject(0x03F2BD, [0xFF, 0x5A, 0x0B]),
|
||||
RoomObject(0x03F2C0, [0xD4, 0x91, 0x64]),
|
||||
RoomObject(0x03F2C3, [0x2C, 0x2E, 0xDC]),
|
||||
RoomObject(0x03F2C6, [0x3D, 0x3E, 0xF9]),
|
||||
RoomObject(0x03F2C9, [0x32, 0xA9, 0xF9]),
|
||||
RoomObject(0x03F2CC, [0x3A, 0xA9, 0xF9]),
|
||||
RoomObject(0x03F2CF, [0x42, 0xA9, 0xF9]),
|
||||
RoomObject(0x03F2D2, [0x4A, 0xA9, 0xF9]),
|
||||
RoomObject(0x03F2D5, [0x57, 0x9E, 0x69]),
|
||||
RoomObject(0x03F2D8, [0x54, 0xDC, 0x69]),
|
||||
RoomObject(0x03F2DB, [0x38, 0xC8, 0x89]),
|
||||
RoomObject(0x03F2DE, [0x58, 0x9C, 0x89]),
|
||||
RoomObject(0x03F2E1, [0x58, 0xA8, 0x89]),
|
||||
RoomObject(0x03F2E4, [0x58, 0xB4, 0x89]),
|
||||
RoomObject(0x03F2E7, [0x58, 0xC0, 0x89]),
|
||||
RoomObject(0x03F2EA, [0x58, 0xCC, 0x89]),
|
||||
RoomObject(0x03F2ED, [0x58, 0xD8, 0x89]),
|
||||
RoomObject(0x03F2F0, [0x58, 0xE4, 0x89]),
|
||||
RoomObject(0x03F2F3, [0xAA, 0x2E, 0xC8]),
|
||||
RoomObject(0x03F2F6, [0xAA, 0x29, 0x3F]),
|
||||
RoomObject(0x03F2F9, [0xAA, 0x2E, 0x79]),
|
||||
RoomObject(0x03F2FC, [0xAA, 0x59, 0x40]),
|
||||
RoomObject(0x03F2FF, [0xD6, 0x2E, 0x7A]),
|
||||
RoomObject(0x03F302, [0xAA, 0x90, 0xC8]),
|
||||
RoomObject(0x03F305, [0xAA, 0x8D, 0x3F]),
|
||||
RoomObject(0x03F308, [0xA8, 0x93, 0x79]),
|
||||
RoomObject(0x03F30B, [0xAA, 0xA1, 0x40]),
|
||||
RoomObject(0x03F30E, [0xD4, 0x93, 0x7A]),
|
||||
RoomObject(0x03F311, [0xB9, 0x5B, 0xF9]),
|
||||
RoomObject(0x03F314, [0xB9, 0xA3, 0xF9]),
|
||||
RoomObject(0x03F317, [0x9C, 0x68, 0x22]),
|
||||
RoomObject(0x03F31A, [0x9C, 0x6A, 0x69]),
|
||||
RoomObject(0x03F31D, [0x9C, 0x7C, 0x22]),
|
||||
RoomObject(0x03F320, [0xD4, 0x7C, 0x22]),
|
||||
RoomObject(0x03F323, [0x9C, 0xB0, 0x22]),
|
||||
RoomObject(0x03F326, [0xD4, 0xB0, 0x22]),
|
||||
RoomObject(0x03F329, [0xB3, 0x73, 0xFA]),
|
||||
RoomObject(0x03F32C, [0xCD, 0x68, 0xDD]),
|
||||
RoomObject(0x03F32F, [0xB8, 0xC0, 0xDD]),
|
||||
RoomObject(0x03F332, [0x08, 0x00, 0x60]),
|
||||
RoomObject(0x03F335, [0x10, 0x00, 0x60]),
|
||||
RoomObject(0x03F338, [0x1B, 0x10, 0xC0]),
|
||||
RoomObject(0x03F33B, [0x59, 0x10, 0xC0]),
|
||||
RoomObject(0x03F33E, [0x68, 0x23, 0xC0]),
|
||||
RoomObject(0x03F341, [0x68, 0x61, 0xC0]),
|
||||
RoomObject(0x03F344, [0x1B, 0x91, 0x60]),
|
||||
RoomObject(0x03F347, [0x88, 0x10, 0x60]),
|
||||
RoomObject(0x03F34A, [0xF0, 0x10, 0x60]),
|
||||
RoomObject(0x03F34D, [0x90, 0xDF, 0xA1]),
|
||||
RoomObject(0x03F350, [0xD4, 0xF7, 0xA3])], [],
|
||||
[DoorObject(Position.InteriorW, DoorKind.TrapTriggerable),
|
||||
DoorObject(Position.SouthW, DoorKind.CaveEntrance), DoorObject(Position.SouthE, DoorKind.CaveEntrance)]
|
||||
)
|
||||
|
||||
Room0127 = Room([0xE1, 0x00],
|
||||
[RoomObject(0x0AB600, [0xFE, 0x89, 0x00]),
|
||||
RoomObject(0x0AB603, [0xA2, 0xA1, 0x61]),
|
||||
|
||||
@@ -124,6 +124,7 @@ def boss_writes(world, player, rom):
|
||||
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
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import RaceRandom as random
|
||||
from Utils import snes_to_pc
|
||||
|
||||
from source.dungeon.EnemyList import SpriteType
|
||||
from source.enemizer.SpriteSheets import uw_sub_group_choices, setup_required_dungeon_groups
|
||||
from source.dungeon.RoomList import Room010C
|
||||
from source.enemizer.SpriteSheets import sub_group_choices, setup_required_dungeon_groups
|
||||
from source.enemizer.SpriteSheets import randomize_underworld_sprite_sheets, randomize_overworld_sprite_sheets
|
||||
from source.enemizer.TilePattern import tile_patterns
|
||||
|
||||
water_rooms = {
|
||||
0x16, 0x28, 0x34, 0x36, 0x38, 0x46, 0x66
|
||||
@@ -52,7 +56,7 @@ def setup_specific_requirements(data_tables):
|
||||
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 uw_sub_group_choices[i]]
|
||||
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)
|
||||
@@ -76,7 +80,7 @@ def get_possible_sheets(room_id, data_tables, specific, uw_sheets):
|
||||
killable_needed = room_id in shutter_sprites
|
||||
water_needed = room_id in water_rooms
|
||||
|
||||
for sheet in data_tables.sprite_sheets.values():
|
||||
for sheet in uw_sheets:
|
||||
if room_id in sheet.room_set:
|
||||
return [sheet]
|
||||
|
||||
@@ -156,7 +160,18 @@ def get_possible_sheets(room_id, data_tables, specific, uw_sheets):
|
||||
return possible_sheets
|
||||
|
||||
|
||||
def uw_candidate_sprites(data_tables):
|
||||
def get_possible_ow_sheets(area_id, ow_sheets):
|
||||
# requirements = data_tables.sprite_requirements
|
||||
|
||||
for sheet in ow_sheets:
|
||||
if area_id in sheet.room_set:
|
||||
return [sheet]
|
||||
|
||||
# not sure I need to match anything else at this point
|
||||
return ow_sheets
|
||||
|
||||
|
||||
def find_candidate_sprites(data_tables, sheet_range):
|
||||
requirements = data_tables.sprite_requirements
|
||||
uw_sprite_candidates = []
|
||||
uw_sheet_candidates = []
|
||||
@@ -173,7 +188,7 @@ def uw_candidate_sprites(data_tables):
|
||||
candidate_sub_groups[i].update(r.sub_groups[i])
|
||||
uw_sprite_candidates.append(k)
|
||||
|
||||
for num in range(65, 124):
|
||||
for num in sheet_range:
|
||||
sheet = data_tables.sprite_sheets[num]
|
||||
if candidate_groups and sheet not in candidate_groups:
|
||||
continue
|
||||
@@ -196,6 +211,17 @@ def get_possible_enemy_sprites(room_id, sheet, uw_sprites, data_tables):
|
||||
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):
|
||||
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]):
|
||||
@@ -211,13 +237,28 @@ def get_randomize_able_sprites(room_id, data_tables):
|
||||
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
|
||||
|
||||
|
||||
# RandomizeRooms(optionFlags);
|
||||
def randomize_underworld_rooms(data_tables):
|
||||
# RoomCollection.RandomizeRoomSpriteGroups
|
||||
# randomize room sprite sheets
|
||||
|
||||
specific = setup_specific_requirements(data_tables)
|
||||
uw_candidates, uw_sheets = uw_candidate_sprites(data_tables)
|
||||
uw_candidates, uw_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, 0x1c, 0x20, 0x29, 0x30, 0x33,
|
||||
0x4d, 0x5a, 0x7F, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
|
||||
@@ -228,26 +269,93 @@ def randomize_underworld_rooms(data_tables):
|
||||
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
|
||||
if randomizeable_sprites:
|
||||
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, uw_sheets)
|
||||
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)
|
||||
if room_id in water_rooms:
|
||||
water_sprites = [x for x in candidate_sprites if x.water_only]
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
chosen = random.choice(water_sprites)
|
||||
sprite.kind = chosen.sprite
|
||||
else:
|
||||
# todo: stal sprites
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
if sprite.drops_item:
|
||||
key_sprites = [x for x in candidate_sprites if x.good_for_key_drop() and not x.water_only]
|
||||
chosen = random.choice(key_sprites)
|
||||
elif room_id in shutter_sprites and i in shutter_sprites[room_id]:
|
||||
killable_sprite = [x for x in candidate_sprites if x.good_for_shutter() and not x.water_only]
|
||||
chosen = random.choice(killable_sprite)
|
||||
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
|
||||
if room_id in water_rooms:
|
||||
water_sprites = [x for x in candidate_sprites if x.water_only]
|
||||
if len(water_sprites) == 0:
|
||||
randomized = False
|
||||
else:
|
||||
non_water = [x for x in candidate_sprites if not x.water_only]
|
||||
chosen = random.choice(non_water)
|
||||
sprite.kind = chosen.sprite
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
chosen = random.choice(water_sprites)
|
||||
sprite.kind = chosen.sprite
|
||||
else:
|
||||
# todo: stal sprites
|
||||
for i, sprite in randomizeable_sprites.items():
|
||||
if sprite.drops_item:
|
||||
choice_list = [x for x in candidate_sprites if x.good_for_key_drop() and not x.water_only]
|
||||
elif room_id in shutter_sprites and i in shutter_sprites[room_id]:
|
||||
choice_list = [x for x in candidate_sprites if x.good_for_shutter() and not x.water_only]
|
||||
else:
|
||||
choice_list = [x for x in candidate_sprites if not x.water_only]
|
||||
if len(choice_list) == 0:
|
||||
randomized = False
|
||||
break
|
||||
chosen = random.choice(choice_list)
|
||||
sprite.kind = chosen.sprite
|
||||
done = randomized
|
||||
# done with sprites
|
||||
# done with rooms
|
||||
# done with rooms
|
||||
|
||||
|
||||
def randomize_overworld_enemies(data_tables, randomize_bush_sprites):
|
||||
# todo: decision on stump/bird
|
||||
# original kodongo discovery?
|
||||
# rom.write_byte(snes_to_pc(0x09CF4F), 0x10) //move bird from tree stump in lost woods
|
||||
ow_candidates, ow_sheets = find_candidate_sprites(data_tables, range(1, 64))
|
||||
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 randomizeable_sprites:
|
||||
candidate_sheets = get_possible_ow_sheets(area_id, ow_sheets)
|
||||
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():
|
||||
chosen = random.choice(candidate_sprites)
|
||||
sprite.kind = chosen
|
||||
if randomize_bush_sprites:
|
||||
pass
|
||||
# todo: randomize the bush sprite
|
||||
|
||||
|
||||
def randomize_enemies(world, player):
|
||||
if world.enemy_shuffle[player] != 'none':
|
||||
data_tables = world.data_tables[player]
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
|
||||
randomize_underworld_rooms(data_tables)
|
||||
randomize_overworld_sprite_sheets(data_tables.sprite_sheets)
|
||||
randomize_overworld_enemies(data_tables, world.enemy_shuffle[player] == 'random')
|
||||
# todo: health shuffle
|
||||
# todo: damage shuffle
|
||||
|
||||
|
||||
def write_enemy_shuffle_settings(world, player, rom):
|
||||
if world.enemy_shuffle[player] != 'none':
|
||||
# killable thief
|
||||
rom.write_byte(snes_to_pc(0x368108), 0xc4)
|
||||
rom.write_byte(snes_to_pc(0x0DB237), 4) # health value: # todo: thief health value
|
||||
|
||||
# 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
|
||||
if world.enemy_shuffle[player] == 'random':
|
||||
rom.write_byte(snes_to_pc(0x368100), 1) # randomize bushes
|
||||
# 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)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
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
|
||||
@@ -8,15 +9,35 @@ import RaceRandom as random
|
||||
|
||||
if __name__ == '__main__':
|
||||
random.seed(42)
|
||||
world = SimpleNamespace(pottery={1: 'none'})
|
||||
data_tables = init_data_tables(world, 1)
|
||||
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
|
||||
randomize_underworld_rooms(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 sprite.sub_type == SpriteType.Overlord:
|
||||
print(f' Overlord #{i+1} {hex(sprite.kind)}:')
|
||||
else:
|
||||
print(f' Enemy #{i+1} {enemy_names[sprite.kind]}:')
|
||||
stats = defaultdict(Counter)
|
||||
column_headers = {}
|
||||
|
||||
for trial in range(0, 100):
|
||||
world = SimpleNamespace(pottery={1: 'none'})
|
||||
data_tables = init_data_tables(world, 1)
|
||||
|
||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
|
||||
randomize_underworld_rooms(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 sprite.sub_type == SpriteType.Overlord:
|
||||
result = f'O{hex(sprite.kind)}'
|
||||
else:
|
||||
result = enemy_names[sprite.kind]
|
||||
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')
|
||||
|
||||
|
||||
1026
source/enemizer/OwEnemyList.py
Normal file
1026
source/enemizer/OwEnemyList.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -554,7 +554,7 @@ def setup_required_dungeon_groups(sheets):
|
||||
|
||||
# non-optional
|
||||
([None, None, None, 82], [0x2, 0x58, 0x64, 0x8c, 0x10b]), # pull switches
|
||||
([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x56, 0x5e, 0x7c, 0x95, 0xc3]), # collasping bridges
|
||||
([None, None, None, 82], [0x1a, 0x3d, 0x44, 0x56, 0x5e, 0x7c, 0x95, 0xc3]), # collapsing bridges
|
||||
([None, None, None, 83], [0x4, 0x3f, 0xce]), # pull tongue
|
||||
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
|
||||
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
|
||||
@@ -593,7 +593,7 @@ def setup_required_dungeon_groups(sheets):
|
||||
# roomCollection.LoadRooms()
|
||||
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
|
||||
# more stuff
|
||||
uw_sub_group_choices = {
|
||||
sub_group_choices = {
|
||||
0: [22, 31, 47, 14], # 70, 72 for guards
|
||||
1: [44, 30, 32], # 73, 13
|
||||
2: [12, 18, 23, 24, 28, 46, 34, 35, 39, 40, 38, 41, 36, 37, 42],
|
||||
@@ -611,7 +611,41 @@ def randomize_underworld_sprite_sheets(sheets):
|
||||
sheet.sub_groups[1] = random.choice([13, 73])
|
||||
for idx in range(0, 4):
|
||||
if not sheet.locked[idx]:
|
||||
sheet.sub_groups[idx] = random.choice(uw_sub_group_choices[idx])
|
||||
sheet.sub_groups[idx] = random.choice(sub_group_choices[idx])
|
||||
# lock the group?
|
||||
|
||||
|
||||
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, 63], {0x1B, 0xAB}) # Hyrule Castle (pre/post-Aga)
|
||||
sheets[6].add_sprite_to_sheet([None, None, None, None], {0x22, 0x28, 0xB2, 0xB8}) # Smithy/Race (pre/post-Aga)
|
||||
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, None], {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
|
||||
|
||||
|
||||
def randomize_overworld_sprite_sheets(sheets):
|
||||
setup_required_overworld_groups(sheets)
|
||||
|
||||
for num in range(1, 64): # sheets 0x1 to 0x3F inclusive
|
||||
sheet = sheets[num]
|
||||
for idx in range(0, 4):
|
||||
if not sheet.locked[idx]:
|
||||
sheet.sub_groups[idx] = random.choice(sub_group_choices[idx])
|
||||
# lock the group?
|
||||
|
||||
|
||||
@@ -627,4 +661,3 @@ def randomize_underworld_sprite_sheets(sheets):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
93
source/enemizer/TilePattern.py
Normal file
93
source/enemizer/TilePattern.py
Normal file
@@ -0,0 +1,93 @@
|
||||
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)])
|
||||
]
|
||||
@@ -1,19 +1,33 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from Utils import snes_to_pc, int24_as_bytes, int16_as_bytes
|
||||
|
||||
from source.dungeon.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites, init_enemy_stats
|
||||
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
|
||||
from source.enemizer.SpriteSheets import init_sprite_sheets, init_sprite_requirements
|
||||
|
||||
|
||||
def convert_area_id_to_offset(area_id):
|
||||
if area_id < 0x40:
|
||||
return area_id
|
||||
if 0x40 <= area_id < 0x80:
|
||||
return area_id + 0x40
|
||||
if 0x90 <= area_id < 0xCF:
|
||||
return area_id - 0x50
|
||||
raise Exception(f'{hex(area_id)} is not a valid area id for offset math')
|
||||
|
||||
|
||||
class DataTables:
|
||||
def __init__(self):
|
||||
self.room_headers = None
|
||||
self.room_list = None
|
||||
self.sprite_sheets = None
|
||||
self.uw_enemy_table = None
|
||||
self.ow_enemy_table = None # todo : data migration
|
||||
self.ow_enemy_table = None
|
||||
self.pot_secret_table = None
|
||||
self.overworld_sprite_sheets = None
|
||||
|
||||
# associated data
|
||||
self.sprite_requirements = None
|
||||
@@ -33,7 +47,6 @@ class DataTables:
|
||||
door_start, bytes_written = room.write_to_rom(snes_to_pc(room_start_address), rom)
|
||||
rom.write_bytes(snes_to_pc(0x1F83C0 + room_id * 3), int24_as_bytes(room_start_address + door_start))
|
||||
room_start_address += bytes_written
|
||||
# todo: room data doors pointers at 1F83C0
|
||||
if room_start_address > 0x380000:
|
||||
raise Exception('Room list exceeded bank size')
|
||||
# size notes: bank 03 uses 140E bytes
|
||||
@@ -45,7 +58,19 @@ 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)
|
||||
# todo: write ow enemy table
|
||||
for area_id, sheet_number 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)
|
||||
else:
|
||||
offset = convert_area_id_to_offset(area_id)
|
||||
rom.write_byte(snes_to_pc(0x00FA81+offset), sheet_number)
|
||||
# _00FA81 is LW normal
|
||||
# _00FAC1 is LW post-aga
|
||||
# _00FB01 is DW
|
||||
for area, sprite_list in vanilla_sprites_ow.items():
|
||||
for sprite in sprite_list:
|
||||
rom.write_bytes(snes_to_pc(sprite.original_address), sprite.sprite_data_ow())
|
||||
|
||||
|
||||
def init_data_tables(world, player):
|
||||
@@ -62,4 +87,10 @@ def init_data_tables(world, player):
|
||||
for room, sprite_list in vanilla_sprites.items():
|
||||
for sprite in sprite_list:
|
||||
uw_table.room_map[room].append(sprite.copy())
|
||||
data_tables.overworld_sprite_sheets = {}
|
||||
data_tables.ow_enemy_table = defaultdict(list)
|
||||
init_vanilla_sprites_ow()
|
||||
for area, sprite_list in vanilla_sprites_ow.items():
|
||||
for sprite in sprite_list:
|
||||
data_tables.ow_enemy_table[area].append(sprite.copy())
|
||||
return data_tables
|
||||
|
||||
Reference in New Issue
Block a user