Bringing in Unstable2 changes

This commit is contained in:
aerinon
2021-02-18 13:19:08 -07:00
13 changed files with 118 additions and 30 deletions

View File

@@ -148,7 +148,9 @@ class World(object):
region.world = self region.world = self
self._region_cache[region.player][region.name] = region self._region_cache[region.player][region.name] = region
for exit in region.exits: for exit in region.exits:
self._entrance_cache[(exit.name, exit.player)] = exit self._entrance_cache[exit.name, exit.player] = exit
for r_location in region.locations:
self._location_cache[r_location.name, r_location.player] = r_location
def initialize_doors(self, doors): def initialize_doors(self, doors):
for door in doors: for door in doors:

View File

@@ -2418,7 +2418,7 @@ interior_doors = [
('Skull Pull Switch S', 'Skull Big Chest N'), ('Skull Pull Switch S', 'Skull Big Chest N'),
('Skull Left Drop ES', 'Skull Compass Room WS'), ('Skull Left Drop ES', 'Skull Compass Room WS'),
('Skull 2 East Lobby NW', 'Skull Big Key SW'), ('Skull 2 East Lobby NW', 'Skull Big Key SW'),
('Skull Big Key WN', 'Skull Lone Pot EN'), ('Skull Big Key EN', 'Skull Lone Pot WN'),
('Skull Small Hall WS', 'Skull 2 West Lobby ES'), ('Skull Small Hall WS', 'Skull 2 West Lobby ES'),
('Skull 2 West Lobby NW', 'Skull X Room SW'), ('Skull 2 West Lobby NW', 'Skull X Room SW'),
('Skull 3 Lobby EN', 'Skull East Bridge WN'), ('Skull 3 Lobby EN', 'Skull East Bridge WN'),

View File

@@ -541,8 +541,8 @@ def create_doors(world, player):
create_door(player, 'Skull 2 East Lobby WS', Nrml).dir(We, 0x57, Bot, High).pos(4), create_door(player, 'Skull 2 East Lobby WS', Nrml).dir(We, 0x57, Bot, High).pos(4),
create_door(player, 'Skull 2 East Lobby NW', Intr).dir(No, 0x57, Left, High).pos(1), create_door(player, 'Skull 2 East Lobby NW', Intr).dir(No, 0x57, Left, High).pos(1),
create_door(player, 'Skull Big Key SW', Intr).dir(So, 0x57, Left, High).pos(1), create_door(player, 'Skull Big Key SW', Intr).dir(So, 0x57, Left, High).pos(1),
create_door(player, 'Skull Big Key WN', Intr).dir(We, 0x57, Top, High).pos(0), create_door(player, 'Skull Big Key EN', Intr).dir(Ea, 0x57, Top, High).pos(0),
create_door(player, 'Skull Lone Pot EN', Intr).dir(Ea, 0x57, Top, High).pos(0), create_door(player, 'Skull Lone Pot WN', Intr).dir(We, 0x57, Top, High).pos(0),
create_door(player, 'Skull Small Hall ES', Nrml).dir(Ea, 0x56, Bot, High).pos(3), create_door(player, 'Skull Small Hall ES', Nrml).dir(Ea, 0x56, Bot, High).pos(3),
create_door(player, 'Skull Small Hall WS', Intr).dir(We, 0x56, Bot, High).pos(2), create_door(player, 'Skull Small Hall WS', Intr).dir(We, 0x56, Bot, High).pos(2),
create_door(player, 'Skull 2 West Lobby S', Nrml).dir(So, 0x56, Left, High).pos(1).portal(Z, 0x00), create_door(player, 'Skull 2 West Lobby S', Nrml).dir(So, 0x56, Left, High).pos(1).portal(Z, 0x00),
@@ -1304,7 +1304,6 @@ def create_doors(world, player):
world.get_door('GT Petting Zoo SE', player).dead_end() world.get_door('GT Petting Zoo SE', player).dead_end()
world.get_door('GT DMs Room SW', player).dead_end() world.get_door('GT DMs Room SW', player).dead_end()
world.get_door("GT Bob\'s Room SE", player).passage = False world.get_door("GT Bob\'s Room SE", player).passage = False
world.get_door('PoD Mimics 2 SW', player).bk_shuffle_req = True
world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo) world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo)
world.get_door('Swamp Lobby S', player).standard_restricted = True # key-drop note (todo) world.get_door('Swamp Lobby S', player).standard_restricted = True # key-drop note (todo)

View File

@@ -579,7 +579,7 @@ def progressive_ctr(new_counter, last_counter):
def unique_child_door(child, key_counter): def unique_child_door(child, key_counter):
if child in key_counter.child_doors or child.dest in key_counter.child_doors: if child in key_counter.child_doors or child.dest in key_counter.child_doors:
return False return False
if child in key_counter.open_doors or child.dest in key_counter.child_doors: if child in key_counter.open_doors or child.dest in key_counter.open_doors:
return False return False
if child.bigKey and key_counter.big_key_opened: if child.bigKey and key_counter.big_key_opened:
return False return False
@@ -589,7 +589,7 @@ def unique_child_door(child, key_counter):
def unique_child_door_2(child, key_counter): def unique_child_door_2(child, key_counter):
if child in key_counter.child_doors or child.dest in key_counter.child_doors: if child in key_counter.child_doors or child.dest in key_counter.child_doors:
return False return False
if child in key_counter.open_doors or child.dest in key_counter.child_doors: if child in key_counter.open_doors or child.dest in key_counter.open_doors:
return False return False
return True return True
@@ -1463,7 +1463,10 @@ def create_odd_key_counter(door, parent_counter, key_layout, world, player):
next_counter = find_next_counter(door, parent_counter, key_layout) next_counter = find_next_counter(door, parent_counter, key_layout)
odd_counter.free_locations = dict_difference(next_counter.free_locations, parent_counter.free_locations) odd_counter.free_locations = dict_difference(next_counter.free_locations, parent_counter.free_locations)
odd_counter.key_only_locations = dict_difference(next_counter.key_only_locations, parent_counter.key_only_locations) odd_counter.key_only_locations = dict_difference(next_counter.key_only_locations, parent_counter.key_only_locations)
odd_counter.child_doors = dict_difference(next_counter.child_doors, parent_counter.child_doors) odd_counter.child_doors = {}
for d in next_counter.child_doors:
if d not in parent_counter.child_doors and (d.type == DoorType.SpiralStairs or d.dest not in parent_counter.child_doors):
odd_counter.child_doors[d] = None
odd_counter.other_locations = dict_difference(next_counter.other_locations, parent_counter.other_locations) odd_counter.other_locations = dict_difference(next_counter.other_locations, parent_counter.other_locations)
odd_counter.important_locations = dict_difference(next_counter.important_locations, parent_counter.important_locations) odd_counter.important_locations = dict_difference(next_counter.important_locations, parent_counter.important_locations)
for loc in odd_counter.other_locations: for loc in odd_counter.other_locations:

View File

@@ -401,12 +401,13 @@ def copy_world(world):
copied_shop.inventory = copy.copy(shop.inventory) copied_shop.inventory = copy.copy(shop.inventory)
# connect copied world # connect copied world
copied_locations = {(loc.name, loc.player): loc for loc in ret.get_locations()} # caches all locations
for region in world.regions: for region in world.regions:
copied_region = ret.get_region(region.name, region.player) copied_region = ret.get_region(region.name, region.player)
copied_region.is_light_world = region.is_light_world copied_region.is_light_world = region.is_light_world
copied_region.is_dark_world = region.is_dark_world copied_region.is_dark_world = region.is_dark_world
copied_region.dungeon = region.dungeon copied_region.dungeon = region.dungeon
copied_region.locations = [ret.get_location(location.name, location.player) for location in region.locations] copied_region.locations = [copied_locations[(location.name, location.player)] for location in region.locations]
for entrance in region.entrances: for entrance in region.entrances:
ret.get_entrance(entrance.name, entrance.player).connect(copied_region) ret.get_entrance(entrance.name, entrance.player).connect(copied_region)

View File

@@ -122,15 +122,32 @@ Added to CLI only now.
The Mystery.py file has been updated for those who like to use that for generating games. Supports keydropshuffle, The Mystery.py file has been updated for those who like to use that for generating games. Supports keydropshuffle,
shopsanity, and other settings that have been included. shopsanity, and other settings that have been included.
## Experimental Item Counter
New item counter modified to show total
# Bug Fixes # Bug Fixes
* 0.3.1.1-u * 0.3.1.0-u
* Shopsanity introduced
* Minor fix to Standard generation
* 0.3.0.4-u
* QoL fixes from Mike
* Allow PoD Mimics 2 as a lobby in non-keysanity seeds (Thanks @Catobat)
* Fix for double-counting Hera key in keydropshuffle
* 0.3.0.3-u
* Disallowed Swamp Lobby in Hyrule Castle in Standard mode * Disallowed Swamp Lobby in Hyrule Castle in Standard mode
* Prevent defeating Aga 1 before Zelda is delivered to the Sanctuary. (He can't take damage) * Prevent defeating Aga 1 before Zelda is delivered to the Sanctuary. (He can't take damage)
* Fix for Ice Jelly room when going backward and enemizer is on * Fix for Ice Jelly room when going backward and enemizer is on
* Fix for inverted - don't start as a bunny in Dark Sanctuary * Fix for inverted - don't start as a bunny in Dark Sanctuary
* Fix for non-ER Inverted with Lobby shuffle. Aga Tower's exit works properly now. * Fix for non-ER Inverted with Lobby shuffle. Aga Tower's exit works properly now.
* Minor fix to Standard generation * Fix for In-Room Stairs with Trap Doors
* Key logic fix
* Fix for door gen re-start
* More lenient keys in DR+Retro
* Fix for shufflepots option
* 0.3.0.2-u
* Introduced in-room staircases/ladders
* 0.3.0.1-u * 0.3.0.1-u
* Problem with lobbies on re-rolls corrected * Problem with lobbies on re-rolls corrected
* Potential playthrough problem addressed * Potential playthrough problem addressed

View File

@@ -473,8 +473,8 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'Skull Compass Room', 'Skull Woods', ['Skull Woods - Compass Chest'], ['Skull Compass Room NE', 'Skull Compass Room ES', 'Skull Compass Room WS']), create_dungeon_region(player, 'Skull Compass Room', 'Skull Woods', ['Skull Woods - Compass Chest'], ['Skull Compass Room NE', 'Skull Compass Room ES', 'Skull Compass Room WS']),
create_dungeon_region(player, 'Skull Left Drop', 'Skull Woods', None, ['Skull Left Drop ES']), create_dungeon_region(player, 'Skull Left Drop', 'Skull Woods', None, ['Skull Left Drop ES']),
create_dungeon_region(player, 'Skull 2 East Lobby', 'Skull Woods', None, ['Skull 2 East Lobby NW', 'Skull 2 East Lobby WS', 'Skull 2 East Lobby SW']), create_dungeon_region(player, 'Skull 2 East Lobby', 'Skull Woods', None, ['Skull 2 East Lobby NW', 'Skull 2 East Lobby WS', 'Skull 2 East Lobby SW']),
create_dungeon_region(player, 'Skull Big Key', 'Skull Woods', ['Skull Woods - Big Key Chest'], ['Skull Big Key SW', 'Skull Big Key WN']), create_dungeon_region(player, 'Skull Big Key', 'Skull Woods', ['Skull Woods - Big Key Chest'], ['Skull Big Key SW', 'Skull Big Key EN']),
create_dungeon_region(player, 'Skull Lone Pot', 'Skull Woods', None, ['Skull Lone Pot EN']), create_dungeon_region(player, 'Skull Lone Pot', 'Skull Woods', None, ['Skull Lone Pot WN']),
create_dungeon_region(player, 'Skull Small Hall', 'Skull Woods', None, ['Skull Small Hall ES', 'Skull Small Hall WS']), create_dungeon_region(player, 'Skull Small Hall', 'Skull Woods', None, ['Skull Small Hall ES', 'Skull Small Hall WS']),
create_dungeon_region(player, 'Skull Back Drop', 'Skull Woods', None, ['Skull Back Drop Star Path', ]), create_dungeon_region(player, 'Skull Back Drop', 'Skull Woods', None, ['Skull Back Drop Star Path', ]),
create_dungeon_region(player, 'Skull 2 West Lobby', 'Skull Woods', ['Skull Woods - West Lobby Pot Key'], ['Skull 2 West Lobby ES', 'Skull 2 West Lobby NW', 'Skull 2 West Lobby S']), create_dungeon_region(player, 'Skull 2 West Lobby', 'Skull Woods', ['Skull Woods - West Lobby Pot Key'], ['Skull 2 West Lobby ES', 'Skull 2 West Lobby NW', 'Skull 2 West Lobby S']),

4
Rom.py
View File

@@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '6a4096235f682b7e4e1a65f274c7037b' RANDOMIZERBASEHASH = '0a34dc667a29125f09b10aeb1e06b83c'
class JsonRom(object): class JsonRom(object):
@@ -942,8 +942,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if difficulty.progressive_bow_limit < 2 and world.swords == 'swordless': if difficulty.progressive_bow_limit < 2 and world.swords == 'swordless':
rom.write_bytes(0x180098, [2, overflow_replacement]) rom.write_bytes(0x180098, [2, overflow_replacement])
rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon
rom.write_byte(0x180182, 0x00) # Don't auto equip silvers on pickup
# set up game internal RNG seed # set up game internal RNG seed
for i in range(1024): for i in range(1024):

View File

@@ -200,3 +200,14 @@ $bc - TT 188 idx 1
; called by 10CE2, (Dungeon_SpiralStaircase_3) ; called by 10CE2, (Dungeon_SpiralStaircase_3)
;122f0 ;122f0
Link's position after screen transition and auto-walk (from $02C034):
0C 20 30 38 48 ; down
D4 D8 C0 C0 A8 ; up
0C 18 28 30 40 ; right
E4 D8 C8 C0 B0 ; left
Effectively indexed by $0418*#$05+$4E.
Row ($0418) is the direction and column ($4E) determines how far to auto-walk (depends on tile attribute at edge of screen).
From left to right: edge, inside high door, outside high door, inside low door and outside low door.

View File

@@ -170,10 +170,10 @@ InroomStairsWarp: {
; should be the same as lda $0462 : and #$04 : lsr #2 : eor #$01 : sta $07 ; should be the same as lda $0462 : and #$04 : lsr #2 : eor #$01 : sta $07
lda $01 : and #$80 : beq .notEdge lda $01 : and #$80 : beq .notEdge
lda $07 : sta $03 : beq + lda $07 : sta $03 : beq +
lda $01 : jsr LoadSouthMidpoint : sta $22 : lda #$e0 lda $01 : jsr LoadSouthMidpoint : sta $22 : lda #$f4
bra ++ bra ++
+ +
lda $01 : jsr LoadNorthMidpoint : sta $22 : lda #$1b lda $01 : jsr LoadNorthMidpoint : sta $22 : dec $21 : lda #$f7
++ ++
sta $20 sta $20
lda $01 : and #$20 : beq + lda $01 : and #$20 : beq +
@@ -185,25 +185,35 @@ InroomStairsWarp: {
brl .layer brl .layer
.notEdge .notEdge
lda $01 : and #$03 : cmp #$03 : bne .normal lda $01 : and #$03 : cmp #$03 : bne .normal
txa : and #$06 : sta $07
lda $01 : and #$30 : lsr #3 : tay lda $01 : and #$30 : lsr #3 : tay
lda.w InroomStairsX,y : sta $22
lda.w InroomStairsX+1,y : sta $02 lda.w InroomStairsX+1,y : sta $02
lda.w InroomStairsY+1,y : sta $03 lda.w InroomStairsY+1,y : sta $03
cpy $07 : beq .vanillaTransition
lda.w InroomStairsX,y : sta $22
lda.w InroomStairsY,y lda.w InroomStairsY,y
ldy $07 : beq + ldy $07 : beq +
!add #$07 !add #$07
+ +
sta $20 sta $20
%StonewallCheck($1b)
inc $07 inc $07
bra ++
.vanillaTransition
lda #$c0 : sta $07 ; leave camera
++
%StonewallCheck($1b)
lda $01 : and #$04 : lsr #2 lda $01 : and #$04 : lsr #2
bra .layer bra .layer
.normal .normal
lda $01 : sta $fe ; trap door lda $01 : sta $fe ; trap door
lda $07 : sta $03 : beq + lda $07 : sta $03 : beq +
ldy $a0 : cpy #$51 : beq .specialFix ; throne room
cpy #$02 : beq .specialFix ; sewers pull switch
cpy #$71 : beq .specialFix ; castle armory
lda #$e0 lda #$e0
ldy $a0 : cpy #$51 : bne ++ ; special fix for throne room bra ++
!sub #$18 .specialFix
lda #$c8
bra ++ bra ++
+ +
%StonewallCheck($43) %StonewallCheck($43)
@@ -235,12 +245,15 @@ InroomStairsWarp: {
ldy #$01 : jsr ShiftQuadSimple ldy #$01 : jsr ShiftQuadSimple
.skipYQuad .skipYQuad
lda $07 : bmi .skipCamera
ldy #$00 : jsr SetCamera ; horizontal camera ldy #$00 : jsr SetCamera ; horizontal camera
ldy #$01 : sty $07 : jsr SetCamera ; vertical camera ldy #$01 : sty $07 : jsr SetCamera ; vertical camera
lda $20 : cmp #$e0 : bcc + lda $20 : cmp #$e0 : bcc +
lda $e8 : bne + lda $e8 : bne +
lda #$10 : sta $e8 ; adjust vertical camera at bottom lda #$10 : sta $e8 ; adjust vertical camera at bottom
+ +
.skipCamera
jsr StairCleanup jsr StairCleanup
ply : plx : plb ; pull the stuff we pushed ply : plx : plb ; pull the stuff we pushed
rts rts

Binary file not shown.

View File

@@ -43,7 +43,7 @@ class SpriteSelector(object):
# Open SpriteSomething directory for Link sprites # Open SpriteSomething directory for Link sprites
def open_spritesomething_listing(_evt): def open_spritesomething_listing(_evt):
webbrowser.open("https://artheau.github.io/SpriteSomething/resources/app/snes/zelda3/link/sprites.html") webbrowser.open("https://miketrethewey.github.io/SpriteSomething-collections/snes/zelda3/link/")
official_frametitle = Frame(self.window) official_frametitle = Frame(self.window)
official_title_text = Label(official_frametitle, text="Official Sprites") official_title_text = Label(official_frametitle, text="Official Sprites")

View File

@@ -1,8 +1,11 @@
from tkinter import ttk, filedialog, StringVar, Button, Entry, Frame, Label, E, W, LEFT, X from tkinter import ttk, filedialog, StringVar, Button, Entry, Frame, Label, E, W, LEFT, X, Text, Tk, INSERT
import source.classes.diags as diagnostics
import source.gui.widgets as widgets import source.gui.widgets as widgets
import json import json
import os import os
from functools import partial
from source.classes.Empty import Empty from source.classes.Empty import Empty
from Main import __version__
def generation_page(parent,settings): def generation_page(parent,settings):
# Generation Setup # Generation Setup
@@ -76,4 +79,45 @@ def generation_page(parent,settings):
# frame: pack # frame: pack
self.widgets[widget].pieces["frame"].pack(fill=X) self.widgets[widget].pieces["frame"].pack(fill=X)
## Run Diagnostics
# This one's more-complicated, build it and stuff it
# widget ID
widget = "diags"
# Empty object
self.widgets[widget] = Empty()
# pieces
self.widgets[widget].pieces = {}
# frame
self.frames["diags"] = Frame(self)
self.frames["diags"].pack()
self.widgets[widget].pieces["frame"] = Frame(self.frames["diags"])
def diags():
# Debugging purposes
dims = {
"window": {
"width": 800,
"height": 500
},
"textarea.characters": {
"width": 120,
"height": 50
}
}
diag = Tk()
diag.title("Door Shuffle " + __version__)
diag.geometry(str(dims["window"]["width"]) + 'x' + str(dims["window"]["height"]))
text = Text(diag, width=dims["textarea.characters"]["width"], height=dims["textarea.characters"]["height"])
text.pack()
text.insert(INSERT,"\n".join(diagnostics.output(__version__)))
# dialog button
self.widgets[widget].pieces["button"] = Button(self.widgets[widget].pieces["frame"], text='Run Diagnostics', command=partial(diags))
# button: pack
self.widgets[widget].pieces["button"].pack(side=LEFT)
# frame: pack
self.widgets[widget].pieces["frame"].pack(fill=X)
return self,settings return self,settings