UW Enemizer Work
This commit is contained in:
630
source/enemizer/SpriteSheets.py
Normal file
630
source/enemizer/SpriteSheets.py
Normal file
@@ -0,0 +1,630 @@
|
||||
from collections import defaultdict
|
||||
import RaceRandom as random
|
||||
|
||||
from source.dungeon.EnemyList import EnemySprite, enemy_names
|
||||
from source.dungeon.RoomConstants import *
|
||||
|
||||
|
||||
class SpriteRequirement:
|
||||
def __init__(self, sprite, overlord=0):
|
||||
self.sprite = sprite
|
||||
self.overlord = overlord
|
||||
|
||||
self.boss = False
|
||||
self.static = False # npcs and do not randomize
|
||||
self.killable = True
|
||||
self.can_drop = True
|
||||
self.water_only = False
|
||||
self.dont_use = False
|
||||
self.ow_valid = True
|
||||
self.uw_valid = True
|
||||
self.can_randomize = True
|
||||
|
||||
self.groups = []
|
||||
self.sub_groups = defaultdict(list)
|
||||
|
||||
self.excluded_rooms = set()
|
||||
self.allowed_rooms = set()
|
||||
|
||||
def can_spawn_in_room(self, room_id):
|
||||
return room_id not in self.excluded_rooms and (self.sprite != EnemySprite.Wallmaster or room_id < 0x100)
|
||||
|
||||
def no_drop(self):
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def sub_group(self, key, subs):
|
||||
if isinstance(subs, list):
|
||||
self.sub_groups[key].extend(subs)
|
||||
else:
|
||||
self.sub_groups[key].append(subs)
|
||||
return self
|
||||
|
||||
def group(self, group_id):
|
||||
self.groups.append(group_id)
|
||||
return self
|
||||
|
||||
def exclude(self, exclusions):
|
||||
self.excluded_rooms.update(exclusions)
|
||||
return self
|
||||
|
||||
def allow(self, allowed):
|
||||
self.allowed_rooms.update(allowed)
|
||||
return self
|
||||
|
||||
def affix(self):
|
||||
self.static = True
|
||||
self.killable = False
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def stasis(self):
|
||||
self.can_randomize = False
|
||||
return self
|
||||
|
||||
def exalt(self):
|
||||
self.boss = True
|
||||
self.static = True # not randomized by sprite sheet
|
||||
return self
|
||||
|
||||
def immune(self):
|
||||
self.killable = False
|
||||
self.can_drop = False
|
||||
return self
|
||||
|
||||
def immerse(self):
|
||||
self.water_only = True
|
||||
return self
|
||||
|
||||
def skip(self):
|
||||
self.dont_use = True
|
||||
return self
|
||||
|
||||
def ow_skip(self):
|
||||
self.ow_valid = False
|
||||
return self
|
||||
|
||||
def uw_skip(self):
|
||||
self.uw_valid = False
|
||||
return self
|
||||
|
||||
def good_for_uw_water(self):
|
||||
return self.water_only and not self.static and not self.dont_use and self.uw_valid
|
||||
|
||||
def good_for_shutter(self):
|
||||
return self.killable and not self.static and not self.dont_use and self.uw_valid
|
||||
|
||||
def good_for_key_drop(self):
|
||||
return self.good_for_shutter() and self.can_drop
|
||||
|
||||
def __str__(self):
|
||||
return f'Req for {enemy_names[self.sprite]}'
|
||||
|
||||
|
||||
NoFlyingRooms = {0xd2, 0x10c} # Mire 2, Mimic Cave
|
||||
NoBeamosOrTrapRooms = {0xb, 0x16, 0x19, 0x1e, 0x26, 0x27, 0x36, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4b, 0x4e, 0x55, 0x57,
|
||||
0x5f, 0x65, 0x6a, 0x74, 0x76, 0x7d, 0x7f, 0x83, 0x84, 0x85, 0x8c, 0x8d, 0x92, 0x95, 0x98, 0x9b,
|
||||
0x9c, 0x9d, 0x9e, 0xa0, 0xaa, 0xaf, 0xb3, 0xba, 0xbb, 0xbc, 0xc6, 0xcb, 0xce, 0xd0, 0xd2, 0xd5,
|
||||
0xd8, 0xdc, 0xdf, 0xe4, 0xe7, 0xee, 0xf9, 0xfd, 0x10c}
|
||||
LenientTrapsForTesting = {0x16, 0x26, 0x3f, 0x40, 0x42, 0x46, 0x49, 0x4e, 0x57,
|
||||
0x65, 0x6a, 0x74, 0x76, 0x7d, 0x98,
|
||||
0x9e, 0xaf, 0xba, 0xc6, 0xcb, 0xce, 0xd2, 0xd5,
|
||||
0xd8, 0xdf, 0xe4, 0xe7, 0xee, 0xfd, 0x10c}
|
||||
# this will have to be dynamic if cave rooms are allowed in dungeons
|
||||
WallmasterValidRooms = {
|
||||
HC_NorthCorridor, HC_SwitchRoom, HoulihanRoom, TR_CrystalRollerRoom,
|
||||
PalaceofDarkness0x09, PoD_StalfosTrapRoom, PoD_TurtleRoom, GT_EntranceRoom, Ice_EntranceRoom,
|
||||
GanonEvacuationRoute, HC_BombableStockRoom, Sanctuary, TR_Hokku_BokkuKeyRoom2, TR_BigKeyRoom, TurtleRock0x15,
|
||||
Swamp_SwimmingTreadmill, Hera_MoldormFallRoom, PoD_DarkMaze, PoD_BigChestRoom, PoD_Mimics_MovingWallRoom,
|
||||
GT_IceArmos, GT_FinalHallway, Ice_BombFloor_BariRoom, Ice_Pengator_BigKeyRoom, Tower_Agahnim, HC_KeyRatRoom,
|
||||
HC_SewerTextTriggerRoom, TR_WestExittoBalcony, TR_DoubleHokku_Bokku_BigchestRoom, Swamp_StatueRoom, Hera_BigChest,
|
||||
Swamp_EntranceRoom, Skull_Mothula, PoD_BigHubRoom, PoD_MapChest_FairyRoom, Ice_CompassRoom, Hera_HardhatBeetlesRoom,
|
||||
HC_SewerKeyChestRoom, Desert_Lanmolas, Swamp_PushBlockPuzzle_Pre_BigKeyRoom, Swamp_BigKey_BSRoom,
|
||||
Swamp_BigChestRoom, Swamp_MapChest_WaterFillRoom, Swamp_KeyPotRoom, Skull_GibdoKey_MothulaHoleRoom,
|
||||
PoD_BombableFloorRoom, PoD_SpikeBlock_ConveyorRoom, GT_TorchRoom2, Ice_StalfosKnights_ConveyorHellway,
|
||||
Ice_MapChestRoom, Tower_FinalBridgeRoom, HC_FirstDarkRoom, HC_6RopesRoom, Desert_TorchPuzzle_MovingWallRoom,
|
||||
TT_BigChestRoom, TT_JailCellsRoom, Swamp_CompassChestRoom, Skull_GibdoTorchPuzzleRoom, PoD_EntranceRoom,
|
||||
PoD_Warps_SouthMimicsRoom, GT_Mini_HelmasaurConveyorRoom, GT_MoldormRoom, Ice_Bomb_JumpRoom,
|
||||
IcePalaceCloneRoom_FairyRoom, HC_WestCorridor, HC_ThroneRoom, HC_EastCorridor, Desert_Popos2_BeamosHellwayRoom,
|
||||
Swamp_UpstairsPitsRoom, CastleSecretEntrance_UncleDeathRoom, Skull_KeyPot_TrapRoom, Skull_BigKeyRoom,
|
||||
Skull_BigChestRoom, Skull_FinalSectionEntranceRoom, PoD_HelmasaurKing, GT_SpikePitRoom, GT_Ganon_BallZ,
|
||||
GT_Gauntlet1_2_3, Ice_LonelyFirebar, Ice_HiddenChest_SpikeFloorRoom, HC_WestEntranceRoom, HC_MainEntranceRoom,
|
||||
HC_EastEntranceRoom, Desert_FinalSectionEntranceRoom, TT_WestAtticRoom, TT_EastAtticRoom,
|
||||
Swamp_HiddenChest_HiddenDoorRoom, Skull_CompassChestRoom, Skull_KeyChest_TrapRoom, PoD_RupeeRoom, GT_MimicsRooms,
|
||||
GT_LanmolasRoom, GT_Gauntlet4_5, Ice_PengatorsRoom, HC_SmallCorridortoJailCells, HC_BoomerangChestRoom,
|
||||
HC_MapChestRoom, Desert_BigChestRoom, Desert_MapChestRoom, Desert_BigKeyChestRoom, Swamp_WaterDrainRoom,
|
||||
Hera_EntranceRoom, GanonsTower, GT_EastSideCollapsingBridge_ExplodingWallRoom, GT_Winder_WarpMazeRoom,
|
||||
Ice_HiddenChest_BombableFloorRoom, Ice_BigSpikeTrapsRoom, HC_JailCellRoom, HC_NextToChasmRoom, HC_BasementChasmRoom,
|
||||
Desert_WestEntranceRoom, Desert_MainEntranceRoom, Desert_EastEntranceRoom, Hera_TileRoom, Eastern_FairyRoom,
|
||||
GT_BlockPuzzle_SpikeSkip_MapChestRoom, GT_EastandWestDownstairs_BigChestRoom, GT_Tile_TorchPuzzleRoom,
|
||||
IcePalace0x8E, Mire_Vitreous, Mire_FinalSwitchRoom, Mire_DarkBombWall_SwitchesRoom,
|
||||
Mire_DarkCaneFloorSwitchPuzzleRoom, GT_FinalCollapsingBridgeRoom, GT_Torches1Room, Mire_TorchPuzzle_MovingWallRoom,
|
||||
Mire_EntranceRoom, Eastern_EyegoreKeyRoom, GT_ManySpikes_WarpMazeRoom, GT_InvisibleFloorMazeRoom,
|
||||
GT_CompassChest_InvisibleFloorRoom, Ice_BigChestRoom, IcePalace0x9F, Mire_Pre_VitreousRoom, Mire_FishRoom,
|
||||
Mire_BridgeKeyChestRoom, MiseryMire0xA3, TR_Trinexx, GT_WizzrobesRooms, GT_MoldormFallRoom, Hera_FairyRoom,
|
||||
Eastern_StalfosSpawnRoom, Eastern_BigChestRoom, Eastern_MapChestRoom, TT_MovingSpikes_KeyPotRoom, TT_BlindTheThief,
|
||||
IcePalace0xAE, Ice_IceBridgeRoom, Tower_CircleofPots, Mire_HourglassRoom, Mire_SlugRoom, Mire_SpikeKeyChestRoom,
|
||||
TR_Pre_TrinexxRoom, TR_DarkMaze, TR_ChainChompsRoom, TR_MapChest_KeyChest_RollerRoom, Eastern_BigKeyRoom,
|
||||
Eastern_LobbyCannonballsRoom, Eastern_DarkAntifairy_KeyPotRoom, TT_Hellway, TT_ConveyorToilet, Ice_BlockPuzzleRoom,
|
||||
IcePalaceCloneRoom_SwitchRoom, Tower_DarkBridgeRoom, Mire_CompassChest_TileRoom, Mire_BigHubRoom, Mire_BigChestRoom,
|
||||
TR_FinalCrystalSwitchPuzzleRoom, TR_LaserBridge, TurtleRock0xC6, TR_TorchPuzzle,
|
||||
Eastern_EntranceRoom, UnknownRoom, TT_NorthWestEntranceRoom, TT_NorthEastEntranceRoom, Ice_HoletoKholdstareRoom,
|
||||
Tower_DarkMaze, Mire_ConveyorSlug_BigKeyRoom, Mire_Mire02_WizzrobesRoom, TR_LaserKeyRoom, TR_EntranceRoom,
|
||||
Eastern_PreArmosKnightsRoom, Eastern_CanonballRoom, EasternPalace, TT_Main_SouthWestEntranceRoom,
|
||||
TT_SouthEastEntranceRoom, Tower_EntranceRoom
|
||||
}
|
||||
|
||||
|
||||
def init_sprite_requirements():
|
||||
reqs = [
|
||||
SpriteRequirement(EnemySprite.Raven).no_drop().sub_group(3, [0x11, 0x19]).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Vulture).no_drop().sub_group(2, 0x12).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.CorrectPullSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.WrongPullSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.Octorok).sub_group(2, [0xc, 0x18]),
|
||||
SpriteRequirement(EnemySprite.Moldorm).exalt().sub_group(2, 0x30),
|
||||
SpriteRequirement(EnemySprite.Octorok4Way).sub_group(2, 0xc),
|
||||
SpriteRequirement(EnemySprite.Cucco).immune().sub_group(3, [0x15, 0x50]).exclude(NoFlyingRooms),
|
||||
# todo: Buzzblob kill rule for mimics
|
||||
SpriteRequirement(EnemySprite.Buzzblob).sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.Snapdragon).sub_group(0, 0x16).sub_group(2, 0x17),
|
||||
SpriteRequirement(EnemySprite.Octoballoon).no_drop().sub_group(2, 0xc).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Hinox).sub_group(0, 0x16),
|
||||
SpriteRequirement(EnemySprite.Moblin).sub_group(2, 0x17),
|
||||
SpriteRequirement(EnemySprite.MiniHelmasaur).sub_group(1, 0x1e),
|
||||
# todo: antifairy kill rule
|
||||
SpriteRequirement(EnemySprite.AntiFairy).no_drop().sub_group(3, [0x52, 0x53])
|
||||
.exclude(NoFlyingRooms).exclude({0x40}), # no anti-fairies in aga tower bridge room
|
||||
SpriteRequirement(EnemySprite.Wiseman).affix().sub_group(2, 0x4c),
|
||||
SpriteRequirement(EnemySprite.Hoarder).no_drop().sub_group(3, 0x11).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.MiniMoldorm).sub_group(1, 0x1e),
|
||||
SpriteRequirement(EnemySprite.Poe).no_drop().sub_group(3, 0x15).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Smithy).affix().sub_group(1, 0x1d).sub_group(3, 0x15),
|
||||
SpriteRequirement(EnemySprite.Statue).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.CrystalSwitch).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.SickKid).affix().sub_group(0, 0x51),
|
||||
SpriteRequirement(EnemySprite.Sluggula).sub_group(2, 0x25),
|
||||
SpriteRequirement(EnemySprite.WaterSwitch).affix().sub_group(3, 0x53),
|
||||
SpriteRequirement(EnemySprite.Ropa).sub_group(0, 0x16),
|
||||
SpriteRequirement(EnemySprite.RedBari).no_drop().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.BlueBari).sub_group(0, 0x1f),
|
||||
# todo: don't randomize red/blue bari in room 0x7F
|
||||
SpriteRequirement(EnemySprite.TalkingTree).affix().sub_group(0, 0x15),
|
||||
SpriteRequirement(EnemySprite.HardhatBeetle).sub_group(1, 0x1e),
|
||||
# todo: deadrock kill rule for mimics (not sure why ice spike room...)
|
||||
SpriteRequirement(EnemySprite.Deadrock).sub_group(3, 0x10).exclude({0x7f, 0x10c}),
|
||||
SpriteRequirement(EnemySprite.DarkWorldHintNpc).affix(), # no groups?
|
||||
SpriteRequirement(EnemySprite.AdultNpc).affix().sub_group(0, [0xe, 0x4f]),
|
||||
SpriteRequirement(EnemySprite.SweepingLady).affix().group(6), # no sub groups?
|
||||
SpriteRequirement(EnemySprite.Lumberjacks).affix().sub_group(2, 0x4a),
|
||||
SpriteRequirement(EnemySprite.RaceGameLady).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.FortuneTeller).affix().sub_group(0, 0x4b),
|
||||
SpriteRequirement(EnemySprite.ArgueBros).affix().sub_group(0, 0x4f),
|
||||
SpriteRequirement(EnemySprite.RupeePull).affix(),
|
||||
SpriteRequirement(EnemySprite.YoungSnitch).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Innkeeper).affix(), # no groups?
|
||||
SpriteRequirement(EnemySprite.Witch).affix().sub_group(2, 0x7c),
|
||||
SpriteRequirement(EnemySprite.Waterfall).affix(),
|
||||
SpriteRequirement(EnemySprite.EyeStatue).affix(),
|
||||
SpriteRequirement(EnemySprite.Locksmith).affix().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.MagicBat).affix().sub_group(3, 0x1d),
|
||||
SpriteRequirement(EnemySprite.KidInKak).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.OldSnitch).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Hoarder2).no_drop().sub_group(3, 0x11).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.TutorialGuard).affix(),
|
||||
SpriteRequirement(EnemySprite.LightningGate).affix().sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.BlueGuard).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.GreenGuard).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedSpearGuard).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.BluesainBolt).sub_group(0, 0x46).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.UsainBolt).sub_group(1, [0xd, 0x49]),
|
||||
SpriteRequirement(EnemySprite.BlueArcher).sub_group(0, 0x48).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.GreenBushGuard).sub_group(0, 0x48).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedJavelinGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.RedBushGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.BombGuard).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.GreenKnifeGuard).sub_group(1, 0x49).sub_group(2, 0x13),
|
||||
SpriteRequirement(EnemySprite.Geldman).no_drop().sub_group(2, 0x12).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.Toppo).no_drop().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.Popo).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.Popo2).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.Popo2).sub_group(1, 0x2c),
|
||||
SpriteRequirement(EnemySprite.ArmosStatue).sub_group(3, 0x10).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.KingZora).affix().sub_group(3, 0x44),
|
||||
SpriteRequirement(EnemySprite.ArmosKnight).exalt().sub_group(3, 0x1d),
|
||||
SpriteRequirement(EnemySprite.Lanmolas).exalt().sub_group(3, 0x31),
|
||||
SpriteRequirement(EnemySprite.FireballZora).immerse().uw_skip().sub_group(2, [0xc, 0x18]),
|
||||
SpriteRequirement(EnemySprite.Zora).immerse().no_drop().uw_skip().sub_group(2, 0xc).sub_group(3, 0x44),
|
||||
SpriteRequirement(EnemySprite.DesertStatue).affix().sub_group(2, 0x12),
|
||||
SpriteRequirement(EnemySprite.Crab).sub_group(2, 0xc),
|
||||
SpriteRequirement(EnemySprite.LostWoodsBird).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.LostWoodsSquirrel).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.SparkCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.SparkCCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.RollerVerticalUp).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerVerticalDown).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerHorizontalLeft).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.RollerHorizontalRight).immune().sub_group(2, 0x27).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.Beamos).immune().sub_group(1, 0x2c).exclude(NoBeamosOrTrapRooms),
|
||||
SpriteRequirement(EnemySprite.MasterSword).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||
# these are excluded for now
|
||||
SpriteRequirement(EnemySprite.DebirandoPit).skip().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.Debirando).skip().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.ArcheryNpc).affix().sub_group(0, 0x4b),
|
||||
SpriteRequirement(EnemySprite.WallCannonVertLeft).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonVertRight).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonHorzTop).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.WallCannonHorzBottom).affix().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.BallNChain).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.CannonTrooper).sub_group(0, 0x46).sub_group(1, 0x49),
|
||||
SpriteRequirement(EnemySprite.CricketRat).sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Snake).sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Keese).no_drop().sub_group(2, [0x1c, 0x24]),
|
||||
SpriteRequirement(EnemySprite.Leever).no_drop().sub_group(0, 0x2f),
|
||||
SpriteRequirement(EnemySprite.FairyPondTrigger).affix().sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.UnclePriest).affix().sub_group(0, [0x47, 0x51]),
|
||||
SpriteRequirement(EnemySprite.RunningNpc).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.BottleMerchant).affix().group(6),
|
||||
SpriteRequirement(EnemySprite.Zelda).affix(),
|
||||
SpriteRequirement(EnemySprite.Grandma).affix().sub_group(0, 0x4b).sub_group(1, 0x4d).sub_group(2, 0x4a),
|
||||
SpriteRequirement(EnemySprite.Agahnim).exalt().sub_group(0, 0x55).sub_group(1, [0x1a, 0x3d]).sub_group(2, 0x42)
|
||||
.sub_group(3, 0x43),
|
||||
SpriteRequirement(EnemySprite.FloatingSkull).no_drop().sub_group(0, 0x1f).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.FirebarCW).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.FirebarCCW).immune().sub_group(0, 0x1f),
|
||||
# todo: don't randomize these in GT Torch Cross and TR Dark Ride? was that ever implemented?
|
||||
SpriteRequirement(EnemySprite.Firesnake).immune().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.Hover).immerse().sub_group(2, 0x22).exclude(NoFlyingRooms),
|
||||
# todo: leave them in swamp palace entrance...
|
||||
SpriteRequirement(EnemySprite.AntiFairyCircle).skip().no_drop().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.GreenEyegoreMimic).sub_group(2, 0x2e),
|
||||
SpriteRequirement(EnemySprite.RedEyegoreMimic).sub_group(2, 0x2e),
|
||||
# kodongos apparently broken?
|
||||
SpriteRequirement(EnemySprite.Kondongo).skip().sub_group(2, 0x2a),
|
||||
SpriteRequirement(EnemySprite.Mothula).exalt().sub_group(2, 0x38).sub_group(3, 0x52),
|
||||
SpriteRequirement(EnemySprite.SpikeBlock).immune().sub_group(3, [0x52, 0x53]).exclude(NoBeamosOrTrapRooms)
|
||||
.exclude({0x28}), # why exclude sp entrance?
|
||||
SpriteRequirement(EnemySprite.Gibdo).sub_group(2, 0x23),
|
||||
SpriteRequirement(EnemySprite.Arrghus).exalt().sub_group(2, 0x39),
|
||||
SpriteRequirement(EnemySprite.Arrghi).exalt().sub_group(2, 0x39),
|
||||
SpriteRequirement(EnemySprite.Terrorpin).sub_group(2, 0x2a).exclude({0x10c}), # probably fine in mimic now
|
||||
SpriteRequirement(EnemySprite.Blob).sub_group(1, 0x20),
|
||||
# todo: wallmaster overlords
|
||||
SpriteRequirement(EnemySprite.Wallmaster).immune().ow_skip().sub_group(2, 0x23)
|
||||
.allow(WallmasterValidRooms),
|
||||
SpriteRequirement(EnemySprite.StalfosKnight).sub_group(1, 0x10).exclude({0x10c}),
|
||||
SpriteRequirement(EnemySprite.HelmasaurKing).exalt().sub_group(2, 0x3a).sub_group(3, 0x3e),
|
||||
SpriteRequirement(EnemySprite.Bumper).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeLeft).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeRight).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeTop).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.LaserEyeBottom).affix().sub_group(3, [0x52, 0x53]),
|
||||
SpriteRequirement(EnemySprite.Pengator).sub_group(2, 0x26),
|
||||
SpriteRequirement(EnemySprite.Kyameron).no_drop().immerse().sub_group(2, 0x22),
|
||||
# todo: leave them in swamp palace entrance...
|
||||
SpriteRequirement(EnemySprite.Wizzrobe).sub_group(2, [0x25, 0x29]),
|
||||
SpriteRequirement(EnemySprite.Zoro).no_drop().sub_group(1, 0x20),
|
||||
SpriteRequirement(EnemySprite.Babasu).no_drop().sub_group(1, 0x20),
|
||||
SpriteRequirement(EnemySprite.GroveOstritch).affix().sub_group(2, 0x4e),
|
||||
SpriteRequirement(EnemySprite.GroveRabbit).affix(),
|
||||
SpriteRequirement(EnemySprite.GroveBird).affix().sub_group(2, 0x4e),
|
||||
SpriteRequirement(EnemySprite.Freezor).stasis().skip().sub_group(2, 0x26),
|
||||
SpriteRequirement(EnemySprite.Kholdstare).exalt().sub_group(2, 0x3c),
|
||||
SpriteRequirement(EnemySprite.KholdstareShell).exalt(),
|
||||
SpriteRequirement(EnemySprite.FallingIce).exalt().sub_group(2, 0x3c),
|
||||
SpriteRequirement(EnemySprite.BlueZazak).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.RedZazak).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.Stalfos).sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.GreenZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.BlueZirro).no_drop().sub_group(3, 0x1b).exclude(NoFlyingRooms),
|
||||
SpriteRequirement(EnemySprite.Pikit).no_drop().sub_group(3, 0x1b),
|
||||
SpriteRequirement(EnemySprite.CrystalMaiden).affix(),
|
||||
SpriteRequirement(EnemySprite.OldMan).affix().sub_group(0, 0x46).sub_group(1, 0x49).sub_group(2, 0x1c),
|
||||
SpriteRequirement(EnemySprite.PipeDown).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeUp).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeRight).affix(),
|
||||
SpriteRequirement(EnemySprite.PipeLeft).affix(),
|
||||
SpriteRequirement(EnemySprite.GoodBee).affix().sub_group(0, 0x1f),
|
||||
SpriteRequirement(EnemySprite.PurpleChest).affix().sub_group(3, 0x15),
|
||||
SpriteRequirement(EnemySprite.BombShopGuy).affix().sub_group(1, 0x4d),
|
||||
SpriteRequirement(EnemySprite.Kiki).affix().sub_group(3, 0x19),
|
||||
SpriteRequirement(EnemySprite.BlindMaiden).affix(),
|
||||
# dialog tester.sub_group(1, 0x2c)
|
||||
SpriteRequirement(EnemySprite.BullyPinkBall).affix().sub_group(3, 0x14),
|
||||
# shop keepers in complex thing below
|
||||
SpriteRequirement(EnemySprite.Drunkard).affix().sub_group(0, 0x4f).sub_group(1, 0x4d).sub_group(2, 0x4a).
|
||||
sub_group(3, 0x50),
|
||||
SpriteRequirement(EnemySprite.Vitreous).exalt().sub_group(3, 0x3d),
|
||||
SpriteRequirement(EnemySprite.Catfish).affix().sub_group(2, 0x18),
|
||||
SpriteRequirement(EnemySprite.CutsceneAgahnim).affix().sub_group(0, 0x55).sub_group(1, 0x3d)
|
||||
.sub_group(2, 0x42).sub_group(3, 0x43),
|
||||
SpriteRequirement(EnemySprite.Boulder).affix().sub_group(3, 0x10),
|
||||
SpriteRequirement(EnemySprite.Gibo).sub_group(2, 0x28),
|
||||
SpriteRequirement(EnemySprite.Thief).no_drop().sub_group(0, [0xe, 0x15]),
|
||||
SpriteRequirement(EnemySprite.Medusa).affix(),
|
||||
SpriteRequirement(EnemySprite.FourWayShooter).affix(),
|
||||
SpriteRequirement(EnemySprite.Pokey).sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.BigFairy).affix().sub_group(2, 0x39).sub_group(3, 0x36),
|
||||
SpriteRequirement(EnemySprite.Tektite).sub_group(3, 0x10),
|
||||
SpriteRequirement(EnemySprite.Chainchomp).immune().sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.TrinexxRockHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.TrinexxFireHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.TrinexxIceHead).exalt().sub_group(0, 0x40).sub_group(3, 0x3f),
|
||||
SpriteRequirement(EnemySprite.Blind).exalt().sub_group(1, 0x2c).sub_group(2, 0x3b),
|
||||
SpriteRequirement(EnemySprite.Swamola).immerse().no_drop().sub_group(3, 0x19),
|
||||
SpriteRequirement(EnemySprite.Lynel).sub_group(3, 0x14),
|
||||
SpriteRequirement(EnemySprite.BunnyBeam).affix(),
|
||||
SpriteRequirement(EnemySprite.FloppingFish).uw_skip().immune(),
|
||||
SpriteRequirement(EnemySprite.Stal).skip(),
|
||||
SpriteRequirement(EnemySprite.DiggingGameNPC).affix().sub_group(1, 0x2a),
|
||||
SpriteRequirement(EnemySprite.Ganon).exalt().sub_group(0, 0x21).sub_group(1, 0x41)
|
||||
.sub_group(2, 0x45).sub_group(3, 0x33),
|
||||
SpriteRequirement(EnemySprite.Faerie).affix(),
|
||||
SpriteRequirement(EnemySprite.FakeMasterSword).immune().sub_group(3, 0x11),
|
||||
SpriteRequirement(EnemySprite.MagicShopAssistant).affix().sub_group(0, 0x4b).sub_group(3, 0x5a),
|
||||
SpriteRequirement(EnemySprite.SomariaPlatform).affix().sub_group(2, 0x27),
|
||||
SpriteRequirement(EnemySprite.CastleMantle).affix().sub_group(0, 0x5d),
|
||||
SpriteRequirement(EnemySprite.MedallionTablet).affix().sub_group(2, 0x12),
|
||||
|
||||
# todo: overlord requirements
|
||||
SpriteRequirement(2, 7).affix().sub_group(2, 46),
|
||||
SpriteRequirement(3, 7).affix().sub_group(2, 46),
|
||||
SpriteRequirement(5, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(6, 7).affix().sub_group(2, [28, 36]),
|
||||
SpriteRequirement(7, 7).affix(),
|
||||
SpriteRequirement(8, 7).affix().sub_group(1, 32),
|
||||
SpriteRequirement(9, 7).affix().sub_group(2, 35),
|
||||
SpriteRequirement(0xa, 7).affix().sub_group(3, 82),
|
||||
SpriteRequirement(0xb, 7).affix().sub_group(3, 82),
|
||||
SpriteRequirement(0x10, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x11, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x12, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x13, 7).affix().sub_group(2, 34),
|
||||
SpriteRequirement(0x14, 7).affix(),
|
||||
SpriteRequirement(0x15, 7).affix().sub_group(2, [37, 41]),
|
||||
SpriteRequirement(0x16, 7).affix().sub_group(1, 32),
|
||||
SpriteRequirement(0x17, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(0x18, 7).affix().sub_group(0, 31),
|
||||
SpriteRequirement(0x19, 7).affix(),
|
||||
SpriteRequirement(0x1a, 7).affix(),
|
||||
]
|
||||
simple = {(r.sprite, r.overlord): r for r in reqs}
|
||||
shopkeeper = [
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0xff, 0x112, 0x11f}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 75).sub_group(1, 77).sub_group(2, 74)
|
||||
.sub_group(3, 90).allow({0x10f, 0x110, 0x11f}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 79).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0x118}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 90)
|
||||
.allow({0x123, 0x124}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 14).sub_group(2, 74).sub_group(3, 80)
|
||||
.allow({0x125}),
|
||||
SpriteRequirement(EnemySprite.Shopkeeper).affix().sub_group(0, 21).allow({0x11e}),
|
||||
]
|
||||
complex_r = {}
|
||||
for req in shopkeeper:
|
||||
for r in req.allowed_rooms:
|
||||
complex_r[r] = req
|
||||
simple[(EnemySprite.Shopkeeper, 0)] = complex_r
|
||||
return simple
|
||||
|
||||
|
||||
vanilla_sheets = [
|
||||
(0x00, 0x49, 0x00, 0x00), (0x46, 0x49, 0x0C, 0x1D), (0x48, 0x49, 0x13, 0x1D), (0x46, 0x49, 0x13, 0x0E),
|
||||
(0x48, 0x49, 0x0C, 0x11), (0x48, 0x49, 0x0C, 0x10), (0x4F, 0x49, 0x4A, 0x50), (0x0E, 0x49, 0x4A, 0x11),
|
||||
(0x46, 0x49, 0x12, 0x00), (0x00, 0x49, 0x00, 0x50), (0x00, 0x49, 0x00, 0x11), (0x48, 0x49, 0x0C, 0x00),
|
||||
(0x00, 0x00, 0x37, 0x36), (0x48, 0x49, 0x4C, 0x11), (0x5D, 0x2C, 0x0C, 0x44), (0x00, 0x00, 0x4E, 0x00),
|
||||
|
||||
(0x0F, 0x00, 0x12, 0x10), (0x00, 0x00, 0x00, 0x4C), (0x00, 0x0D, 0x17, 0x00), (0x16, 0x0D, 0x17, 0x1B),
|
||||
(0x16, 0x0D, 0x17, 0x14), (0x15, 0x0D, 0x17, 0x15), (0x16, 0x0D, 0x18, 0x19), (0x16, 0x0D, 0x17, 0x19),
|
||||
(0x16, 0x0D, 0x00, 0x00), (0x16, 0x0D, 0x18, 0x1B), (0x0F, 0x49, 0x4A, 0x11), (0x4B, 0x2A, 0x5C, 0x15),
|
||||
(0x16, 0x49, 0x17, 0x1D), (0x00, 0x00, 0x00, 0x15), (0x16, 0x0D, 0x17, 0x10), (0x16, 0x49, 0x12, 0x00),
|
||||
|
||||
(0x16, 0x49, 0x0C, 0x11), (0x00, 0x00, 0x12, 0x10), (0x16, 0x0D, 0x00, 0x11), (0x16, 0x49, 0x0C, 0x00),
|
||||
(0x16, 0x0D, 0x4C, 0x11), (0x0E, 0x0D, 0x4A, 0x11), (0x16, 0x1A, 0x17, 0x1B), (0x4F, 0x34, 0x4A, 0x50),
|
||||
(0x35, 0x4D, 0x65, 0x36), (0x4A, 0x34, 0x4E, 0x00), (0x0E, 0x34, 0x4A, 0x11), (0x51, 0x34, 0x5D, 0x59),
|
||||
(0x4B, 0x49, 0x4C, 0x11), (0x2D, 0x00, 0x00, 0x00), (0x5D, 0x00, 0x12, 0x59), (0x00, 0x00, 0x00, 0x00),
|
||||
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
|
||||
(0x47, 0x49, 0x2B, 0x2D), (0x46, 0x49, 0x1C, 0x52), (0x00, 0x49, 0x1C, 0x52), (0x5D, 0x49, 0x00, 0x52),
|
||||
(0x46, 0x49, 0x13, 0x52), (0x4B, 0x4D, 0x4A, 0x5A), (0x47, 0x49, 0x1C, 0x52), (0x4B, 0x4D, 0x39, 0x36),
|
||||
(0x1F, 0x2C, 0x2E, 0x52), (0x1F, 0x2C, 0x2E, 0x1D), (0x2F, 0x2C, 0x2E, 0x52), (0x2F, 0x2C, 0x2E, 0x31),
|
||||
(0x1F, 0x1E, 0x30, 0x52), (0x51, 0x49, 0x13, 0x00), (0x4F, 0x49, 0x13, 0x50), (0x4F, 0x4D, 0x4A, 0x50),
|
||||
|
||||
(0x4B, 0x49, 0x4C, 0x2B), (0x1F, 0x20, 0x22, 0x53), (0x55, 0x3D, 0x42, 0x43), (0x1F, 0x1E, 0x23, 0x52),
|
||||
(0x1F, 0x1E, 0x39, 0x3A), (0x1F, 0x1E, 0x3A, 0x3E), (0x1F, 0x1E, 0x3C, 0x3D), (0x40, 0x1E, 0x27, 0x3F),
|
||||
(0x55, 0x1A, 0x42, 0x43), (0x1F, 0x1E, 0x2A, 0x52), (0x1F, 0x1E, 0x38, 0x52), (0x1F, 0x20, 0x28, 0x52),
|
||||
(0x1F, 0x20, 0x26, 0x52), (0x1F, 0x2C, 0x25, 0x52), (0x1F, 0x20, 0x27, 0x52), (0x1F, 0x1E, 0x29, 0x52),
|
||||
|
||||
(0x1F, 0x2C, 0x3B, 0x52), (0x46, 0x49, 0x24, 0x52), (0x21, 0x41, 0x45, 0x33), (0x1F, 0x2C, 0x28, 0x31),
|
||||
(0x1F, 0x0D, 0x29, 0x52), (0x1F, 0x1E, 0x27, 0x52), (0x1F, 0x20, 0x27, 0x53), (0x48, 0x49, 0x13, 0x52),
|
||||
(0x0E, 0x1E, 0x4A, 0x50), (0x1F, 0x20, 0x26, 0x53), (0x15, 0x00, 0x00, 0x00), (0x1F, 0x00, 0x2A, 0x52),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x00),
|
||||
(0x00, 0x00, 0x00, 0x00), (0x00, 0x00, 0x00, 0x08), (0x5D, 0x49, 0x00, 0x52), (0x55, 0x49, 0x42, 0x43),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50),
|
||||
(0x61, 0x62, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x56, 0x63, 0x50), (0x61, 0x56, 0x57, 0x50),
|
||||
(0x61, 0x56, 0x33, 0x50), (0x61, 0x56, 0x57, 0x50), (0x61, 0x62, 0x63, 0x50), (0x61, 0x62, 0x63, 0x50)
|
||||
]
|
||||
|
||||
required_boss_sheets = {EnemySprite.ArmosKnight: 9, EnemySprite.Lanmolas: 11, EnemySprite.Moldorm: 12,
|
||||
EnemySprite.HelmasaurKing: 21, EnemySprite.Arrghus: 20, EnemySprite.Mothula: 26,
|
||||
EnemySprite.Blind: 32, EnemySprite.Kholdstare: 22, EnemySprite.Vitreous: 22,
|
||||
EnemySprite.TrinexxRockHead: 23}
|
||||
|
||||
|
||||
class SpriteSheet:
|
||||
def __init__(self, id, default_sub_groups):
|
||||
self.id = id
|
||||
self.sub_groups = list(default_sub_groups)
|
||||
self.locked = [False] * 4
|
||||
self.room_set = set()
|
||||
|
||||
def dungeon_id(self):
|
||||
return self.id + 0x40
|
||||
|
||||
def valid_sprite(self, requirement):
|
||||
if requirement.groups and self.id not in requirement.groups:
|
||||
return False
|
||||
for idx, sub in enumerate(self.sub_groups):
|
||||
if requirement.sub_groups[idx] and sub not in requirement.sub_groups[idx]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def lock_sprite_in(self, sprite):
|
||||
for i, options in sprite.sub_groups.items():
|
||||
self.locked[i] = len(options) > 0
|
||||
|
||||
def add_sprite_to_sheet(self, groups, rooms=None):
|
||||
for idx, g in enumerate(groups):
|
||||
if g is not None:
|
||||
self.sub_groups[idx] = g
|
||||
self.locked[idx] = True
|
||||
if rooms is not None:
|
||||
self.room_set.update(rooms)
|
||||
|
||||
def write_to_rom(self, rom, base_address):
|
||||
rom.write_bytes(base_address + self.id * 4, self.sub_groups)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.id} => [{", ".join([str(x) for x in self.sub_groups])}]'
|
||||
|
||||
|
||||
# convert to dungeon id
|
||||
def did(n):
|
||||
return n + 0x40
|
||||
|
||||
|
||||
def init_sprite_sheets(requirements):
|
||||
sheets = {id: SpriteSheet(id, def_sheet) for id, def_sheet in enumerate(vanilla_sheets)}
|
||||
# wait until bosses are randomized to determine which are randomized
|
||||
for sprite, sheet_num in required_boss_sheets.items():
|
||||
sheet = sheets[did(sheet_num)] # convert to dungeon sheet id
|
||||
boss_sprite = requirements[(sprite, 0)]
|
||||
sheet.lock_sprite_in(boss_sprite)
|
||||
return sheets
|
||||
|
||||
|
||||
def setup_required_dungeon_groups(sheets):
|
||||
|
||||
sheets[did(1)].add_sprite_to_sheet([70, 73, 28, 82], {0xe4, 0xf0}) # old man
|
||||
# various npcs
|
||||
sheets[did(5)].add_sprite_to_sheet([75, 77, 74, 90], {0xf3, 0x109, 0x10e, 0x10f, 0x110, 0x111, 0x11a, 0x11c, 0x122})
|
||||
sheets[did(7)].add_sprite_to_sheet([75, 77, 57, 54], {0x8, 0x2c, 0x114, 0x115}) # big fairies
|
||||
sheets[did(13)].add_sprite_to_sheet([81, None, None, None], {0x55, 0x102, 0x104}) # uncle, sick kid
|
||||
sheets[did(14)].add_sprite_to_sheet([71, 73, 76, 80], {0x12, 0x105, 0x10a}) # wisemen
|
||||
sheets[did(15)].add_sprite_to_sheet([79, 77, 74, 80], {0xf4, 0xf5, 0x101, 0x103, 0x106, 0x118, 0x119}) # more npcs
|
||||
sheets[did(18)].add_sprite_to_sheet([85, 61, 66, 67], {0x20, 0x30}) # aga alter, aga1
|
||||
sheets[did(24)].add_sprite_to_sheet([85, 26, 66, 67], {0xd}) # aga2
|
||||
sheets[did(34)].add_sprite_to_sheet([33, 65, 69, 51], {0}) # ganon
|
||||
sheets[did(40)].add_sprite_to_sheet([14, None, 74, 80], {0x124, 0x125, 0x126}) # fairy + rupee npcs
|
||||
sheets[did(9)].add_sprite_to_sheet([None, None, None, 29], {0xe3}) # magic bat
|
||||
sheets[did(28)].add_sprite_to_sheet([None, None, 38, 82], {0xe, 0x7e, 0x8e, 0x9e}) # freezors
|
||||
sheets[did(3)].add_sprite_to_sheet([93, None, None, None], {0x51}) # mantle
|
||||
sheets[did(42)].add_sprite_to_sheet([21, None, None, None], {0x11e}) # hype cave
|
||||
sheets[did(10)].add_sprite_to_sheet([47, None, 46, None], {0x5c, 0x75, 0xb9, 0xd9}) # cannonballs
|
||||
sheets[did(37)].add_sprite_to_sheet([31, None, 39, 82], {0x24, 0xb4, 0xb5, 0xc6, 0xc7, 0xd6}) # somaria platforms
|
||||
# not sure 31 is needed above
|
||||
|
||||
free_sheet_reqs = [
|
||||
([75, None, None, None], [0xff, 0x112, 0x11f]), # shopkeepers
|
||||
([None, 77, None, 21], [0x121]), # smithy
|
||||
([None, None, None, 80], [0x108]), # chicken house
|
||||
([14, 30, None, None], [0x123]), # mini moldorm (shutter door)
|
||||
([None, None, 34, None], [0x36, 0x46, 0x66, 0x76]), # pirogusu spawners
|
||||
([None, 32, None, None], [0x3e, 0x9f]), # babasu spawners
|
||||
([31, None, None, None], [0x7f]), # force baris
|
||||
([None, None, 35, None], [0x39, 0x49, 0x56, 0x57, 0x68, 0x8d]), # wallmasters
|
||||
# bumpers - why the split - because of other requirements -
|
||||
([None, None, None, (82, 83)], [0x17, 0x2a, 0x4c, 0x59, 0x67, 0x68, 0x7e, 0x8b, 0xeb, 0xfb]),
|
||||
# crystal switches - split for some reason
|
||||
([None, None, None, (82, 83)], [0xb, 0x13, 0x1b, 0x1e, 0x2a, 0x2b, 0x31, 0x3e, 0x5b, 0x6b, 0x77, 0xb7, 0x8b, 0x91, 0x92, 0x9b, 0x9d, 0xa1, 0xab, 0xb6, 0xbf, 0xc1, 0xc4, 0xef]),
|
||||
# laser eyes - split for some reason
|
||||
([None, None, None, (82, 83)], [0x13, 0x23, 0x96, 0xa5, 0xc5, 0xd5]),
|
||||
# statues - split for some reason
|
||||
([None, None, None, (82, 83)], [0x26, 0x2b, 0x40, 0x4a, 0x57, 0x6b, 0x7b]),
|
||||
|
||||
# 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, 83], [0x4, 0x3f, 0xce]), # pull tongue
|
||||
([None, None, None, 83], [0x35, 0x37, 0x76]), # swamp drains
|
||||
([None, None, 34, None], [0x28]), # tektike forced? - spawn chest
|
||||
([None, None, 37, None], [0x97]), # wizzrobe spawner - in middle of room...
|
||||
]
|
||||
|
||||
# find home for the free_sheet_reqs
|
||||
for pair in free_sheet_reqs:
|
||||
groups, room_list = pair
|
||||
possible_sheets = []
|
||||
found_match = False
|
||||
for num in range(65, 124):
|
||||
sheet = sheets[num]
|
||||
valid = True
|
||||
match = True
|
||||
for idx, value in enumerate(groups):
|
||||
if value is not None and sheet.locked[idx]:
|
||||
valid = False
|
||||
if (sheet.sub_groups[idx] not in value if isinstance(value, tuple)
|
||||
else value != sheet.sub_groups[idx]):
|
||||
match = False
|
||||
elif value is not None:
|
||||
match = False
|
||||
if match:
|
||||
found_match = True
|
||||
break
|
||||
if valid:
|
||||
possible_sheets.append(sheet)
|
||||
if not found_match:
|
||||
chosen_sheet = random.choice(possible_sheets)
|
||||
chosen_groups = [(random.choice(g) if isinstance(g, tuple) else g) for g in groups]
|
||||
chosen_sheet.add_sprite_to_sheet(chosen_groups, room_list)
|
||||
|
||||
|
||||
# RandomizeRooms(optionFlags);
|
||||
# roomCollection.LoadRooms()
|
||||
# roomCollection.RandomizeRoomSpriteGroups(spriteGroupCollection, optionFlags);
|
||||
# more stuff
|
||||
uw_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],
|
||||
3: [17, 16, 27, 20, 82, 83]
|
||||
}
|
||||
|
||||
|
||||
def randomize_underworld_sprite_sheets(sheets):
|
||||
setup_required_dungeon_groups(sheets)
|
||||
|
||||
for num in range(65, 124): # sheets 0x41 to 0x7B inclusive
|
||||
sheet = sheets[num]
|
||||
if not sheet.locked[1] and num in [65, 66, 67, 68]:
|
||||
sheet.locked[1] = True
|
||||
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])
|
||||
# lock the group?
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user