Merged in DR v1.4.1.10

This commit is contained in:
codemann8
2024-04-18 09:56:12 -05:00
11 changed files with 81 additions and 23 deletions

View File

@@ -26,7 +26,7 @@ jobs:
# os & python versions
strategy:
matrix:
os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ]
os-name: [ ubuntu-latest, ubuntu-20.04, macOS-latest, windows-latest ]
python-version: [ 3.9 ]
# needs: [ install-test ]
steps:
@@ -110,7 +110,7 @@ jobs:
strategy:
matrix:
# install/release on not bionic
os-name: [ ubuntu-latest, ubuntu-18.04, macOS-latest, windows-latest ]
os-name: [ ubuntu-latest, ubuntu-20.04, macOS-latest, windows-latest ]
python-version: [ 3.9 ]
needs: [ install-build ]

View File

@@ -744,7 +744,7 @@ class CollectionState(object):
@staticmethod
def valid_crystal(door, new_crystal_state):
return (not door.crystal or door.crystal == CrystalBarrier.Either or new_crystal_state == CrystalBarrier.Either
or new_crystal_state == door.crystal)
or new_crystal_state == door.crystal or door.alternative_crystal_rule)
def check_key_doors_in_dungeons(self, rrp, player):
for dungeon_name, checklist in self.dungeons_to_check[player].items():
@@ -2084,6 +2084,7 @@ class Door(object):
self.bigKey = False # There's a big key door on this side
self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door)
self.crystal = CrystalBarrier.Null # How your crystal state changes if you use this door
self.alternative_crystal_rule = False
self.req_event = None # if a dungeon event is required for this door - swamp palace mostly
self.controller = None
self.dependents = []
@@ -3716,3 +3717,4 @@ class KeyRuleType(FastEnum):
WorstCase = 0
AllowSmall = 1
Lock = 2
CrystalAlternative = 3

View File

@@ -20,7 +20,7 @@ from DungeonGenerator import create_dungeon_builders, split_dungeon_builder, sim
from DungeonGenerator import dungeon_portals, dungeon_drops, connect_doors, count_reserved_locations
from DungeonGenerator import valid_region_to_explore
from KeyDoorShuffle import analyze_dungeon, build_key_layout, validate_key_layout, determine_prize_lock
from KeyDoorShuffle import validate_bk_layout
from KeyDoorShuffle import validate_bk_layout, DoorRules
from Utils import ncr, kth_combination
@@ -264,7 +264,7 @@ def vanilla_key_logic(world, player):
log_key_logic(builder.name, key_layout.key_logic)
# special adjustments for vanilla
if world.keyshuffle[player] != 'universal':
if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none' :
if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none':
# adjust hc doors
def adjust_hc_door(door_rule):
if door_rule.new_rules[KeyRuleType.WorstCase] == 3:
@@ -280,9 +280,28 @@ def vanilla_key_logic(world, player):
if pod_front.new_rules[KeyRuleType.WorstCase] == 6:
pod_front.new_rules[KeyRuleType.WorstCase] = 1
pod_front.small_key_num = 1
# adjust mire key logic - this currently cannot be done dynamically
create_alternative_door_rules('Mire Hub Upper Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Lower Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Right Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Top Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Switch Blue Barrier N', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Hub Switch Blue Barrier S', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Map Spot Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Map Spike Side Blue Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Crystal Dead End Left Barrier', 2, 'Misery Mire', world, player)
create_alternative_door_rules('Mire Crystal Dead End Right Barrier', 2, 'Misery Mire', world, player)
# gt logic? I'm unsure it needs adjusting
def create_alternative_door_rules(door, amount, dungeon, world, player):
rules = DoorRules(0, True)
world.key_logic[player][dungeon].door_rules[door] = rules
rules.new_rules[KeyRuleType.CrystalAlternative] = amount
world.get_door(door, player).alternative_crystal_rule = True
def validate_vanilla_reservation(dungeon, world, player):
return validate_key_layout(world.key_layout[player][dungeon.name], world, player)

View File

@@ -61,8 +61,8 @@ item_table = {'Bow': (True, False, None, 0x0B, 200, 'You have\nchosen the\narche
'Progressive Glove': (True, False, None, 0x61, 150, 'A way to lift\nheavier things', 'and the lift upgrade', 'body-building kid', 'some glove for sale', 'fungus for gloves', 'body-building boy lifts again', 'a Glove'),
'Silver Arrows': (True, False, None, 0x58, 100, 'Do you fancy\nsilver tipped\narrows?', 'and the ganonsbane', 'ganon-killing kid', 'ganon doom for sale', 'fungus for pork', 'archer boy shines again', 'the Silver Arrows'),
'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x37, 0x08], 999, None, None, None, None, None, None, None),
'Red Pendant': (True, False, 'Crystal', [0x02, 0x32, 0x60, 0x00, 0x69, 0x38, 0x09], 999, None, None, None, None, None, None, None),
'Blue Pendant': (True, False, 'Crystal', [0x01, 0x34, 0x60, 0x00, 0x69, 0x39, 0x0a], 999, None, None, None, None, None, None, None),
'Blue Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x39, 0x09], 999, None, None, None, None, None, None, None),
'Red Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x38, 0x0a], 999, None, None, None, None, None, None, None),
'Triforce': (True, False, None, 0x6A, 777, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'),
'Power Star': (True, False, None, 0x6B, 100, 'A small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'),
'Triforce Piece': (True, False, None, 0x6C, 100, 'A small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce piece'),

View File

@@ -7,6 +7,7 @@ import RaceRandom as random
import string
import time
import zlib
import base64
from BaseClasses import World, CollectionState, Item, Region, Location, Shop, Entrance, Settings
from Bosses import place_bosses
@@ -40,7 +41,7 @@ from source.enemizer.DamageTables import DamageTable
from source.enemizer.Enemizer import randomize_enemies
from source.rom.DataTables import init_data_tables
version_number = '1.4.1.8'
version_number = '1.4.1.10'
version_branch = '-u'
__version__ = f'{version_number}{version_branch}'
@@ -328,6 +329,10 @@ def main(args, seed=None, fish=None):
if args.jsonout:
jsonout[f'patch_t{team}_p{player}'] = rom.patches
if args.bps:
localRom = LocalRom.fromJsonRom(rom, args.rom)
patch = create_bps_from_data(LocalRom(args.rom, patch=False).buffer, localRom.buffer)
jsonout[f'bps_t{team}_p{player}'] = base64.b64encode(patch.binary_ba).decode()
else:
outfilepname = f'_T{team+1}' if world.teams > 1 else ''
if world.players > 1:

View File

@@ -141,6 +141,19 @@ These are now independent of retro mode and have three options: None, Random, an
# Patch Notes
* 1.4.1.10u
* Vanilla key logic: Fix for vanilla layout Misery Mire which allows more complex key logic. Locations blocked by crystal switch access are only locked by 2 keys thanks to that being the minimum in Mire to reach one of two crystal switches.
* Autotracking: Fix for chest turn counter with chest containing multiworld items (Thanks Hiimcody)
* Enemizer: Enemy bans
* Rom: Code prettification and fixing byte designations by Codemann
* Support added for BPS patches via jsonout setting (Thanks Veetorp!)
* 1.4.1.9u
* Enemy Drop Underworld: Changed enemy drop indicator to not require compass
* Experimental: Moved dark world bunny spawns out of experimental. (It is now always on)
* Fix: Red/Blue pendants were swapped for autotracking. (Thanks Muffins!)
* Fix: Red square sometimes wasn't blinking
* Updated tournament winners
* Enemizer: Enemy bans
* 1.4.1.8u
* HUD: New dungeon indicators based on common abbreviations
* OWG+HMG: EG is allowed to be armed

5
Rom.py
View File

@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '59bea5ff31ed36e1235b897efade6595'
RANDOMIZERBASEHASH = 'ddbecd34e58b7fdf6bed48114b3124d5'
class JsonRom(object):
@@ -713,8 +713,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
rom.write_bytes(0xfb1fc, [0xc8, 0x9d, 0x69, 0xb4, 0xac, 0x5d])
if world.standardize_palettes[player] == 'original':
dr_flags |= DROptions.OriginalPalettes
if world.experimental[player]:
dr_flags |= DROptions.DarkWorld_Spawns
dr_flags |= DROptions.DarkWorld_Spawns # no longer experimental
if world.logic[player] not in ['owglitches', 'hybridglitches', 'nologic']:
dr_flags |= DROptions.Fix_EG
if world.door_type_mode[player] in ['big', 'all', 'chaos']:

View File

@@ -1570,6 +1570,7 @@ kill_chests = {
def add_connection(parent_name, target_name, entrance_name, world, player):
parent = world.get_region(parent_name, player)
target = world.get_region(target_name, player)
@@ -2026,10 +2027,13 @@ def add_key_logic_rules(world, player):
for d_name, d_logic in key_logic.items():
for door_name, rule in d_logic.door_rules.items():
door_entrance = world.get_entrance(door_name, player)
add_rule(door_entrance, eval_func(door_name, d_name, player))
if door_entrance.door.dependents:
for dep in door_entrance.door.dependents:
add_rule(dep.entrance, eval_func(door_name, d_name, player))
if not door_entrance.door.smallKey and door_entrance.door.crystal == CrystalBarrier.Blue:
add_rule(door_entrance, eval_alternative_crystal(door_name, d_name, player), 'or')
else:
add_rule(door_entrance, eval_func(door_name, d_name, player))
if door_entrance.door.dependents:
for dep in door_entrance.door.dependents:
add_rule(dep.entrance, eval_func(door_name, d_name, player))
for location in d_logic.bk_restricted:
if not location.forced_item:
forbid_item(location, d_logic.bk_name, player)
@@ -2121,6 +2125,15 @@ def eval_small_key_door_strict_main(state, door_name, dungeon, player):
return state.has_sm_key_strict(key_layout.key_logic.small_key_name, player, number)
def eval_alternative_crystal_main(state, door_name, dungeon, player):
key_logic = state.world.key_logic[player][dungeon]
door_rule = key_logic.door_rules[door_name]
for ruleType, number in door_rule.new_rules.items():
if ruleType == KeyRuleType.CrystalAlternative:
return state.has_sm_key(key_logic.small_key_name, player, number)
return False
def eval_small_key_door(door_name, dungeon, player):
return lambda state: eval_small_key_door_main(state, door_name, dungeon, player)
@@ -2133,6 +2146,10 @@ def eval_small_key_door_strict(door_name, dungeon, player):
return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player)
def eval_alternative_crystal(door_name, dungeon, player):
return lambda state: eval_alternative_crystal_main(state, door_name, dungeon, player)
def allow_big_key_in_big_chest(bk_name, player):
return lambda state, item: item.name == bk_name and item.player == player

View File

@@ -2027,6 +2027,8 @@ class TextTable(object):
text['ganon_phase_3_alt'] = CompressedTextMapper.convert("Got wax in your ears? I cannot die!")
# 190
text['sign_east_death_mountain_bridge'] = CompressedTextMapper.convert("Glitched\ntournament\nwinners\n{HARP}\n"
"~~~HMG 2023~~~\ntam\n\n"
"~~~No Logic 2022~~~\nChexhuman\n\n"
"~~~HMG 2021~~~\nKrithel\n\n"
"~~~OWG 2019~~~\nGlan\n\n"
"~~~OWG 2018~~~\nChristosOwen\nthe numpty")

Binary file not shown.

View File

@@ -77,7 +77,7 @@ UwGeneralDeny:
- [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2"
- [ 0x0039, 3, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Mini Helmasaur"
- [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1"
- [ 0x0039, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Hardhat Beetle"
- [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper"]] #"Skull Woods - Play Pen - Hardhat Beetle"
- [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2"
- [ 0x003b, 1, [ "Bumper" ]]
- [ 0x003c, 0, ["BigSpike"]]
@@ -289,6 +289,8 @@ UwGeneralDeny:
- [ 0x00ae, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 1"
- [ 0x00ae, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 2"
- [ 0x00af, 0, [ "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Ice Clock - Fire Bar (Clockwise)"
- [0x00b0, 7, [ "StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
- [0x00b0, 8, [ "StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
- [ 0x00b1, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 1"
- [ 0x00b1, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 2"
- [ 0x00b1, 4, ["Bumper", "BigSpike", "AntiFairyCircle" ]]
@@ -445,6 +447,7 @@ OwGeneralDeny:
- [0x5e, 19, ["Gibo"]] # kiki eating Gibo
- [0x5e, 20, ["Gibo"]] # kiki eating Gibo
- [0x77, 1, ["Bumper"]] # soft-lock potential near ladder
- [0x7f, 1, ["Bumper"]] # soft-lock potential near ladder
UwEnemyDrop:
- [0x0085, 9, ["Babasu"]] # ran off the edge and didn't return
- [0x00cb, 3, ["Zoro"]] # layer issues
@@ -457,8 +460,6 @@ UwEnemyDrop:
- [0x0077, 5, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
- [0x008D, 10, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
- [0x008D, 12, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
- [0x00b0, 7, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
- [0x00b0, 8, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
# the following are not allowed at certain pits (or on conveyors near pits)
# because they despawned or clipped away or immediately fell, etc
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard", "Hover",
@@ -680,11 +681,11 @@ UwEnemyDrop:
- [0x00a5, 4, ["GreenMimic", "RedMimic"]]
- [0x00a5, 5, ["GreenMimic", "RedMimic"]]
- [0x00a5, 6, ["GreenMimic", "RedMimic"]]
- [0x00bb, 1, ["GreenMimic", "RedMimic"]]
- [0x00bb, 4, ["GreenMimic", "RedMimic"]]
- [0x00bb, 5, ["GreenMimic", "RedMimic"]]
- [0x00bb, 6, ["GreenMimic", "RedMimic"]]
- [0x00bb, 7, ["GreenMimic", "RedMimic"]]
- [0x00bb, 1, ["GreenMimic", "RedMimic", "Terrorpin"]]
- [0x00bb, 4, ["GreenMimic", "RedMimic", "Terrorpin"]]
- [0x00bb, 5, ["GreenMimic", "RedMimic", "Terrorpin"]]
- [0x00bb, 6, ["GreenMimic", "RedMimic", "Terrorpin"]]
- [0x00bb, 7, ["GreenMimic", "RedMimic", "Terrorpin"]]
- [0x00bb, 8, ["GreenMimic", "RedMimic"]]
- [0x00bb, 9, ["GreenMimic", "RedMimic"]]
- [0x00bb, 10, ["GreenMimic", "RedMimic"]]