Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2023-05-07 20:29:36 -05:00
13 changed files with 90 additions and 38 deletions

View File

@@ -1,10 +1,18 @@
# Changelog # Changelog
## 0.3.0.7
- \~Merged in DR v1.2.0.16~
- Major overhaul of how item GFX are drawn on screen
- Bonk prize GFX can now all be displayed simultaneously
- Rupee items that are in-plain-sight are now animated
- Narrow items are now centered within their tile space
- Fixed issue with pottery items showing bad GFX after map check or medallion use
- Fixed issue with bonk drop items causing duplicate sprite spawns
## 0.3.0.6 ## 0.3.0.6
- \~Merged in DR v1.2.0.15~ - \~Merged in DR v1.2.0.15~
- Fixed Tower of Hera music silence issue - Fixed Tower of Hera music silence issue
- Improved GT crystal cutscene - Improved symmetrical GT crystal cutscene
- Fixed issue with bonk drop items causing duplicate sprite spawns
- Changed bonk prizes to not mark as collected unless it is visible on screen - Changed bonk prizes to not mark as collected unless it is visible on screen
## 0.3.0.5 ## 0.3.0.5

View File

@@ -4162,7 +4162,7 @@ interior_doors = [
('Mire Neglected Room SE', 'Mire Chest View NE'), ('Mire Neglected Room SE', 'Mire Chest View NE'),
('Mire BK Chest Ledge WS', 'Mire Warping Pool ES'), # technically one-way ('Mire BK Chest Ledge WS', 'Mire Warping Pool ES'), # technically one-way
('Mire Torches Top SW', 'Mire Torches Bottom NW'), ('Mire Torches Top SW', 'Mire Torches Bottom NW'),
('Mire Torches Bottom WS', 'Mire Attic Hint ES'), ('Mire Torches Bottom ES', 'Mire Attic Hint WS'),
('Mire Dark Shooters SE', 'Mire Key Rupees NE'), ('Mire Dark Shooters SE', 'Mire Key Rupees NE'),
('Mire Dark Shooters SW', 'Mire Block X NW'), ('Mire Dark Shooters SW', 'Mire Block X NW'),
('Mire Tall Dark and Roomy WS', 'Mire Crystal Right ES'), ('Mire Tall Dark and Roomy WS', 'Mire Crystal Right ES'),

View File

@@ -924,9 +924,9 @@ def create_doors(world, player):
create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1), create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom Holes', Hole), create_door(player, 'Mire Torches Bottom Holes', Hole),
create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1), create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom WS', Intr).dir(We, 0x97, Bot, High).pos(0), create_door(player, 'Mire Torches Bottom ES', Intr).dir(Ea, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Torches Top Holes', Hole), create_door(player, 'Mire Torches Top Holes', Hole),
create_door(player, 'Mire Attic Hint ES', Intr).dir(Ea, 0x97, Bot, High).pos(0), create_door(player, 'Mire Attic Hint WS', Intr).dir(We, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Attic Hint Hole', Hole), create_door(player, 'Mire Attic Hint Hole', Hole),
create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec), create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec),
create_door(player, 'Mire Dark Shooters SW', Intr).dir(So, 0x93, Left, High).pos(0), create_door(player, 'Mire Dark Shooters SW', Intr).dir(So, 0x93, Left, High).pos(0),

View File

@@ -2769,7 +2769,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d),
'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00), 'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00),
'Hype Cave': (0x940, 0xc80), 'Hype Cave': (0x940, 0xc80),
'Bonk Fairy (Dark)': (0x740, 0xa80), 'Bonk Fairy (Dark)': (0x740, 0xa80),
'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x080, 0x7a0),
'Hammer Peg Cave': (0x4c0, 0x940), 'Hammer Peg Cave': (0x4c0, 0x940),
'Red Shield Shop': (0x500, 0x680), 'Red Shield Shop': (0x500, 0x680),
'Dark Sanctuary Hint': (0x720, 0x4a0), 'Dark Sanctuary Hint': (0x720, 0x4a0),

View File

@@ -36,7 +36,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new
from source.tools.BPS import create_bps_from_data from source.tools.BPS import create_bps_from_data
from source.classes.CustomSettings import CustomSettings from source.classes.CustomSettings import CustomSettings
version_number = '1.2.0.15' version_number = '1.2.0.16'
version_branch = '-u' version_branch = '-u'
__version__ = f'{version_number}{version_branch}' __version__ = f'{version_number}{version_branch}'

View File

@@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
from OverworldGlitchRules import create_owg_connections from OverworldGlitchRules import create_owg_connections
from Utils import bidict from Utils import bidict
version_number = '0.3.0.6' version_number = '0.3.0.7'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''

View File

@@ -109,6 +109,11 @@ These are now independent of retro mode and have three options: None, Random, an
# Bug Fixes and Notes # Bug Fixes and Notes
* 1.2.0.16u
* Fix for partial key logic on vanilla Mire
* Fix for Kholdstare Shell collision when at Lanmo 2
* Fix for Mire Attic Hint door (direction was swapped)
* Dungeon at Chest Game displays correctly on OW map option
* 1.2.0.15u * 1.2.0.15u
* GUI reorganization * GUI reorganization
* Logic fix for pots in GT conveyor cross * Logic fix for pots in GT conveyor cross

View File

@@ -814,8 +814,8 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']), create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']),
create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']), create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']),
create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']), create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']),
create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom WS', 'Mire Torches Bottom Holes']), create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom ES', 'Mire Torches Bottom Holes']),
create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint ES', 'Mire Attic Hint Hole']), create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint WS', 'Mire Attic Hint Hole']),
create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']), create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']),
create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']), create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']),
create_dungeon_region(player, 'Mire Block X', 'Misery Mire', None, ['Mire Block X NW', 'Mire Block X WS']), create_dungeon_region(player, 'Mire Block X', 'Misery Mire', None, ['Mire Block X NW', 'Mire Block X WS']),

2
Rom.py
View File

@@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '544b8d7dd202c6e8a9e70b31af5bae3d' RANDOMIZERBASEHASH = '3c651a38ea79504029c71b382c9c17da'
class JsonRom(object): class JsonRom(object):

View File

@@ -1840,7 +1840,9 @@ def add_key_logic_rules(world, player):
key_logic = world.key_logic[player] key_logic = world.key_logic[player]
eval_func = eval_small_key_door eval_func = eval_small_key_door
if world.key_logic_algorithm[player] == 'strict' and world.keyshuffle[player] == 'wild': if world.key_logic_algorithm[player] == 'strict' and world.keyshuffle[player] == 'wild':
eval_func = eval_small_key_door_strict eval_func = eval_small_key_door_strict
elif world.key_logic_algorithm[player] != 'default':
eval_func = eval_small_key_door_partial
for d_name, d_logic in key_logic.items(): for d_name, d_logic in key_logic.items():
for door_name, rule in d_logic.door_rules.items(): for door_name, rule in d_logic.door_rules.items():
door_entrance = world.get_entrance(door_name, player) door_entrance = world.get_entrance(door_name, player)
@@ -1896,6 +1898,36 @@ def eval_small_key_door_main(state, door_name, dungeon, player):
return door_openable return door_openable
def eval_small_key_door_partial_main(state, door_name, dungeon, player):
if state.is_door_open(door_name, player):
return True
key_logic = state.world.key_logic[player][dungeon]
if door_name not in key_logic.door_rules:
return False
door_rule = key_logic.door_rules[door_name]
door_openable = False
for ruleType, number in door_rule.new_rules.items():
if door_openable:
return True
if ruleType == KeyRuleType.WorstCase:
number = min(number, door_rule.small_key_num)
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
elif ruleType == KeyRuleType.AllowSmall:
small_loc_item = door_rule.small_location.item
if small_loc_item and small_loc_item.name == key_logic.small_key_name and small_loc_item.player == player:
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
elif isinstance(ruleType, tuple):
lock, lock_item = ruleType
# this doesn't track logical locks yet, i.e. hammer locks the item and hammer is there, but the item isn't
for loc in door_rule.alternate_big_key_loc:
spot = state.world.get_location(loc, player)
if spot.item and spot.item.name == lock_item:
number = min(number, door_rule.alternate_small_key)
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
break
return door_openable
def eval_small_key_door_strict_main(state, door_name, dungeon, player): def eval_small_key_door_strict_main(state, door_name, dungeon, player):
if state.is_door_open(door_name, player): if state.is_door_open(door_name, player):
return True return True
@@ -1910,6 +1942,10 @@ def eval_small_key_door(door_name, dungeon, player):
return lambda state: eval_small_key_door_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_main(state, door_name, dungeon, player)
def eval_small_key_door_partial(door_name, dungeon, player):
return lambda state: eval_small_key_door_partial_main(state, door_name, dungeon, player)
def eval_small_key_door_strict(door_name, dungeon, player): def eval_small_key_door_strict(door_name, dungeon, player):
return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player)

View File

@@ -424,14 +424,16 @@ LoadMapDarkOrMixed:
OWBonkGoodBeeDrop: OWBonkGoodBeeDrop:
{ {
LDA.l OWFlags+1 : AND.b #$02 : BNE .shuffled LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE .shuffled
.vanilla ; what we wrote over .vanilla ; what we wrote over
STZ.w $0DD0,X STZ.w $0DD0,X
LDA.l BottleContentsOne : ORA.l BottleContentsTwo LDA.l BottleContentsOne : ORA.l BottleContentsTwo
ORA.l BottleContentsThree : ORA.l BottleContentsFour ORA.l BottleContentsThree : ORA.l BottleContentsFour
RTL RTL
.shuffled .shuffled
PHY : TXY LDA.w $0DD0,X : BNE +
JMP .return+1
+ PHY : TXY
LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected
LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx
+ +
@@ -495,33 +497,37 @@ OWBonkGoodBeeDrop:
; spawn itemget item ; spawn itemget item
.spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected
PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return
+ LDA.b #$01 : STA !REDRAW + PHA
LDA.b #$01 : STA !FORCE_HEART_SPAWN
LDA.b #$EB : STA.l $7FFE00 LDA.b #$EB : STA.l $7FFE00
JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite
TYX : STZ.w $0F20,X ; layer the sprite is on LDA.b #$01 : STA.w !SPRITE_REDRAW,Y
PLA : STA.w $0E80,Y
; affects the rate the item moves in the Y/X direction ; affects the rate the item moves in the Y/X direction
STZ.w $0D40,X LDA.b #$00 : STA.w $0D40,Y
LDA.b #$0A : STA.w $0D50,Y LDA.b #$0A : STA.w $0D50,Y
LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch) LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch)
LDA.b #$FF : STA.w $0B58,Y ; stun timer LDA.b #$FF : STA.w $0B58,Y ; stun timer
LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means
LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on
; sets the tile type that is underneath the sprite, water ; sets the tile type that is underneath the sprite, water
LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this TYX : LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this
; sets OW event bitmask flag, uses free RAM ; sets OW event bitmask flag, uses free RAM
LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y
; determines the initial spawn point of item ; determines the initial spawn point of item
LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y
LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y
LDA.b #$01 : STA !REDRAW
.return .return
PLY PLY
LDA #$08 ; makes original good bee not spawn LDA #$08 ; makes original good bee not spawn
@@ -533,8 +539,10 @@ OWBonkDrops:
{ {
CMP.b #$D8 : BEQ + CMP.b #$D8 : BEQ +
RTL RTL
+ LDA.l OWFlags+1 : AND.b #!FLAG_OW_CROSSED : BNE + + LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE +
JSL.l Sprite_TransmuteToBomb : RTL JSL.l Sprite_TransmuteToBomb : RTL
+ LDA.w $0DD0,Y : BNE +
RTL
+ +
; loop thru rando bonk table to find match ; loop thru rando bonk table to find match
@@ -618,13 +626,17 @@ OWBonkDrops:
; spawn itemget item ; spawn itemget item
.spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2) .spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2)
PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2) PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2)
+ LDA 2,S : TAX : INX + PHA
LDA.b #$01 : STA !REDRAW LDA.b #$01 : STA !FORCE_HEART_SPAWN
LDA.b #$EB : STA.l $7FFE00 LDA.b #$EB : STA.l $7FFE00
JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite
LDA.b #$01 : STA.w !SPRITE_REDRAW,Y
PLA : STA.w $0E80,Y
; affects the rate the item moves in the Y/X direction ; affects the rate the item moves in the Y/X direction
LDA.b #$00 : STA.w $0D40,Y LDA.b #$00 : STA.w $0D40,Y
LDA.b #$0A : STA.w $0D50,Y LDA.b #$0A : STA.w $0D50,Y
@@ -637,14 +649,12 @@ OWBonkDrops:
; sets OW event bitmask flag, uses free RAM ; sets OW event bitmask flag, uses free RAM
PLA : STA.w $0ED0,Y ; S = X (row + 2) PLA : STA.w $0ED0,Y ; S = X (row + 2)
; determines the initial spawn point of item ; determines the initial spawn point of item
PLX : INX : INX : INX PLX : INX : INX : INX
LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y
LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y
LDA.b #$01 : STA !REDRAW
PLB : RTL PLB : RTL
.return .return
@@ -958,7 +968,9 @@ OWNewDestination:
OWLoadSpecialArea: OWLoadSpecialArea:
{ {
LDA.l Overworld_LoadSpecialOverworld_RoomId,X : STA.b $A0 LDA.l Overworld_LoadSpecialOverworld_RoomId,X : STA.b $A0
JSL Overworld_LoadSpecialOverworld ; sets M and X flags CMP.w #$0182 : BNE +
JSL ZoraSplashGfxFix
+ JSL Overworld_LoadSpecialOverworld ; sets M and X flags
TYX TYX
LDY.b #$00 LDY.b #$00
CPX.b #$01 : BNE + ; check if going to water transition CPX.b #$01 : BNE + ; check if going to water transition

Binary file not shown.

View File

@@ -287,13 +287,4 @@ def create_guiargs(parent):
guiargs = update_deprecated_args(guiargs) guiargs = update_deprecated_args(guiargs)
# Key drop shuffle stuff
if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro':
if guiargs.bow_mode == 'progressive':
guiargs.bow_mode = 'retro'
elif guiargs.bow_mode == 'silvers':
guiargs.bow_mode = 'retro_silvers'
guiargs.take_any = 'random' if guiargs.take_any == 'none' else guiargs.take_any
guiargs.keyshuffle = 'universal'
return guiargs return guiargs