Lots of bugfixes - see notes
This commit is contained in:
@@ -476,7 +476,7 @@ class CollectionState(object):
|
||||
new_crystal_state = crystal_state
|
||||
for exit in new_region.exits:
|
||||
door = exit.door
|
||||
if door is not None and door.crystal == CrystalBarrier.Either:
|
||||
if door is not None and door.crystal == CrystalBarrier.Either and door.entrance.can_reach(self):
|
||||
new_crystal_state = CrystalBarrier.Either
|
||||
break
|
||||
if new_region in rrp:
|
||||
@@ -487,7 +487,7 @@ class CollectionState(object):
|
||||
for exit in new_region.exits:
|
||||
door = exit.door
|
||||
if door is not None and not door.blocked:
|
||||
door_crystal_state = new_crystal_state & (door.crystal or CrystalBarrier.Either)
|
||||
door_crystal_state = door.crystal if door.crystal else new_crystal_state
|
||||
bc[exit] = door_crystal_state
|
||||
queue.append((exit, door_crystal_state))
|
||||
elif door is None:
|
||||
@@ -1906,7 +1906,8 @@ class Spoiler(object):
|
||||
'enemy_damage': self.world.enemy_damage,
|
||||
'players': self.world.players,
|
||||
'teams': self.world.teams,
|
||||
'experimental' : self.world.experimental
|
||||
'experimental': self.world.experimental,
|
||||
'keydropshuffle': self.world.keydropshuffle,
|
||||
}
|
||||
|
||||
def to_json(self):
|
||||
@@ -1967,6 +1968,7 @@ class Spoiler(object):
|
||||
outfile.write('Enemy damage: %s\n' % self.metadata['enemy_damage'][player])
|
||||
outfile.write('Hints: %s\n' % ('Yes' if self.metadata['hints'][player] else 'No'))
|
||||
outfile.write('Experimental: %s\n' % ('Yes' if self.metadata['experimental'][player] else 'No'))
|
||||
outfile.write('Key Drops shuffled: %s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No'))
|
||||
if self.doors:
|
||||
outfile.write('\n\nDoors:\n\n')
|
||||
outfile.write('\n'.join(
|
||||
|
||||
@@ -41,6 +41,8 @@ def link_doors(world, player):
|
||||
for entrance, ext in straight_staircases:
|
||||
connect_two_way(world, entrance, ext, player)
|
||||
|
||||
connect_custom(world, player)
|
||||
|
||||
find_inaccessible_regions(world, player)
|
||||
|
||||
if world.intensity[player] >= 3 and world.doorShuffle[player] in ['basic', 'crossed']:
|
||||
@@ -197,6 +199,12 @@ def convert_key_doors(k_doors, world, player):
|
||||
return result
|
||||
|
||||
|
||||
def connect_custom(world, player):
|
||||
if hasattr(world, 'custom_doors') and world.custom_doors[player]:
|
||||
for entrance, ext in world.custom_doors[player]:
|
||||
connect_two_way(world, entrance, ext, player)
|
||||
|
||||
|
||||
def connect_simple_door(world, exit_name, region_name, player):
|
||||
region = world.get_region(region_name, player)
|
||||
world.get_entrance(exit_name, player).connect(region)
|
||||
|
||||
@@ -564,6 +564,8 @@ def determine_paths_for_dungeon(world, player, all_regions, name):
|
||||
paths.append(('Hyrule Dungeon Cellblock', 'Sanctuary'))
|
||||
if world.doorShuffle[player] in ['basic'] and name == 'Thieves Town':
|
||||
paths.append('Thieves Attic Window')
|
||||
elif 'Thieves Attic Window' in all_r_names:
|
||||
paths.append('Thieves Attic Window')
|
||||
for boss in boss_path_checks:
|
||||
if boss in all_r_names:
|
||||
paths.append(boss)
|
||||
@@ -1260,6 +1262,9 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player,
|
||||
sector = find_sector(r_name, all_sectors)
|
||||
reverse_d_map[sector] = key
|
||||
|
||||
complete_dungeons = {x: y for x, y in dungeon_map.items() if sum(len(sector.outstanding_doors) for sector in y.sectors) <= 0}
|
||||
[dungeon_map.pop(key) for key in complete_dungeons.keys()]
|
||||
|
||||
# categorize sectors
|
||||
identify_destination_sectors(accessible_sectors, reverse_d_map, dungeon_map, connections,
|
||||
dungeon_entrances, split_dungeon_entrances)
|
||||
@@ -1315,6 +1320,7 @@ def create_dungeon_builders(all_sectors, connections_tuple, world, player,
|
||||
assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, builder_info)
|
||||
# the rest
|
||||
assign_the_rest(dungeon_map, neutral_sectors, global_pole, builder_info)
|
||||
dungeon_map.update(complete_dungeons)
|
||||
finished = True
|
||||
except NeutralizingException:
|
||||
pass
|
||||
|
||||
20
ItemList.py
20
ItemList.py
@@ -6,7 +6,7 @@ from BaseClasses import Region, RegionType, Shop, ShopType, Location
|
||||
from Bosses import place_bosses
|
||||
from Dungeons import get_dungeon_item_pool
|
||||
from EntranceShuffle import connect_entrance
|
||||
from Fill import FillError, fill_restrictive
|
||||
from Fill import FillError, fill_restrictive, fast_fill
|
||||
from Items import ItemFactory
|
||||
|
||||
import source.classes.constants as CONST
|
||||
@@ -738,3 +738,21 @@ def test():
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
|
||||
|
||||
def fill_specific_items(world):
|
||||
keypool = [item for item in world.itempool if item.smallkey]
|
||||
cage = world.get_location('Tower of Hera - Basement Cage', 1)
|
||||
c_dungeon = cage.parent_region.dungeon
|
||||
key_item = next(x for x in keypool if c_dungeon.name in x.name or (c_dungeon.name == 'Hyrule Castle' and 'Escape' in x.name))
|
||||
world.itempool.remove(key_item)
|
||||
all_state = world.get_all_state(True)
|
||||
fill_restrictive(world, all_state, [cage], [key_item])
|
||||
|
||||
# somaria = next(item for item in world.itempool if item.name == 'Cane of Somaria')
|
||||
# shooter = world.get_location('Palace of Darkness - Shooter Room', 1)
|
||||
# world.itempool.remove(somaria)
|
||||
# all_state = world.get_all_state(True)
|
||||
# fill_restrictive(world, all_state, [shooter], [somaria])
|
||||
|
||||
|
||||
|
||||
7
Main.py
7
Main.py
@@ -21,10 +21,10 @@ from RoomData import create_rooms
|
||||
from Rules import set_rules
|
||||
from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive
|
||||
from Fill import distribute_items_cutoff, distribute_items_staleness, distribute_items_restrictive, flood_items, balance_multiworld_progression
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes, fill_specific_items
|
||||
from Utils import output_path, parse_player_names
|
||||
|
||||
__version__ = '0.2.0.7-u'
|
||||
__version__ = '0.2.0.8-u'
|
||||
|
||||
class EnemizerError(RuntimeError):
|
||||
pass
|
||||
@@ -139,6 +139,9 @@ def main(args, seed=None, fish=None):
|
||||
|
||||
fill_prizes(world)
|
||||
|
||||
# used for debugging
|
||||
# fill_specific_items(world)
|
||||
|
||||
logger.info(world.fish.translate("cli","cli","placing.dungeon.items"))
|
||||
|
||||
shuffled_locations = None
|
||||
|
||||
@@ -3,14 +3,19 @@
|
||||
* Lobby shuffle added as Intensity level 3
|
||||
* Can now be found in the spoiler
|
||||
* Known issues:
|
||||
* If a dungeon is vanilla in ER and Sanc is in that dungeon and the dungeon has an entrance that needs to let link out: is broken.
|
||||
* e.g. PoD, GT, TR
|
||||
* Some TR lobbies that need a bomb aren't pre-opened.
|
||||
* Palettes aren't perfect - may add Sanctuary and Sewer palette back. May add a way to turn off palette "fixing"
|
||||
* Certain hints in ER due to lobby changes
|
||||
* Some ugly colors
|
||||
* Invisible floors can be see in many palettes
|
||||
* Animated tiles aren't loaded correctly in lobbies
|
||||
* If a wallmaster grabs you and the lobby is dark, the lamp doesn't turn on
|
||||
* --keydropshuffle added (coming to the GUI soon). This add 33 new locations to the game where keys are found under pots
|
||||
and where enemies drop keys. This includes 32 small key location and the ball and chain guard who normally drop the HC
|
||||
Big Key.
|
||||
* Multiworld untested - May need changes to MultiClient/MultiServer to recognize new locations
|
||||
* Overall location count updated
|
||||
* Setting mentioned in spoiler
|
||||
* GT Big Key count / total location count needs to be updated
|
||||
* --mixed_travel setting added
|
||||
* Due to Hammerjump, Hovering in PoD Arena, and the Mire Big Key Chest bomb jump two sections of a supertile that are
|
||||
@@ -30,14 +35,24 @@ otherwise unconnected logically can be reach using these glitches. To prevent th
|
||||
|
||||
# Bug Fixes
|
||||
|
||||
* Fixed a situation where logic did not account properly for Big Key doors in standard Hyrule Castle
|
||||
* Fixed a problem ER shuffle generation that did not account for lobbies moving around
|
||||
* Fixed a problem with camera unlock (GT Mimics and Mire Minibridge)
|
||||
* Fixed a problem with bad-pseudo layer at PoD map Balcony (unable to hit switch with Bomb)
|
||||
* Fixed a problem with the Ganon hint when hints are turned off
|
||||
* 2.0.8-u
|
||||
* Player sprite disappears after picking up a key drop in keydropshuffle
|
||||
* Sewers and Hyrule Castle compass problems
|
||||
* Double count of the Hera Basement Cage item (both overall and compass)
|
||||
* Unnecessary/inconsistent rug cutoff
|
||||
* TR Crystal Maze thought you get through backwards without Somaria
|
||||
* Ensure Thieves Attic Window area can always be reached
|
||||
* Fixed where HC big key was not counted
|
||||
* Prior fixes
|
||||
* Fixed a situation where logic did not account properly for Big Key doors in standard Hyrule Castle
|
||||
* Fixed a problem ER shuffle generation that did not account for lobbies moving around
|
||||
* Fixed a problem with camera unlock (GT Mimics and Mire Minibridge)
|
||||
* Fixed a problem with bad-pseudo layer at PoD map Balcony (unable to hit switch with Bomb)
|
||||
* Fixed a problem with the Ganon hint when hints are turned off
|
||||
|
||||
# Known Issues
|
||||
|
||||
(I'm planning to fix theese in this Unstable iteration hopefully)
|
||||
|
||||
* Backward TR Crystal Maze locking Somaria
|
||||
* Multiworld = /missing command not working
|
||||
* Potenial keylocks in multi-entrance dungeons
|
||||
* Incorrect vanilla keylogic for Mire
|
||||
* ER - Potential for Skull Woods West to be completely inaccessible in non-beatable logic
|
||||
24
Rom.py
24
Rom.py
@@ -24,7 +24,7 @@ from EntranceShuffle import door_addresses, exit_ids
|
||||
|
||||
|
||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||
RANDOMIZERBASEHASH = '78947c3825898cac3ab57cbe44b50390'
|
||||
RANDOMIZERBASEHASH = 'fb2886fc00a7736369ce6ba90b526bc9'
|
||||
|
||||
|
||||
class JsonRom(object):
|
||||
@@ -709,8 +709,21 @@ def patch_rom(world, rom, player, team, enemized):
|
||||
|
||||
write_custom_shops(rom, world, player)
|
||||
|
||||
def credits_digit(num):
|
||||
# top: $54 is 1, 55 2, etc , so 57=4, 5C=9
|
||||
# bot: $7A is 1, 7B is 2, etc so 7D=4, 82=9 (zero unknown...)
|
||||
return 0x53+num, 0x79+num
|
||||
|
||||
if world.keydropshuffle[player]:
|
||||
rom.write_byte(0x140000, 1)
|
||||
mid_top, mid_bot = credits_digit(4)
|
||||
last_top, last_bot = credits_digit(9)
|
||||
# top half
|
||||
rom.write_byte(0x118C53, mid_top)
|
||||
rom.write_byte(0x118C54, last_top)
|
||||
# bottom half
|
||||
rom.write_byte(0x118C71, mid_bot)
|
||||
rom.write_byte(0x118C72, last_bot)
|
||||
|
||||
# patch medallion requirements
|
||||
if world.required_medallions[player][0] == 'Bombos':
|
||||
@@ -765,7 +778,7 @@ def patch_rom(world, rom, player, team, enemized):
|
||||
TRIFORCE_PIECE = ItemFactory('Triforce Piece', player).code
|
||||
GREEN_CLOCK = ItemFactory('Green Clock', player).code
|
||||
|
||||
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
|
||||
rom.write_byte(0x18004F, 0x01) # Byrna Invulnerability: on
|
||||
|
||||
# handle difficulty_adjustments
|
||||
if world.difficulty_adjustments[player] == 'hard':
|
||||
@@ -2210,11 +2223,18 @@ def patch_shuffled_dark_sanc(world, rom, player):
|
||||
|
||||
def update_compasses(rom, world, player):
|
||||
layouts = world.dungeon_layouts[player]
|
||||
provided_dungeon = False
|
||||
for name, builder in layouts.items():
|
||||
dungeon_id = compass_data[name][4]
|
||||
rom.write_byte(0x187000 + dungeon_id//2, builder.location_cnt)
|
||||
if builder.bk_provided:
|
||||
if provided_dungeon:
|
||||
logging.getLogger('').warning('Multiple dungeons have forced BKs! Compass code might need updating?')
|
||||
rom.write_byte(0x186FFF, dungeon_id)
|
||||
provided_dungeon = True
|
||||
if not provided_dungeon:
|
||||
rom.write_byte(0x186FFF, 0xff)
|
||||
|
||||
|
||||
|
||||
InconvenientDungeonEntrances = {'Turtle Rock': 'Turtle Rock Main',
|
||||
|
||||
@@ -139,6 +139,14 @@ org $019dbd ; <- Bank01.asm : 4465 of Object_Draw8xN (LDA $9B52, Y : STA $7E2000
|
||||
jsl CutoffEntranceRug : bra .nextTile : nop
|
||||
.nextTile
|
||||
|
||||
;maybe set 02e2 to 0
|
||||
|
||||
org $0799de ; <- Bank07.asm : 4088 (LDA.b #$15 : STA $5D)
|
||||
JSL StoreTempBunnyState
|
||||
;
|
||||
org $08c450 ; <- ancilla_receive_item.asm : 146-148 (STY $5D : STZ $02D8)
|
||||
JSL RetrieveBunnyState : NOP
|
||||
|
||||
; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire
|
||||
; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes
|
||||
; Hera BK door back can be seen with Pot clipping - likely useful for no logic seeds
|
||||
|
||||
@@ -116,10 +116,12 @@ KeyGet:
|
||||
lda $7ef36f ; what we wrote over
|
||||
pha
|
||||
lda.l ShuffleKeyDrops : bne +
|
||||
pla : rtl
|
||||
+
|
||||
ldy $0e80, x
|
||||
phy
|
||||
- pla : rtl
|
||||
+ ldy $0e80, x
|
||||
lda $a0 : cmp #$87 : bne +
|
||||
jsr ShouldKeyBeCountedForDungeon : bcc -
|
||||
jsl CountChestKeyLong : bra -
|
||||
+ phy
|
||||
jsr KeyGetPlayer : sta !MULTIWORLD_ITEM_PLAYER_ID
|
||||
jsl.l $0791b3 ; Player_HaltDashAttackLong
|
||||
jsl.l Link_ReceiveItem
|
||||
@@ -136,6 +138,16 @@ KeyGet:
|
||||
pla : dec : rtl
|
||||
}
|
||||
|
||||
; Input Y - the item type
|
||||
ShouldKeyBeCountedForDungeon:
|
||||
{
|
||||
phx
|
||||
lda $040c : lsr : tax
|
||||
tya : cmp KeyTable, x : bne +
|
||||
- plx : sec : rts
|
||||
+ cmp #$24 : beq -
|
||||
plx : clc : rts
|
||||
}
|
||||
|
||||
BigKeyGet:
|
||||
{
|
||||
|
||||
@@ -88,6 +88,7 @@ SuctionOverworldFix:
|
||||
CutoffRooms:
|
||||
db $bc, $a2, $1a, $49, $14, $8c, $9f, $c2
|
||||
db $66, $5d, $a8
|
||||
; Don't forget CutoffRoomCount!!!
|
||||
|
||||
CutoffEntranceRug:
|
||||
pha : phx
|
||||
@@ -96,7 +97,7 @@ CutoffEntranceRug:
|
||||
cmp #$000C : bne .norm
|
||||
+ lda $a0 : sep #$20 : ldx #$0000
|
||||
- cmp.l CutoffRooms, x : beq .check
|
||||
inx : cpx #$0009 : !blt - ; CutoffRoom Count is here!
|
||||
inx : cpx #$000B : !blt - ; CutoffRoomCount is here!
|
||||
rep #$20
|
||||
.norm plx : pla : lda $9B52, y : sta $7E2000, x ; what we wrote over
|
||||
rtl
|
||||
@@ -108,3 +109,15 @@ rtl
|
||||
bra .norm
|
||||
.skip plx : pla : rtl
|
||||
|
||||
|
||||
StoreTempBunnyState:
|
||||
LDA $5D : CMP #$1C : BNE +
|
||||
STA $5F
|
||||
+ LDA #$15 : STA $5D ; what we wrote over
|
||||
RTL
|
||||
|
||||
RetrieveBunnyState:
|
||||
STY $5D : STZ $02D8 ; what we wrote over
|
||||
LDA $5F : BEQ +
|
||||
STA $5D
|
||||
+ RTL
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user