Overworld enemizer work
This commit is contained in:
@@ -1040,7 +1040,7 @@ class PotSecretTable(object):
|
|||||||
self.room_map = defaultdict(list)
|
self.room_map = defaultdict(list)
|
||||||
self.multiworld_count = 0
|
self.multiworld_count = 0
|
||||||
|
|
||||||
def write_pot_data_to_rom(self, rom, colorize):
|
def write_pot_data_to_rom(self, rom, colorize, data_tables):
|
||||||
pointer_address = snes_to_pc(0x09D87E) # pots currently in bank 9
|
pointer_address = snes_to_pc(0x09D87E) # pots currently in bank 9
|
||||||
data_bank_address = snes_to_pc(0x09DACE)
|
data_bank_address = snes_to_pc(0x09DACE)
|
||||||
# pointer_offset = 0x128 * 2
|
# pointer_offset = 0x128 * 2
|
||||||
@@ -1057,7 +1057,11 @@ class PotSecretTable(object):
|
|||||||
rom.write_bytes(data_pointer + list_idx * 3, pot.pot_data())
|
rom.write_bytes(data_pointer + list_idx * 3, pot.pot_data())
|
||||||
if pot.location is not None and not pot.location.forced_item:
|
if pot.location is not None and not pot.location.forced_item:
|
||||||
collection_rate_mask |= 1 << (15 - list_idx)
|
collection_rate_mask |= 1 << (15 - list_idx)
|
||||||
if colorize and pot.obj_ref:
|
if colorize:
|
||||||
|
if room in data_tables.room_list:
|
||||||
|
room_object = data_tables.room_list[room]
|
||||||
|
room_object.find_all_pots()[list_idx].change_type(Shuffled_Pot)
|
||||||
|
elif pot.obj_ref:
|
||||||
pot.obj_ref.change_type(Shuffled_Pot)
|
pot.obj_ref.change_type(Shuffled_Pot)
|
||||||
pot.obj_ref.write_to_rom(rom)
|
pot.obj_ref.write_to_rom(rom)
|
||||||
list_idx += 1
|
list_idx += 1
|
||||||
|
|||||||
9
Rom.py
9
Rom.py
@@ -35,6 +35,7 @@ from source.classes.SFX import randomize_sfx
|
|||||||
from source.item.FillUtil import valid_pot_items
|
from source.item.FillUtil import valid_pot_items
|
||||||
from source.dungeon.EnemyList import EnemySprite
|
from source.dungeon.EnemyList import EnemySprite
|
||||||
from source.enemizer.Bossmizer import boss_writes
|
from source.enemizer.Bossmizer import boss_writes
|
||||||
|
from source.enemizer.Enemizer import write_enemy_shuffle_settings
|
||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
@@ -1511,12 +1512,15 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
|
|
||||||
if world.boss_shuffle[player] != 'none':
|
if world.boss_shuffle[player] != 'none':
|
||||||
boss_writes(world, player, rom)
|
boss_writes(world, player, rom)
|
||||||
|
write_enemy_shuffle_settings(world, player, rom)
|
||||||
|
|
||||||
# todo: combine this with data_tables for in place edits
|
|
||||||
if (world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none'
|
if (world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none'
|
||||||
or world.pottery[player] != 'none'):
|
or world.pottery[player] != 'none'):
|
||||||
for room in world.rooms:
|
for room in world.rooms:
|
||||||
if room.player == player and room.modified:
|
if room.player == player and room.modified:
|
||||||
|
if room.index in world.data_tables[player].room_list:
|
||||||
|
world.data_tables[player].room_list[room.index].doors = room.doorList
|
||||||
|
else:
|
||||||
rom.write_bytes(room.address(), room.rom_data())
|
rom.write_bytes(room.address(), room.rom_data())
|
||||||
|
|
||||||
if world.data_tables[player]:
|
if world.data_tables[player]:
|
||||||
@@ -1536,8 +1540,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
# 21 bytes
|
# 21 bytes
|
||||||
from Main import __version__
|
from Main import __version__
|
||||||
seedstring = f'{world.seed:09}' if isinstance(world.seed, int) else world.seed
|
seedstring = f'{world.seed:09}' if isinstance(world.seed, int) else world.seed
|
||||||
# todo: change to DR when Enemizer is okay with DR
|
rom.name = bytearray(f'DR{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{seedstring}\0', 'utf8')[:21]
|
||||||
rom.name = bytearray(f'ER{__version__.split("-")[0].replace(".","")[0:3]}_{team+1}_{player}_{seedstring}\0', 'utf8')[:21]
|
|
||||||
rom.name.extend([0] * (21 - len(rom.name)))
|
rom.name.extend([0] * (21 - len(rom.name)))
|
||||||
rom.write_bytes(0x7FC0, rom.name)
|
rom.write_bytes(0x7FC0, rom.name)
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ class EnemyStats:
|
|||||||
# Raven light/dark world
|
# Raven light/dark world
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EnemySprite(FastEnum):
|
class EnemySprite(FastEnum):
|
||||||
Raven = 0x00
|
Raven = 0x00
|
||||||
Vulture = 0x01
|
Vulture = 0x01
|
||||||
@@ -84,7 +82,7 @@ class EnemySprite(FastEnum):
|
|||||||
TelepathicTile = 0x2d
|
TelepathicTile = 0x2d
|
||||||
FluteKid = 0x2e
|
FluteKid = 0x2e
|
||||||
RaceGameLady = 0x2f
|
RaceGameLady = 0x2f
|
||||||
|
RaceGameGuy = 0x30
|
||||||
FortuneTeller = 0x31
|
FortuneTeller = 0x31
|
||||||
ArgueBros = 0x32
|
ArgueBros = 0x32
|
||||||
RupeePull = 0x33
|
RupeePull = 0x33
|
||||||
@@ -156,6 +154,7 @@ class EnemySprite(FastEnum):
|
|||||||
BottleMerchant = 0x75
|
BottleMerchant = 0x75
|
||||||
Zelda = 0x76
|
Zelda = 0x76
|
||||||
Grandma = 0x78
|
Grandma = 0x78
|
||||||
|
Bee = 0x79
|
||||||
Agahnim = 0x7a
|
Agahnim = 0x7a
|
||||||
FloatingSkull = 0x7c
|
FloatingSkull = 0x7c
|
||||||
BigSpike = 0x7d
|
BigSpike = 0x7d
|
||||||
@@ -203,7 +202,7 @@ class EnemySprite(FastEnum):
|
|||||||
BlueZirro = 0xa9
|
BlueZirro = 0xa9
|
||||||
Pikit = 0xaa
|
Pikit = 0xaa
|
||||||
CrystalMaiden = 0xab
|
CrystalMaiden = 0xab
|
||||||
# ... OW
|
Apple = 0xac
|
||||||
OldMan = 0xad
|
OldMan = 0xad
|
||||||
PipeDown = 0xae
|
PipeDown = 0xae
|
||||||
PipeUp = 0xaf
|
PipeUp = 0xaf
|
||||||
@@ -242,17 +241,29 @@ class EnemySprite(FastEnum):
|
|||||||
BunnyBeam = 0xd1
|
BunnyBeam = 0xd1
|
||||||
FloppingFish = 0xd2
|
FloppingFish = 0xd2
|
||||||
Stal = 0xd3 # alive skull rock?
|
Stal = 0xd3 # alive skull rock?
|
||||||
|
Landmine = 0xd4
|
||||||
DiggingGameNPC = 0xd5
|
DiggingGameNPC = 0xd5
|
||||||
Ganon = 0xd6
|
Ganon = 0xd6
|
||||||
|
|
||||||
|
SmallHeart = 0xd8
|
||||||
|
BlueRupee = 0xda
|
||||||
|
RedRupee = 0xdb
|
||||||
|
BombRefill1 = 0xdc
|
||||||
|
BombRefill4 = 0xdd
|
||||||
|
BombRefill8 = 0xde
|
||||||
|
|
||||||
|
LargeMagic = 0xe0
|
||||||
Faerie = 0xe3
|
Faerie = 0xe3
|
||||||
SmallKey = 0xe4
|
SmallKey = 0xe4
|
||||||
|
Mushroom = 0xe7
|
||||||
FakeMasterSword = 0xe8
|
FakeMasterSword = 0xe8
|
||||||
MagicShopAssistant = 0xe9
|
MagicShopAssistant = 0xe9
|
||||||
HeartPiece = 0xeb
|
HeartPiece = 0xeb
|
||||||
SomariaPlatform = 0xed
|
SomariaPlatform = 0xed
|
||||||
CastleMantle = 0xee
|
CastleMantle = 0xee
|
||||||
MedallionTablet = 0xf2
|
MedallionTablet = 0xf2
|
||||||
|
PositionTarget = 0xf3
|
||||||
|
Boulders = 0xf4
|
||||||
|
|
||||||
|
|
||||||
class SpriteType(FastEnum):
|
class SpriteType(FastEnum):
|
||||||
@@ -488,10 +499,13 @@ class Sprite(object):
|
|||||||
self.drop_item_kind = drop_item_kind
|
self.drop_item_kind = drop_item_kind
|
||||||
|
|
||||||
self.location = None
|
self.location = None
|
||||||
|
self.original_address = None
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Sprite(self.super_tile, self.kind, self.sub_type, self.layer, self.tile_x, self.tile_y, self.region,
|
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)
|
self.drops_item, self.drop_item_kind)
|
||||||
|
sprite.original_address = self.original_address
|
||||||
|
return sprite
|
||||||
|
|
||||||
def sprite_data(self):
|
def sprite_data(self):
|
||||||
data = [(self.layer << 7) | ((self.sub_type & 0x18) << 2) | self.tile_y,
|
data = [(self.layer << 7) | ((self.sub_type & 0x18) << 2) | self.tile_y,
|
||||||
@@ -506,6 +520,9 @@ class Sprite(object):
|
|||||||
data.append(code)
|
data.append(code)
|
||||||
return data
|
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:
|
# map of super_tile to list of Sprite objects:
|
||||||
vanilla_sprites = {}
|
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():
|
def init_vanilla_sprites():
|
||||||
|
if vanilla_sprites:
|
||||||
|
return
|
||||||
create_sprite(0x0000, EnemySprite.Ganon, 0x00, 0, 0x17, 0x05, 'Pyramid')
|
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, 0x12, 0x05, 'Sewers Yet More Rats')
|
||||||
create_sprite(0x0002, EnemySprite.CricketRat, 0x00, 1, 0x15, 0x06, '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:
|
class EnemyTable:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.room_map = defaultdict(list)
|
self.room_map = defaultdict(list)
|
||||||
self.multiworld_count = 0
|
|
||||||
|
|
||||||
def write_sprite_data_to_rom(self, rom):
|
def write_sprite_data_to_rom(self, rom):
|
||||||
pointer_address = snes_to_pc(0x09D62E)
|
pointer_address = snes_to_pc(0x09D62E)
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ class Room:
|
|||||||
rom.write_bytes(address + offset, [0xFF, 0xFF])
|
rom.write_bytes(address + offset, [0xFF, 0xFF])
|
||||||
return door_start, offset + 2 # how many bytes were written
|
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],
|
Room0006 = Room([0xE1, 0x00],
|
||||||
[RoomObject(0x1FA15C, [0x1B, 0xA3, 0xC8]),
|
[RoomObject(0x1FA15C, [0x1B, 0xA3, 0xC8]),
|
||||||
@@ -405,6 +413,93 @@ Room00C8 = Room([0xE1, 0x00],
|
|||||||
|
|
||||||
Room00DE = Room([0xE4, 0x00], [], [RoomObject(0x1FCAE5, [0xAD, 0x21, 0xF9])], [])
|
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],
|
Room0127 = Room([0xE1, 0x00],
|
||||||
[RoomObject(0x0AB600, [0xFE, 0x89, 0x00]),
|
[RoomObject(0x0AB600, [0xFE, 0x89, 0x00]),
|
||||||
RoomObject(0x0AB603, [0xA2, 0xA1, 0x61]),
|
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)
|
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(0x368102), eye_number) # enemizer flag
|
||||||
rom.write_byte(snes_to_pc(0x1DDBB3), eye_number) # loop variable
|
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]
|
data_tables = world.data_tables[player]
|
||||||
arrghus_can_swim = True
|
arrghus_can_swim = True
|
||||||
water_tiles_on = True
|
water_tiles_on = True
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import RaceRandom as random
|
import RaceRandom as random
|
||||||
|
from Utils import snes_to_pc
|
||||||
|
|
||||||
from source.dungeon.EnemyList import SpriteType
|
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 = {
|
water_rooms = {
|
||||||
0x16, 0x28, 0x34, 0x36, 0x38, 0x46, 0x66
|
0x16, 0x28, 0x34, 0x36, 0x38, 0x46, 0x66
|
||||||
@@ -52,7 +56,7 @@ def setup_specific_requirements(data_tables):
|
|||||||
if requirement.good_for_uw_water():
|
if requirement.good_for_uw_water():
|
||||||
water_groups.update(requirement.groups)
|
water_groups.update(requirement.groups)
|
||||||
for i in range(0, 4):
|
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)
|
water_sub_groups[i].update(limited)
|
||||||
if requirement.good_for_shutter():
|
if requirement.good_for_shutter():
|
||||||
killable_groups.update(requirement.groups)
|
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
|
killable_needed = room_id in shutter_sprites
|
||||||
water_needed = room_id in water_rooms
|
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:
|
if room_id in sheet.room_set:
|
||||||
return [sheet]
|
return [sheet]
|
||||||
|
|
||||||
@@ -156,7 +160,18 @@ def get_possible_sheets(room_id, data_tables, specific, uw_sheets):
|
|||||||
return possible_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
|
requirements = data_tables.sprite_requirements
|
||||||
uw_sprite_candidates = []
|
uw_sprite_candidates = []
|
||||||
uw_sheet_candidates = []
|
uw_sheet_candidates = []
|
||||||
@@ -173,7 +188,7 @@ def uw_candidate_sprites(data_tables):
|
|||||||
candidate_sub_groups[i].update(r.sub_groups[i])
|
candidate_sub_groups[i].update(r.sub_groups[i])
|
||||||
uw_sprite_candidates.append(k)
|
uw_sprite_candidates.append(k)
|
||||||
|
|
||||||
for num in range(65, 124):
|
for num in sheet_range:
|
||||||
sheet = data_tables.sprite_sheets[num]
|
sheet = data_tables.sprite_sheets[num]
|
||||||
if candidate_groups and sheet not in candidate_groups:
|
if candidate_groups and sheet not in candidate_groups:
|
||||||
continue
|
continue
|
||||||
@@ -196,6 +211,17 @@ def get_possible_enemy_sprites(room_id, sheet, uw_sprites, data_tables):
|
|||||||
return ret
|
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):
|
def get_randomize_able_sprites(room_id, data_tables):
|
||||||
sprite_table = {}
|
sprite_table = {}
|
||||||
for idx, sprite in enumerate(data_tables.uw_enemy_table.room_map[room_id]):
|
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
|
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);
|
# RandomizeRooms(optionFlags);
|
||||||
def randomize_underworld_rooms(data_tables):
|
def randomize_underworld_rooms(data_tables):
|
||||||
# RoomCollection.RandomizeRoomSpriteGroups
|
# RoomCollection.RandomizeRoomSpriteGroups
|
||||||
# randomize room sprite sheets
|
# randomize room sprite sheets
|
||||||
|
|
||||||
specific = setup_specific_requirements(data_tables)
|
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):
|
for room_id in range(0, 0x128):
|
||||||
if room_id in {0, 1, 3, 6, 7, 0xd, 0x14, 0x1c, 0x20, 0x29, 0x30, 0x33,
|
if room_id in {0, 1, 3, 6, 7, 0xd, 0x14, 0x1c, 0x20, 0x29, 0x30, 0x33,
|
||||||
0x4d, 0x5a, 0x7F, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
|
0x4d, 0x5a, 0x7F, 0x90, 0xa4, 0xac, 0xc8, 0xde}:
|
||||||
@@ -228,11 +269,17 @@ def randomize_underworld_rooms(data_tables):
|
|||||||
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
|
randomizeable_sprites = get_randomize_able_sprites(room_id, data_tables)
|
||||||
if randomizeable_sprites:
|
if randomizeable_sprites:
|
||||||
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, uw_sheets)
|
candidate_sheets = get_possible_sheets(room_id, data_tables, specific, uw_sheets)
|
||||||
|
done = False
|
||||||
|
while not done:
|
||||||
chosen_sheet = random.choice(candidate_sheets)
|
chosen_sheet = random.choice(candidate_sheets)
|
||||||
data_tables.room_headers[room_id].sprite_sheet = chosen_sheet.id - 0x40
|
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)
|
candidate_sprites = get_possible_enemy_sprites(room_id, chosen_sheet, uw_candidates, data_tables)
|
||||||
|
randomized = True
|
||||||
if room_id in water_rooms:
|
if room_id in water_rooms:
|
||||||
water_sprites = [x for x in candidate_sprites if x.water_only]
|
water_sprites = [x for x in candidate_sprites if x.water_only]
|
||||||
|
if len(water_sprites) == 0:
|
||||||
|
randomized = False
|
||||||
|
else:
|
||||||
for i, sprite in randomizeable_sprites.items():
|
for i, sprite in randomizeable_sprites.items():
|
||||||
chosen = random.choice(water_sprites)
|
chosen = random.choice(water_sprites)
|
||||||
sprite.kind = chosen.sprite
|
sprite.kind = chosen.sprite
|
||||||
@@ -240,14 +287,75 @@ def randomize_underworld_rooms(data_tables):
|
|||||||
# todo: stal sprites
|
# todo: stal sprites
|
||||||
for i, sprite in randomizeable_sprites.items():
|
for i, sprite in randomizeable_sprites.items():
|
||||||
if sprite.drops_item:
|
if sprite.drops_item:
|
||||||
key_sprites = [x for x in candidate_sprites if x.good_for_key_drop() and not x.water_only]
|
choice_list = [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]:
|
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]
|
choice_list = [x for x in candidate_sprites if x.good_for_shutter() and not x.water_only]
|
||||||
chosen = random.choice(killable_sprite)
|
|
||||||
else:
|
else:
|
||||||
non_water = [x for x in candidate_sprites if not x.water_only]
|
choice_list = [x for x in candidate_sprites if not x.water_only]
|
||||||
chosen = random.choice(non_water)
|
if len(choice_list) == 0:
|
||||||
|
randomized = False
|
||||||
|
break
|
||||||
|
chosen = random.choice(choice_list)
|
||||||
sprite.kind = chosen.sprite
|
sprite.kind = chosen.sprite
|
||||||
|
done = randomized
|
||||||
# done with sprites
|
# 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 types import SimpleNamespace
|
||||||
|
from collections import Counter, defaultdict
|
||||||
|
|
||||||
from source.dungeon.EnemyList import enemy_names, SpriteType
|
from source.dungeon.EnemyList import enemy_names, SpriteType
|
||||||
from source.enemizer.Enemizer import randomize_underworld_rooms
|
from source.enemizer.Enemizer import randomize_underworld_rooms
|
||||||
@@ -8,15 +9,35 @@ import RaceRandom as random
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
random.seed(42)
|
random.seed(42)
|
||||||
|
|
||||||
|
stats = defaultdict(Counter)
|
||||||
|
column_headers = {}
|
||||||
|
|
||||||
|
for trial in range(0, 100):
|
||||||
world = SimpleNamespace(pottery={1: 'none'})
|
world = SimpleNamespace(pottery={1: 'none'})
|
||||||
data_tables = init_data_tables(world, 1)
|
data_tables = init_data_tables(world, 1)
|
||||||
|
|
||||||
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
|
randomize_underworld_sprite_sheets(data_tables.sprite_sheets)
|
||||||
randomize_underworld_rooms(data_tables)
|
randomize_underworld_rooms(data_tables)
|
||||||
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
|
for room_id, enemy_list in data_tables.uw_enemy_table.room_map.items():
|
||||||
print(f'Room {hex(room_id)}:')
|
# print(f'Room {hex(room_id)}:')
|
||||||
for i, sprite in enumerate(enemy_list):
|
for i, sprite in enumerate(enemy_list):
|
||||||
if sprite.sub_type == SpriteType.Overlord:
|
if sprite.sub_type == SpriteType.Overlord:
|
||||||
print(f' Overlord #{i+1} {hex(sprite.kind)}:')
|
result = f'O{hex(sprite.kind)}'
|
||||||
else:
|
else:
|
||||||
print(f' Enemy #{i+1} {enemy_names[sprite.kind]}:')
|
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
|
# non-optional
|
||||||
([None, None, None, 82], [0x2, 0x58, 0x64, 0x8c, 0x10b]), # pull switches
|
([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], [0x4, 0x3f, 0xce]), # pull tongue
|
||||||
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
|
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
|
||||||
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
|
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
|
||||||
@@ -593,7 +593,7 @@ def setup_required_dungeon_groups(sheets):
|
|||||||
# roomCollection.LoadRooms()
|
# roomCollection.LoadRooms()
|
||||||
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
|
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
|
||||||
# more stuff
|
# more stuff
|
||||||
uw_sub_group_choices = {
|
sub_group_choices = {
|
||||||
0: [22, 31, 47, 14], # 70, 72 for guards
|
0: [22, 31, 47, 14], # 70, 72 for guards
|
||||||
1: [44, 30, 32], # 73, 13
|
1: [44, 30, 32], # 73, 13
|
||||||
2: [12, 18, 23, 24, 28, 46, 34, 35, 39, 40, 38, 41, 36, 37, 42],
|
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])
|
sheet.sub_groups[1] = random.choice([13, 73])
|
||||||
for idx in range(0, 4):
|
for idx in range(0, 4):
|
||||||
if not sheet.locked[idx]:
|
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?
|
# 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 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.EnemyList import EnemyTable, init_vanilla_sprites, vanilla_sprites, init_enemy_stats
|
||||||
from source.dungeon.RoomHeader import init_room_headers
|
from source.dungeon.RoomHeader import init_room_headers
|
||||||
from source.dungeon.RoomList import Room0127
|
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
|
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:
|
class DataTables:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.room_headers = None
|
self.room_headers = None
|
||||||
self.room_list = None
|
self.room_list = None
|
||||||
self.sprite_sheets = None
|
self.sprite_sheets = None
|
||||||
self.uw_enemy_table = 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.pot_secret_table = None
|
||||||
|
self.overworld_sprite_sheets = None
|
||||||
|
|
||||||
# associated data
|
# associated data
|
||||||
self.sprite_requirements = None
|
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)
|
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))
|
rom.write_bytes(snes_to_pc(0x1F83C0 + room_id * 3), int24_as_bytes(room_start_address + door_start))
|
||||||
room_start_address += bytes_written
|
room_start_address += bytes_written
|
||||||
# todo: room data doors pointers at 1F83C0
|
|
||||||
if room_start_address > 0x380000:
|
if room_start_address > 0x380000:
|
||||||
raise Exception('Room list exceeded bank size')
|
raise Exception('Room list exceeded bank size')
|
||||||
# size notes: bank 03 uses 140E bytes
|
# size notes: bank 03 uses 140E bytes
|
||||||
@@ -45,7 +58,19 @@ class DataTables:
|
|||||||
if self.uw_enemy_table.size() > 0x2800:
|
if self.uw_enemy_table.size() > 0x2800:
|
||||||
raise Exception('Sprite table is too big for current area')
|
raise Exception('Sprite table is too big for current area')
|
||||||
self.uw_enemy_table.write_sprite_data_to_rom(rom)
|
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):
|
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 room, sprite_list in vanilla_sprites.items():
|
||||||
for sprite in sprite_list:
|
for sprite in sprite_list:
|
||||||
uw_table.room_map[room].append(sprite.copy())
|
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
|
return data_tables
|
||||||
|
|||||||
Reference in New Issue
Block a user