Merge Unstable into EdgeWork
This commit is contained in:
@@ -220,6 +220,7 @@ jobs:
|
|||||||
body: ${{ steps.release_notes.outputs.body }}
|
body: ${{ steps.release_notes.outputs.body }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
if: contains(github.ref, 'master') || contains(github.ref, 'stable') || contains(github.ref, 'dev') || contains(github.ref, 'DoorRelease')
|
||||||
# upload linux archive asset
|
# upload linux archive asset
|
||||||
- name: Upload Linux Archive Asset
|
- name: Upload Linux Archive Asset
|
||||||
id: upload-linux-asset
|
id: upload-linux-asset
|
||||||
@@ -231,6 +232,7 @@ jobs:
|
|||||||
asset_path: ../deploy/linux/ALttPDoorRandomizer.tar.gz
|
asset_path: ../deploy/linux/ALttPDoorRandomizer.tar.gz
|
||||||
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-linux-bionic.tar.gz
|
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-linux-bionic.tar.gz
|
||||||
asset_content_type: application/gzip
|
asset_content_type: application/gzip
|
||||||
|
if: contains(github.ref, 'master') || contains(github.ref, 'stable') || contains(github.ref, 'dev') || contains(github.ref, 'DoorRelease')
|
||||||
# upload macos archive asset
|
# upload macos archive asset
|
||||||
- name: Upload MacOS Archive Asset
|
- name: Upload MacOS Archive Asset
|
||||||
id: upload-macos-asset
|
id: upload-macos-asset
|
||||||
@@ -242,6 +244,7 @@ jobs:
|
|||||||
asset_path: ../deploy/macos/ALttPDoorRandomizer.tar.gz
|
asset_path: ../deploy/macos/ALttPDoorRandomizer.tar.gz
|
||||||
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-osx.tar.gz
|
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-osx.tar.gz
|
||||||
asset_content_type: application/gzip
|
asset_content_type: application/gzip
|
||||||
|
if: contains(github.ref, 'master') || contains(github.ref, 'stable') || contains(github.ref, 'dev') || contains(github.ref, 'DoorRelease')
|
||||||
# upload windows archive asset
|
# upload windows archive asset
|
||||||
- name: Upload Windows Archive Asset
|
- name: Upload Windows Archive Asset
|
||||||
id: upload-windows-asset
|
id: upload-windows-asset
|
||||||
@@ -253,3 +256,4 @@ jobs:
|
|||||||
asset_path: ../deploy/windows/ALttPDoorRandomizer.zip
|
asset_path: ../deploy/windows/ALttPDoorRandomizer.zip
|
||||||
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-windows.zip
|
asset_name: ALttPDoorRandomizer-${{ steps.debug_info.outputs.github_tag }}-windows.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
if: contains(github.ref, 'master') || contains(github.ref, 'stable') || contains(github.ref, 'dev') || contains(github.ref, 'DoorRelease')
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode
|
||||||
*_Spoiler.txt
|
*_Spoiler.txt
|
||||||
|
*.bmbp
|
||||||
|
*.log
|
||||||
|
*_Spoiler.json
|
||||||
*.pyc
|
*.pyc
|
||||||
*.sfc
|
*.sfc
|
||||||
*.srm
|
*.srm
|
||||||
@@ -18,6 +21,9 @@ EnemizerCLI/
|
|||||||
RaceRom.py
|
RaceRom.py
|
||||||
upx/
|
upx/
|
||||||
weights/
|
weights/
|
||||||
|
/MultiMystery/
|
||||||
|
/Players/
|
||||||
|
/QUsb2Snes/
|
||||||
|
|
||||||
resources/user/*
|
resources/user/*
|
||||||
!resources/user/.gitkeep
|
!resources/user/.gitkeep
|
||||||
|
|||||||
+47
-1
@@ -1031,6 +1031,44 @@ class Direction(Enum):
|
|||||||
Down = 5
|
Down = 5
|
||||||
|
|
||||||
|
|
||||||
|
@unique
|
||||||
|
class Hook(Enum):
|
||||||
|
North = 0
|
||||||
|
West = 1
|
||||||
|
South = 2
|
||||||
|
East = 3
|
||||||
|
Stairs = 4
|
||||||
|
NEdge = 5
|
||||||
|
SEdge = 6
|
||||||
|
WEdge = 7
|
||||||
|
EEdge = 8
|
||||||
|
|
||||||
|
|
||||||
|
hook_dir_map = {
|
||||||
|
Direction.North: Hook.North,
|
||||||
|
Direction.South: Hook.South,
|
||||||
|
Direction.West: Hook.West,
|
||||||
|
Direction.East: Hook.East,
|
||||||
|
}
|
||||||
|
|
||||||
|
edge_map = {
|
||||||
|
Direction.North: Hook.NEdge,
|
||||||
|
Direction.South: Hook.SEdge,
|
||||||
|
Direction.West: Hook.WEdge,
|
||||||
|
Direction.East: Hook.EEdge,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def hook_from_door(door):
|
||||||
|
if door.type == DoorType.SpiralStairs:
|
||||||
|
return Hook.Stairs
|
||||||
|
if door.type == DoorType.Normal:
|
||||||
|
return hook_dir_map[door.direction]
|
||||||
|
if door.type == DoorType.Open:
|
||||||
|
return edge_map[door.direction]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Polarity:
|
class Polarity:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.vector = [0, 0, 0]
|
self.vector = [0, 0, 0]
|
||||||
@@ -1306,6 +1344,7 @@ class Sector(object):
|
|||||||
self.branch_factor = None
|
self.branch_factor = None
|
||||||
self.dead_end_cnt = None
|
self.dead_end_cnt = None
|
||||||
self.entrance_sector = None
|
self.entrance_sector = None
|
||||||
|
self.destination_entrance = False
|
||||||
self.equations = None
|
self.equations = None
|
||||||
|
|
||||||
def region_set(self):
|
def region_set(self):
|
||||||
@@ -1327,6 +1366,13 @@ class Sector(object):
|
|||||||
magnitude[idx] = magnitude[idx] + 1
|
magnitude[idx] = magnitude[idx] + 1
|
||||||
return magnitude
|
return magnitude
|
||||||
|
|
||||||
|
def hook_magnitude(self):
|
||||||
|
magnitude = [0] * len(Hook)
|
||||||
|
for door in self.outstanding_doors:
|
||||||
|
idx = hook_from_door(door).value
|
||||||
|
magnitude[idx] = magnitude[idx] + 1
|
||||||
|
return magnitude
|
||||||
|
|
||||||
def outflow(self):
|
def outflow(self):
|
||||||
outflow = 0
|
outflow = 0
|
||||||
for door in self.outstanding_doors:
|
for door in self.outstanding_doors:
|
||||||
@@ -1349,7 +1395,7 @@ class Sector(object):
|
|||||||
self.branch_factor -= cnt_dead - 1
|
self.branch_factor -= cnt_dead - 1
|
||||||
for region in self.regions:
|
for region in self.regions:
|
||||||
for ent in region.entrances:
|
for ent in region.entrances:
|
||||||
if ent.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld]:
|
if ent.parent_region.type in [RegionType.LightWorld, RegionType.DarkWorld] or ent.parent_region.name == 'Sewer Drop':
|
||||||
# same sector as another entrance
|
# same sector as another entrance
|
||||||
if region.name not in ['Skull Pot Circle', 'Skull Back Drop', 'Desert East Lobby', 'Desert West Lobby']:
|
if region.name not in ['Skull Pot Circle', 'Skull Back Drop', 'Desert East Lobby', 'Desert West Lobby']:
|
||||||
self.branch_factor += 1
|
self.branch_factor += 1
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ def parse_settings():
|
|||||||
"accessibility": "items",
|
"accessibility": "items",
|
||||||
"algorithm": "balanced",
|
"algorithm": "balanced",
|
||||||
|
|
||||||
|
# Shuffle Ganon defaults to TRUE
|
||||||
"openpyramid": False,
|
"openpyramid": False,
|
||||||
"shuffleganon": True,
|
"shuffleganon": True,
|
||||||
"shuffle": "vanilla",
|
"shuffle": "vanilla",
|
||||||
@@ -146,7 +147,9 @@ def parse_settings():
|
|||||||
"multi": 1,
|
"multi": 1,
|
||||||
"names": "",
|
"names": "",
|
||||||
|
|
||||||
|
# Hints default to TRUE
|
||||||
"hints": True,
|
"hints": True,
|
||||||
|
"no_hints": False,
|
||||||
"disablemusic": False,
|
"disablemusic": False,
|
||||||
"quickswap": False,
|
"quickswap": False,
|
||||||
"heartcolor": "red",
|
"heartcolor": "red",
|
||||||
@@ -156,10 +159,11 @@ def parse_settings():
|
|||||||
"ow_palettes": "default",
|
"ow_palettes": "default",
|
||||||
"uw_palettes": "default",
|
"uw_palettes": "default",
|
||||||
|
|
||||||
|
# Spoiler defaults to FALSE
|
||||||
|
# Playthrough defaults to TRUE
|
||||||
|
# ROM defaults to TRUE
|
||||||
"create_spoiler": False,
|
"create_spoiler": False,
|
||||||
"skip_playthrough": False,
|
|
||||||
"calc_playthrough": True,
|
"calc_playthrough": True,
|
||||||
"suppress_rom": False,
|
|
||||||
"create_rom": True,
|
"create_rom": True,
|
||||||
"usestartinventory": False,
|
"usestartinventory": False,
|
||||||
"custom": False,
|
"custom": False,
|
||||||
@@ -309,9 +313,9 @@ def get_args_priority(settings_args, gui_args, cli_args):
|
|||||||
else:
|
else:
|
||||||
newArgs[key] = args[key]
|
newArgs[key] = args[key]
|
||||||
|
|
||||||
newArgs[key] = update_deprecated_args(newArgs[key])
|
|
||||||
else:
|
else:
|
||||||
newArgs[key] = args[key]
|
newArgs[key] = args[key]
|
||||||
|
newArgs[key] = update_deprecated_args(newArgs[key])
|
||||||
|
|
||||||
args = newArgs
|
args = newArgs
|
||||||
|
|
||||||
|
|||||||
+21
-21
@@ -409,11 +409,6 @@ def determine_entrance_list(world, player):
|
|||||||
return entrance_map, potential_entrances, connections
|
return entrance_map, potential_entrances, connections
|
||||||
|
|
||||||
|
|
||||||
# todo: kill drop exceptions
|
|
||||||
def drop_exception(name):
|
|
||||||
return name in ['Skull Pot Circle', 'Skull Back Drop']
|
|
||||||
|
|
||||||
|
|
||||||
def add_shuffled_entrances(sectors, region_list, entrance_list):
|
def add_shuffled_entrances(sectors, region_list, entrance_list):
|
||||||
for sector in sectors:
|
for sector in sectors:
|
||||||
for region in sector.regions:
|
for region in sector.regions:
|
||||||
@@ -431,8 +426,6 @@ def find_enabled_origins(sectors, enabled, entrance_list, entrance_map, key):
|
|||||||
if key not in entrance_map.keys():
|
if key not in entrance_map.keys():
|
||||||
key = ' '.join(key.split(' ')[:-1])
|
key = ' '.join(key.split(' ')[:-1])
|
||||||
entrance_map[key].append(region.name)
|
entrance_map[key].append(region.name)
|
||||||
if drop_exception(region.name): # only because they have unique regions
|
|
||||||
entrance_list.append(region.name)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_drop_origins(entrance_list):
|
def remove_drop_origins(entrance_list):
|
||||||
@@ -504,7 +497,7 @@ def cross_dungeon(world, player):
|
|||||||
all_sectors = []
|
all_sectors = []
|
||||||
for key in dungeon_regions.keys():
|
for key in dungeon_regions.keys():
|
||||||
all_sectors.extend(convert_to_sectors(dungeon_regions[key], world, player))
|
all_sectors.extend(convert_to_sectors(dungeon_regions[key], world, player))
|
||||||
dungeon_builders = create_dungeon_builders(all_sectors, world, player)
|
dungeon_builders = create_dungeon_builders(all_sectors, connections_tuple, world, player)
|
||||||
for builder in dungeon_builders.values():
|
for builder in dungeon_builders.values():
|
||||||
builder.entrance_list = list(entrances_map[builder.name])
|
builder.entrance_list = list(entrances_map[builder.name])
|
||||||
dungeon_obj = world.get_dungeon(builder.name, player)
|
dungeon_obj = world.get_dungeon(builder.name, player)
|
||||||
@@ -524,25 +517,15 @@ def cross_dungeon(world, player):
|
|||||||
check_required_paths(paths, world, player)
|
check_required_paths(paths, world, player)
|
||||||
|
|
||||||
hc = world.get_dungeon('Hyrule Castle', player)
|
hc = world.get_dungeon('Hyrule Castle', player)
|
||||||
del hc.dungeon_items[0] # removes map
|
|
||||||
hc.dungeon_items.append(ItemFactory('Compass (Escape)', player))
|
hc.dungeon_items.append(ItemFactory('Compass (Escape)', player))
|
||||||
at = world.get_dungeon('Agahnims Tower', player)
|
at = world.get_dungeon('Agahnims Tower', player)
|
||||||
at.dungeon_items.append(ItemFactory('Compass (Agahnims Tower)', player))
|
at.dungeon_items.append(ItemFactory('Compass (Agahnims Tower)', player))
|
||||||
gt = world.get_dungeon('Ganons Tower', player)
|
at.dungeon_items.append(ItemFactory('Map (Agahnims Tower)', player))
|
||||||
del gt.dungeon_items[0] # removes map
|
|
||||||
|
|
||||||
assign_cross_keys(dungeon_builders, world, player)
|
assign_cross_keys(dungeon_builders, world, player)
|
||||||
all_dungeon_items = [y for x in world.dungeons if x.player == player for y in x.all_items]
|
all_dungeon_items = [y for x in world.dungeons if x.player == player for y in x.all_items]
|
||||||
target_items = 34 if world.retro[player] else 63
|
target_items = 34 if world.retro[player] else 63
|
||||||
d_items = target_items - len(all_dungeon_items)
|
d_items = target_items - len(all_dungeon_items)
|
||||||
if d_items > 0:
|
|
||||||
if d_items >= 1: # restore HC map
|
|
||||||
world.get_dungeon('Hyrule Castle', player).dungeon_items.append(ItemFactory('Map (Escape)', player))
|
|
||||||
if d_items >= 2: # restore GT map
|
|
||||||
world.get_dungeon('Ganons Tower', player).dungeon_items.append(ItemFactory('Map (Ganons Tower)', player))
|
|
||||||
if d_items > 2:
|
|
||||||
world.pool_adjustment[player] = d_items - 2
|
|
||||||
elif d_items < 0:
|
|
||||||
world.pool_adjustment[player] = d_items
|
world.pool_adjustment[player] = d_items
|
||||||
smooth_door_pairs(world, player)
|
smooth_door_pairs(world, player)
|
||||||
|
|
||||||
@@ -1127,7 +1110,7 @@ def stateful_door(door, kind):
|
|||||||
|
|
||||||
|
|
||||||
def random_door_type(door, partner, world, player, type_a, type_b, room_a, room_b):
|
def random_door_type(door, partner, world, player, type_a, type_b, room_a, room_b):
|
||||||
r_kind = random.choices([DoorKind.Normal, DoorKind.Bombable, DoorKind.Dashable], [5, 2, 3], k=1)[0]
|
r_kind = random.choices([DoorKind.Normal, DoorKind.Bombable, DoorKind.Dashable], [15, 4, 6], k=1)[0]
|
||||||
if r_kind != DoorKind.Normal:
|
if r_kind != DoorKind.Normal:
|
||||||
if door.type == DoorType.Normal:
|
if door.type == DoorType.Normal:
|
||||||
add_pair(door, partner, world, player)
|
add_pair(door, partner, world, player)
|
||||||
@@ -1301,7 +1284,7 @@ def check_if_regions_visited(state, check_paths):
|
|||||||
|
|
||||||
def check_for_pinball_fix(state, bad_region, world, player):
|
def check_for_pinball_fix(state, bad_region, world, player):
|
||||||
pinball_region = world.get_region('Skull Pinball', player)
|
pinball_region = world.get_region('Skull Pinball', player)
|
||||||
if bad_region.name == 'Skull 2 West Lobby' and state.visited_at_all(pinball_region): #revisit this for entrance shuffle
|
if bad_region.name == 'Skull 2 West Lobby' and state.visited_at_all(pinball_region): # revisit this for entrance shuffle
|
||||||
door = world.get_door('Skull Pinball WS', player)
|
door = world.get_door('Skull Pinball WS', player)
|
||||||
room = world.get_room(door.roomIndex, player)
|
room = world.get_room(door.roomIndex, player)
|
||||||
if room.doorList[door.doorListPos][1] == DoorKind.Trap:
|
if room.doorList[door.doorListPos][1] == DoorKind.Trap:
|
||||||
@@ -1319,6 +1302,7 @@ class DROptions(Flag):
|
|||||||
NoOptions = 0x00
|
NoOptions = 0x00
|
||||||
Eternal_Mini_Bosses = 0x01 # If on, GT minibosses marked as defeated when they try to spawn a heart
|
Eternal_Mini_Bosses = 0x01 # If on, GT minibosses marked as defeated when they try to spawn a heart
|
||||||
Town_Portal = 0x02 # If on, Players will start with mirror scroll
|
Town_Portal = 0x02 # If on, Players will start with mirror scroll
|
||||||
|
Map_Info = 0x04
|
||||||
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required
|
Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required
|
||||||
|
|
||||||
# DATA GOES DOWN HERE
|
# DATA GOES DOWN HERE
|
||||||
@@ -2081,3 +2065,19 @@ compass_data = {
|
|||||||
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0, 0x18),
|
'Turtle Rock': (0x11F, 0xcb, 0x15e, 0, 0x18),
|
||||||
'Ganons Tower': (0x13A, 0xcc, 0x170, 2, 0x1a)
|
'Ganons Tower': (0x13A, 0xcc, 0x170, 2, 0x1a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# For compass boss indicator
|
||||||
|
boss_indicator = {
|
||||||
|
'Eastern Palace': (0x04, 'Eastern Boss SE'),
|
||||||
|
'Desert Palace': (0x06, 'Desert Boss SW'),
|
||||||
|
'Agahnims Tower': (0x08, 'Tower Agahnim 1 SW'),
|
||||||
|
'Swamp Palace': (0x0a, 'Swamp Boss SW'),
|
||||||
|
'Palace of Darkness': (0x0c, 'PoD Boss SE'),
|
||||||
|
'Misery Mire': (0x0e, 'Mire Boss SW'),
|
||||||
|
'Skull Woods': (0x10, 'Skull Spike Corner SW'),
|
||||||
|
'Ice Palace': (0x12, 'Ice Antechamber NE'),
|
||||||
|
'Tower of Hera': (0x14, 'Hera Boss Down Stairs'),
|
||||||
|
'Thieves Town': (0x16, 'Thieves Boss SE'),
|
||||||
|
'Turtle Rock': (0x18, 'TR Boss SW'),
|
||||||
|
'Ganons Tower': (0x1a, 'GT Agahnim 2 SW')
|
||||||
|
}
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ def create_doors(world, player):
|
|||||||
create_door(player, 'PoD Basement Ledge Drop Down', Lgcl),
|
create_door(player, 'PoD Basement Ledge Drop Down', Lgcl),
|
||||||
create_door(player, 'PoD Stalfos Basement Warp', Warp),
|
create_door(player, 'PoD Stalfos Basement Warp', Warp),
|
||||||
create_door(player, 'PoD Arena Main SW', Nrml).dir(So, 0x2a, Left, High).pos(4),
|
create_door(player, 'PoD Arena Main SW', Nrml).dir(So, 0x2a, Left, High).pos(4),
|
||||||
create_door(player, 'PoD Arena Bridge SE', Nrml).dir(So, 0x2a, Right, High).pos(5).kill(),
|
create_door(player, 'PoD Arena Bridge SE', Nrml).dir(So, 0x2a, Right, High).pos(5),
|
||||||
create_door(player, 'PoD Arena Main NW', Nrml).dir(No, 0x2a, Left, High).small_key().pos(1),
|
create_door(player, 'PoD Arena Main NW', Nrml).dir(No, 0x2a, Left, High).small_key().pos(1),
|
||||||
create_door(player, 'PoD Arena Main NE', Nrml).dir(No, 0x2a, Right, High).no_exit().trap(0x4).pos(0),
|
create_door(player, 'PoD Arena Main NE', Nrml).dir(No, 0x2a, Right, High).no_exit().trap(0x4).pos(0),
|
||||||
create_door(player, 'PoD Arena Main Crystal Path', Lgcl),
|
create_door(player, 'PoD Arena Main Crystal Path', Lgcl),
|
||||||
|
|||||||
+866
-127
File diff suppressed because it is too large
Load Diff
+10
-2
@@ -9,9 +9,10 @@ import shlex
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from source.classes.BabelFish import BabelFish
|
from source.classes.BabelFish import BabelFish
|
||||||
|
import source.classes.diags as diagnostics
|
||||||
|
|
||||||
from CLI import parse_cli, get_args_priority
|
from CLI import parse_cli, get_args_priority
|
||||||
from Main import main, EnemizerError
|
from Main import main, EnemizerError, __version__
|
||||||
from Rom import get_sprite_from_name
|
from Rom import get_sprite_from_name
|
||||||
from Utils import is_bundled, close_console
|
from Utils import is_bundled, close_console
|
||||||
from Fill import FillError
|
from Fill import FillError
|
||||||
@@ -19,6 +20,13 @@ from Fill import FillError
|
|||||||
def start():
|
def start():
|
||||||
args = parse_cli(None)
|
args = parse_cli(None)
|
||||||
|
|
||||||
|
# print diagnostics
|
||||||
|
# usage: py DungeonRandomizer.py --diags
|
||||||
|
if args.diags:
|
||||||
|
diags = diagnostics.output(__version__)
|
||||||
|
print("\n".join(diags))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
if is_bundled() and len(sys.argv) == 1:
|
if is_bundled() and len(sys.argv) == 1:
|
||||||
# for the bundled builds, if we have no arguments, the user
|
# for the bundled builds, if we have no arguments, the user
|
||||||
# probably wants the gui. Users of the bundled build who want the command line
|
# probably wants the gui. Users of the bundled build who want the command line
|
||||||
@@ -67,7 +75,7 @@ def start():
|
|||||||
logger.warning('%s: %s', fish.translate("cli","cli","generation.failed"), err)
|
logger.warning('%s: %s', fish.translate("cli","cli","generation.failed"), err)
|
||||||
seed = random.randint(0, 999999999)
|
seed = random.randint(0, 999999999)
|
||||||
for fail in failures:
|
for fail in failures:
|
||||||
logger.info('%s seed failed with: %s', fail[1], fail[0])
|
logger.info('%s\tseed failed with: %s', fail[1], fail[0])
|
||||||
fail_rate = 100 * len(failures) / args.count
|
fail_rate = 100 * len(failures) / args.count
|
||||||
success_rate = 100 * (args.count - len(failures)) / args.count
|
success_rate = 100 * (args.count - len(failures)) / args.count
|
||||||
fail_rate = str(fail_rate).split('.')
|
fail_rate = str(fail_rate).split('.')
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import sys
|
|||||||
block_cipher = None
|
block_cipher = None
|
||||||
console = True
|
console = True
|
||||||
|
|
||||||
|
BINARY_SLUG = "DungeonRandomizer"
|
||||||
|
|
||||||
def recurse_for_py_files(names_so_far):
|
def recurse_for_py_files(names_so_far):
|
||||||
returnvalue = []
|
returnvalue = []
|
||||||
for name in os.listdir(os.path.join(*names_so_far)):
|
for name in os.listdir(os.path.join(*names_so_far)):
|
||||||
@@ -28,7 +30,7 @@ binaries = []
|
|||||||
#if sys.platform.find("windows"):
|
#if sys.platform.find("windows"):
|
||||||
# binaries.append(("ucrtbase.dll","."))
|
# binaries.append(("ucrtbase.dll","."))
|
||||||
|
|
||||||
a = Analysis(['DungeonRandomizer.py'],
|
a = Analysis([f"./{BINARY_SLUG}.py"],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=binaries,
|
binaries=binaries,
|
||||||
datas=[],
|
datas=[],
|
||||||
@@ -56,7 +58,7 @@ exe = EXE(pyz,
|
|||||||
a.zipfiles,
|
a.zipfiles,
|
||||||
a.datas,
|
a.datas,
|
||||||
[],
|
[],
|
||||||
name='DungeonRandomizer',
|
name=BINARY_SLUG,
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ console = True
|
|||||||
|
|
||||||
if sys.platform.find("mac") or sys.platform.find("osx"):
|
if sys.platform.find("mac") or sys.platform.find("osx"):
|
||||||
console = False
|
console = False
|
||||||
|
BINARY_SLUG = "Gui"
|
||||||
|
|
||||||
def recurse_for_py_files(names_so_far):
|
def recurse_for_py_files(names_so_far):
|
||||||
returnvalue = []
|
returnvalue = []
|
||||||
@@ -31,7 +32,7 @@ binaries = []
|
|||||||
#if sys.platform.find("windows"):
|
#if sys.platform.find("windows"):
|
||||||
# binaries.append(("ucrtbase.dll","."))
|
# binaries.append(("ucrtbase.dll","."))
|
||||||
|
|
||||||
a = Analysis(['DungeonRandomizer.py'],
|
a = Analysis([f"./{BINARY_SLUG}.py"],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=binaries,
|
binaries=binaries,
|
||||||
datas=[],
|
datas=[],
|
||||||
@@ -59,7 +60,7 @@ exe = EXE(pyz,
|
|||||||
a.zipfiles,
|
a.zipfiles,
|
||||||
a.datas,
|
a.datas,
|
||||||
[],
|
[],
|
||||||
name='Gui',
|
name=BINARY_SLUG,
|
||||||
debug=False,
|
debug=False,
|
||||||
bootloader_ignore_signals=False,
|
bootloader_ignore_signals=False,
|
||||||
strip=False,
|
strip=False,
|
||||||
|
|||||||
+4
-3
@@ -1,13 +1,14 @@
|
|||||||
import queue
|
import queue
|
||||||
|
import os
|
||||||
import threading
|
import threading
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
from Utils import local_path
|
from Utils import local_path
|
||||||
|
|
||||||
def set_icon(window):
|
def set_icon(window):
|
||||||
er16 = tk.PhotoImage(file=local_path('data/ER16.gif'))
|
er16 = tk.PhotoImage(file=local_path(os.path.join("data","ER16.gif")))
|
||||||
er32 = tk.PhotoImage(file=local_path('data/ER32.gif'))
|
er32 = tk.PhotoImage(file=local_path(os.path.join("data","ER32.gif")))
|
||||||
er48 = tk.PhotoImage(file=local_path('data/ER32.gif'))
|
er48 = tk.PhotoImage(file=local_path(os.path.join("data","ER48.gif")))
|
||||||
window.tk.call('wm', 'iconphoto', window._w, er16, er32, er48) # pylint: disable=protected-access
|
window.tk.call('wm', 'iconphoto', window._w, er16, er32, er48) # pylint: disable=protected-access
|
||||||
|
|
||||||
# Although tkinter is intended to be thread safe, there are many reports of issues
|
# Although tkinter is intended to be thread safe, there are many reports of issues
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
|
|||||||
'Progressive Glove': (True, False, None, 0x61, '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'),
|
'Progressive Glove': (True, False, None, 0x61, '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, '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'),
|
'Silver Arrows': (True, False, None, 0x58, '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, 0x01], None, None, None, None, None, None, None),
|
'Green Pendant': (True, False, 'Crystal', [0x04, 0x38, 0x62, 0x00, 0x69, 0x01], None, None, None, None, None, None, None),
|
||||||
'Red Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], None, None, None, None, None, None, None),
|
'Blue Pendant': (True, False, 'Crystal', [0x02, 0x34, 0x60, 0x00, 0x69, 0x02], None, None, None, None, None, None, None),
|
||||||
'Blue Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], None, None, None, None, None, None, None),
|
'Red Pendant': (True, False, 'Crystal', [0x01, 0x32, 0x60, 0x00, 0x69, 0x03], None, None, None, None, None, None, None),
|
||||||
'Triforce': (True, False, None, 0x6A, '\n YOU WIN!', 'and the triforce', 'victorious kid', 'victory for sale', 'fungus for the win', 'greedy boy wins game again', 'the Triforce'),
|
'Triforce': (True, False, None, 0x6A, '\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, 'a small victory', 'and the power star', 'star-struck kid', 'star for sale', 'see stars with shroom', 'mario powers up again', 'a Power Star'),
|
'Power Star': (True, False, None, 0x6B, '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, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce Piece'),
|
'Triforce Piece': (True, False, None, 0x6C, 'a small victory', 'and the thirdforce', 'triangular kid', 'triangle for sale', 'fungus for triangle', 'wise boy has triangle again', 'a Triforce Piece'),
|
||||||
@@ -130,6 +130,7 @@ item_table = {'Bow': (True, False, None, 0x0B, 'You have\nchosen the\narcher cla
|
|||||||
'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'),
|
'Small Key (Agahnims Tower)': (False, False, 'SmallKey', 0xA4, 'A small key to Agahnim', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Castle Tower'),
|
||||||
'Big Key (Agahnims Tower)': (False, False, 'BigKey', 0x9B, 'A big key to Agahnim', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Castle Tower'),
|
'Big Key (Agahnims Tower)': (False, False, 'BigKey', 0x9B, 'A big key to Agahnim', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Castle Tower'),
|
||||||
'Compass (Agahnims Tower)': (False, True, 'Compass', 0x8B, 'Now you can find Aga1!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Castle Tower'),
|
'Compass (Agahnims Tower)': (False, True, 'Compass', 0x8B, 'Now you can find Aga1!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds null again', 'a compass to Castle Tower'),
|
||||||
|
'Map (Agahnims Tower)': (False, True, 'Map', 0x7B, 'A tightly folded map rests here', 'and the map', 'cartography kid', 'map for sale', 'a map to shrooms', 'map boy navigates again', 'a map to Castle Tower'),
|
||||||
'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'),
|
'Small Key (Palace of Darkness)': (False, False, 'SmallKey', 0xA6, 'A small key to darkness', 'and the key', 'the unlocking kid', 'keys for sale', 'unlock the fungus', 'key boy opens door again', 'a small key to Palace of Darkness'),
|
||||||
'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'),
|
'Big Key (Palace of Darkness)': (False, False, 'BigKey', 0x99, 'A big key to darkness', 'and the big key', 'the big-unlock kid', 'big key for sale', 'face key fungus', 'key boy opens chest again', 'a big key to Palace of Darkness'),
|
||||||
'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'),
|
'Compass (Palace of Darkness)': (False, True, 'Compass', 0x89, 'Now you can find Helmasaur King!', 'and the compass', 'the magnetic kid', 'compass for sale', 'magnetic fungus', 'compass boy finds boss again', 'a compass to Palace of Darkness'),
|
||||||
|
|||||||
@@ -19,16 +19,17 @@ from Doors import create_doors
|
|||||||
from DoorShuffle import link_doors
|
from DoorShuffle import link_doors
|
||||||
from RoomData import create_rooms
|
from RoomData import create_rooms
|
||||||
from Rules import set_rules
|
from Rules import set_rules
|
||||||
from Dungeons import create_dungeons, fill_dungeons, fill_dungeons_restrictive, dungeon_regions
|
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 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
|
||||||
from Utils import output_path, parse_player_names, print_wiki_doors_by_region, print_wiki_doors_by_room
|
from Utils import output_path, parse_player_names
|
||||||
|
|
||||||
__version__ = '0.1.0-dev'
|
__version__ = '0.1.0.0-u'
|
||||||
|
|
||||||
class EnemizerError(RuntimeError):
|
class EnemizerError(RuntimeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def main(args, seed=None, fish=None):
|
def main(args, seed=None, fish=None):
|
||||||
if args.outputpath:
|
if args.outputpath:
|
||||||
os.makedirs(args.outputpath, exist_ok=True)
|
os.makedirs(args.outputpath, exist_ok=True)
|
||||||
@@ -186,20 +187,18 @@ def main(args, seed=None, fish=None):
|
|||||||
|
|
||||||
rom_names = []
|
rom_names = []
|
||||||
jsonout = {}
|
jsonout = {}
|
||||||
|
enemized = False
|
||||||
if not args.suppress_rom:
|
if not args.suppress_rom:
|
||||||
logger.info(world.fish.translate("cli","cli","patching.rom"))
|
logger.info(world.fish.translate("cli","cli","patching.rom"))
|
||||||
for team in range(world.teams):
|
for team in range(world.teams):
|
||||||
for player in range(1, world.players + 1):
|
for player in range(1, world.players + 1):
|
||||||
sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
|
sprite_random_on_hit = type(args.sprite[player]) is str and args.sprite[player].lower() == 'randomonhit'
|
||||||
enemized = False
|
|
||||||
use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] != 'none'
|
use_enemizer = (world.boss_shuffle[player] != 'none' or world.enemy_shuffle[player] != 'none'
|
||||||
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
|
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default'
|
||||||
or args.shufflepots[player] or sprite_random_on_hit)
|
or args.shufflepots[player] or sprite_random_on_hit)
|
||||||
|
|
||||||
rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom)
|
rom = JsonRom() if args.jsonout or use_enemizer else LocalRom(args.rom)
|
||||||
|
|
||||||
patch_rom(world, rom, player, team, use_enemizer)
|
|
||||||
|
|
||||||
if use_enemizer and (args.enemizercli or not args.jsonout):
|
if use_enemizer and (args.enemizercli or not args.jsonout):
|
||||||
if args.rom and not(os.path.isfile(args.rom)):
|
if args.rom and not(os.path.isfile(args.rom)):
|
||||||
raise RuntimeError("Could not find valid base rom for enemizing at expected path %s." % args.rom)
|
raise RuntimeError("Could not find valid base rom for enemizing at expected path %s." % args.rom)
|
||||||
@@ -242,13 +241,44 @@ def main(args, seed=None, fish=None):
|
|||||||
outfilepname += f'_P{player}'
|
outfilepname += f'_P{player}'
|
||||||
if world.players > 1 or world.teams > 1:
|
if world.players > 1 or world.teams > 1:
|
||||||
outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][team] != 'Player %d' % player else ''
|
outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][team] != 'Player %d' % player else ''
|
||||||
outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s_%s-%s%s%s%s%s' % (world.logic[player], world.difficulty[player], world.difficulty_adjustments[player],
|
outfilestuffs = {
|
||||||
world.mode[player], world.goal[player],
|
"logic": world.logic[player], # 0
|
||||||
"" if world.timer in ['none', 'display'] else "-" + world.timer,
|
"difficulty": world.difficulty[player], # 1
|
||||||
world.shuffle[player], world.doorShuffle[player], world.algorithm, mcsb_name,
|
"difficulty_adjustments": world.difficulty_adjustments[player], # 2
|
||||||
"-retro" if world.retro[player] else "",
|
"mode": world.mode[player], # 3
|
||||||
"-prog_" + world.progressive if world.progressive in ['off', 'random'] else "",
|
"goal": world.goal[player], # 4
|
||||||
"-nohints" if not world.hints[player] else "")) if not args.outputname else ''
|
"timer": str(world.timer), # 5
|
||||||
|
"shuffle": world.shuffle[player], # 6
|
||||||
|
"doorShuffle": world.doorShuffle[player], # 7
|
||||||
|
"algorithm": world.algorithm, # 8
|
||||||
|
"mscb": mcsb_name, # 9
|
||||||
|
"retro": world.retro[player], # A
|
||||||
|
"progressive": world.progressive, # B
|
||||||
|
"hints": 'True' if world.hints[player] else 'False' # C
|
||||||
|
}
|
||||||
|
# 0 1 2 3 4 5 6 7 8 9 A B C
|
||||||
|
outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s_%s-%s%s%s%s%s' % (
|
||||||
|
# 0 1 2 3 4 5 6 7 8 9 A B C
|
||||||
|
# _noglitches_normal-normal-open-ganon-ohko_simple_basic-balanced-keysanity-retro-prog_swords-nohints
|
||||||
|
# _noglitches_normal-normal-open-ganon _simple_basic-balanced-keysanity-retro
|
||||||
|
# _noglitches_normal-normal-open-ganon _simple_basic-balanced-keysanity -prog_swords
|
||||||
|
# _noglitches_normal-normal-open-ganon _simple_basic-balanced-keysanity -nohints
|
||||||
|
outfilestuffs["logic"], # 0
|
||||||
|
|
||||||
|
outfilestuffs["difficulty"], # 1
|
||||||
|
outfilestuffs["difficulty_adjustments"], # 2
|
||||||
|
outfilestuffs["mode"], # 3
|
||||||
|
outfilestuffs["goal"], # 4
|
||||||
|
"" if outfilestuffs["timer"] in ['False', 'none', 'display'] else "-" + outfilestuffs["timer"], # 5
|
||||||
|
|
||||||
|
outfilestuffs["shuffle"], # 6
|
||||||
|
outfilestuffs["doorShuffle"], # 7
|
||||||
|
outfilestuffs["algorithm"], # 8
|
||||||
|
outfilestuffs["mscb"], # 9
|
||||||
|
|
||||||
|
"-retro" if outfilestuffs["retro"] == "True" else "", # A
|
||||||
|
"-prog_" + outfilestuffs["progressive"] if outfilestuffs["progressive"] in ['off', 'random'] else "", # B
|
||||||
|
"-nohints" if not outfilestuffs["hints"] == "True" else "")) if not args.outputname else '' # C
|
||||||
rom.write_to_file(output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.sfc'))
|
rom.write_to_file(output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.sfc'))
|
||||||
|
|
||||||
if world.players > 1:
|
if world.players > 1:
|
||||||
@@ -272,6 +302,10 @@ def main(args, seed=None, fish=None):
|
|||||||
print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()}))
|
print(json.dumps({**jsonout, 'spoiler': world.spoiler.to_json()}))
|
||||||
elif args.create_spoiler:
|
elif args.create_spoiler:
|
||||||
logger.info(world.fish.translate("cli","cli","patching.spoiler"))
|
logger.info(world.fish.translate("cli","cli","patching.spoiler"))
|
||||||
|
if args.jsonout:
|
||||||
|
with open(output_path('%s_Spoiler.json' % outfilebase), 'w') as outfile:
|
||||||
|
outfile.write(world.spoiler.to_json())
|
||||||
|
else:
|
||||||
world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))
|
world.spoiler.to_file(output_path('%s_Spoiler.txt' % outfilebase))
|
||||||
|
|
||||||
YES = world.fish.translate("cli","cli","yes")
|
YES = world.fish.translate("cli","cli","yes")
|
||||||
@@ -282,6 +316,7 @@ def main(args, seed=None, fish=None):
|
|||||||
logger.info(world.fish.translate("cli","cli","made.rom") % (YES if (args.create_rom) else NO))
|
logger.info(world.fish.translate("cli","cli","made.rom") % (YES if (args.create_rom) else NO))
|
||||||
logger.info(world.fish.translate("cli","cli","made.playthrough") % (YES if (args.calc_playthrough) else NO))
|
logger.info(world.fish.translate("cli","cli","made.playthrough") % (YES if (args.calc_playthrough) else NO))
|
||||||
logger.info(world.fish.translate("cli","cli","made.spoiler") % (YES if (not args.jsonout and args.create_spoiler) else NO))
|
logger.info(world.fish.translate("cli","cli","made.spoiler") % (YES if (not args.jsonout and args.create_spoiler) else NO))
|
||||||
|
logger.info(world.fish.translate("cli","cli","used.enemizer") % (YES if enemized else NO))
|
||||||
logger.info(world.fish.translate("cli","cli","seed") + ": %d", world.seed)
|
logger.info(world.fish.translate("cli","cli","seed") + ": %d", world.seed)
|
||||||
logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start)
|
logger.info(world.fish.translate("cli","cli","total.time"), time.perf_counter() - start)
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -7,6 +7,7 @@ import re
|
|||||||
|
|
||||||
from DungeonRandomizer import parse_cli
|
from DungeonRandomizer import parse_cli
|
||||||
from Main import main as DRMain
|
from Main import main as DRMain
|
||||||
|
from source.classes.BabelFish import BabelFish
|
||||||
|
|
||||||
def parse_yaml(txt):
|
def parse_yaml(txt):
|
||||||
def strip(s):
|
def strip(s):
|
||||||
@@ -100,7 +101,7 @@ def main():
|
|||||||
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel]
|
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel]
|
||||||
logging.basicConfig(format='%(message)s', level=loglevel)
|
logging.basicConfig(format='%(message)s', level=loglevel)
|
||||||
|
|
||||||
DRMain(erargs, seed)
|
DRMain(erargs, seed, BabelFish())
|
||||||
|
|
||||||
def get_weights(path):
|
def get_weights(path):
|
||||||
try:
|
try:
|
||||||
@@ -150,6 +151,10 @@ def roll_settings(weights):
|
|||||||
ret.door_shuffle = door_shuffle if door_shuffle != 'none' else 'vanilla'
|
ret.door_shuffle = door_shuffle if door_shuffle != 'none' else 'vanilla'
|
||||||
ret.experimental = get_choice('experimental') == 'on'
|
ret.experimental = get_choice('experimental') == 'on'
|
||||||
|
|
||||||
|
ret.dungeon_counters = get_choice('dungeon_counters')
|
||||||
|
if ret.dungeon_counters == 'default':
|
||||||
|
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
|
||||||
|
|
||||||
goal = get_choice('goals')
|
goal = get_choice('goals')
|
||||||
ret.goal = {'ganon': 'ganon',
|
ret.goal = {'ganon': 'ganon',
|
||||||
'fast_ganon': 'crystals',
|
'fast_ganon': 'crystals',
|
||||||
|
|||||||
+6
-4
@@ -1,6 +1,8 @@
|
|||||||
# Features
|
# New Features
|
||||||
|
|
||||||
## Door Randomizer
|
* None yet
|
||||||
|
|
||||||
* Native GUI executables
|
# Bug Fixes
|
||||||
* Native Dungeon Randomizer CLI executables
|
|
||||||
|
* Crossed Dungeon generation improvements
|
||||||
|
* Fix for Animated Tiles in crossed dungeon
|
||||||
@@ -10,7 +10,7 @@ import sys
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from BaseClasses import CollectionState, ShopType, Region, Location, DoorType
|
from BaseClasses import CollectionState, ShopType, Region, Location, DoorType
|
||||||
from DoorShuffle import compass_data, DROptions
|
from DoorShuffle import compass_data, DROptions, boss_indicator
|
||||||
from Dungeons import dungeon_music_addresses
|
from Dungeons import dungeon_music_addresses
|
||||||
from Regions import location_table
|
from Regions import location_table
|
||||||
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
||||||
@@ -22,7 +22,7 @@ from EntranceShuffle import door_addresses, exit_ids
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = '5e01caffabb4509a0987ef2f2f0bcd56'
|
RANDOMIZERBASEHASH = '6042de1d3a63417efe4397b69c626b88'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -162,7 +162,7 @@ def read_rom(stream):
|
|||||||
|
|
||||||
def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, random_sprite_on_hit):
|
def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, random_sprite_on_hit):
|
||||||
baserom_path = os.path.abspath(baserom_path)
|
baserom_path = os.path.abspath(baserom_path)
|
||||||
basepatch_path = os.path.abspath(local_path('data/base2current.json'))
|
basepatch_path = os.path.abspath(local_path(os.path.join("data","base2current.json")))
|
||||||
enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json")
|
enemizer_basepatch_path = os.path.join(os.path.dirname(enemizercli), "enemizerBasePatch.json")
|
||||||
randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json'))
|
randopatch_path = os.path.abspath(output_path('enemizer_randopatch.json'))
|
||||||
options_path = os.path.abspath(output_path('enemizer_options.json'))
|
options_path = os.path.abspath(output_path('enemizer_options.json'))
|
||||||
@@ -305,7 +305,7 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, shufflepots, r
|
|||||||
_sprite_table = {}
|
_sprite_table = {}
|
||||||
def _populate_sprite_table():
|
def _populate_sprite_table():
|
||||||
if not _sprite_table:
|
if not _sprite_table:
|
||||||
for dir in [local_path('data/sprites/official'), local_path('data/sprites/unofficial')]:
|
for dir in [local_path(os.path.join("data","sprites","official")), local_path(os.path.join("data","sprites","unofficial"))]:
|
||||||
for file in os.listdir(dir):
|
for file in os.listdir(dir):
|
||||||
filepath = os.path.join(dir, file)
|
filepath = os.path.join(dir, file)
|
||||||
if not os.path.isfile(filepath):
|
if not os.path.isfile(filepath):
|
||||||
@@ -387,7 +387,7 @@ class Sprite(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_link_sprite():
|
def default_link_sprite():
|
||||||
return Sprite(local_path('data/default.zspr'))
|
return get_sprite_from_name('Link')
|
||||||
|
|
||||||
def decode8(self, pos):
|
def decode8(self, pos):
|
||||||
arr = [[0 for _ in range(8)] for _ in range(8)]
|
arr = [[0 for _ in range(8)] for _ in range(8)]
|
||||||
@@ -594,10 +594,22 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
if world.mode[player] == 'inverted':
|
if world.mode[player] == 'inverted':
|
||||||
patch_shuffled_dark_sanc(world, rom, player)
|
patch_shuffled_dark_sanc(world, rom, player)
|
||||||
|
|
||||||
|
# setup dr option flags based on experimental, etc.
|
||||||
|
dr_flags = DROptions.Eternal_Mini_Bosses if world.doorShuffle[player] == 'vanilla' else DROptions.Town_Portal
|
||||||
|
if world.experimental[player]:
|
||||||
|
dr_flags |= DROptions.Map_Info
|
||||||
|
|
||||||
# patch doors
|
# patch doors
|
||||||
dr_flags = DROptions.Eternal_Mini_Bosses if world.doorShuffle[player] == 'vanilla' or not world.experimental[player] else DROptions.Town_Portal
|
|
||||||
if world.doorShuffle[player] == 'crossed':
|
if world.doorShuffle[player] == 'crossed':
|
||||||
rom.write_byte(0x139004, 2)
|
rom.write_byte(0x139004, 2)
|
||||||
|
for name, layout in world.key_layout[player].items():
|
||||||
|
offset = compass_data[name][4]//2
|
||||||
|
rom.write_byte(0x13f01c+offset, layout.max_chests + layout.max_drops)
|
||||||
|
rom.write_byte(0x13f02a+offset, layout.max_chests)
|
||||||
|
builder = world.dungeon_layouts[player][name]
|
||||||
|
bk_status = 1 if builder.bk_required else 0
|
||||||
|
bk_status = 2 if builder.bk_provided else bk_status
|
||||||
|
rom.write_byte(0x13f038+offset*2, bk_status)
|
||||||
rom.write_byte(0x151f1, 2)
|
rom.write_byte(0x151f1, 2)
|
||||||
rom.write_byte(0x15270, 2)
|
rom.write_byte(0x15270, 2)
|
||||||
rom.write_byte(0x1597b, 2)
|
rom.write_byte(0x1597b, 2)
|
||||||
@@ -622,6 +634,13 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
if builder.pre_open_stonewall:
|
if builder.pre_open_stonewall:
|
||||||
if builder.pre_open_stonewall.name == 'Desert Wall Slide NW':
|
if builder.pre_open_stonewall.name == 'Desert Wall Slide NW':
|
||||||
dr_flags |= DROptions.Open_Desert_Wall
|
dr_flags |= DROptions.Open_Desert_Wall
|
||||||
|
for name, pair in boss_indicator.items():
|
||||||
|
dungeon_id, boss_door = pair
|
||||||
|
opposite_door = world.get_door(boss_door, player).dest
|
||||||
|
if opposite_door.roomIndex > -1:
|
||||||
|
dungeon_name = opposite_door.entrance.parent_region.dungeon.name
|
||||||
|
dungeon_id = boss_indicator[dungeon_name][0]
|
||||||
|
rom.write_byte(0x13f000+dungeon_id, opposite_door.roomIndex)
|
||||||
rom.write_byte(0x139006, dr_flags.value)
|
rom.write_byte(0x139006, dr_flags.value)
|
||||||
if dr_flags & DROptions.Town_Portal and world.mode[player] == 'inverted':
|
if dr_flags & DROptions.Town_Portal and world.mode[player] == 'inverted':
|
||||||
rom.write_byte(0x139008, 1)
|
rom.write_byte(0x139008, 1)
|
||||||
@@ -1048,6 +1067,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
'Big Key (Desert Palace)': (0x367, 0x10), 'Compass (Desert Palace)': (0x365, 0x10), 'Map (Desert Palace)': (0x369, 0x10),
|
'Big Key (Desert Palace)': (0x367, 0x10), 'Compass (Desert Palace)': (0x365, 0x10), 'Map (Desert Palace)': (0x369, 0x10),
|
||||||
'Big Key (Tower of Hera)': (0x366, 0x20), 'Compass (Tower of Hera)': (0x364, 0x20), 'Map (Tower of Hera)': (0x368, 0x20),
|
'Big Key (Tower of Hera)': (0x366, 0x20), 'Compass (Tower of Hera)': (0x364, 0x20), 'Map (Tower of Hera)': (0x368, 0x20),
|
||||||
'Big Key (Escape)': (0x367, 0xC0), 'Compass (Escape)': (0x365, 0xC0), 'Map (Escape)': (0x369, 0xC0),
|
'Big Key (Escape)': (0x367, 0xC0), 'Compass (Escape)': (0x365, 0xC0), 'Map (Escape)': (0x369, 0xC0),
|
||||||
|
'Big Key (Agahnims Tower)': (0x367, 0x08), 'Compass (Agahnims Tower)': (0x365, 0x08), 'Map (Agahnims Tower)': (0x369, 0x08),
|
||||||
'Big Key (Palace of Darkness)': (0x367, 0x02), 'Compass (Palace of Darkness)': (0x365, 0x02), 'Map (Palace of Darkness)': (0x369, 0x02),
|
'Big Key (Palace of Darkness)': (0x367, 0x02), 'Compass (Palace of Darkness)': (0x365, 0x02), 'Map (Palace of Darkness)': (0x369, 0x02),
|
||||||
'Big Key (Thieves Town)': (0x366, 0x10), 'Compass (Thieves Town)': (0x364, 0x10), 'Map (Thieves Town)': (0x368, 0x10),
|
'Big Key (Thieves Town)': (0x366, 0x10), 'Compass (Thieves Town)': (0x364, 0x10), 'Map (Thieves Town)': (0x368, 0x10),
|
||||||
'Big Key (Skull Woods)': (0x366, 0x80), 'Compass (Skull Woods)': (0x364, 0x80), 'Map (Skull Woods)': (0x368, 0x80),
|
'Big Key (Skull Woods)': (0x366, 0x80), 'Compass (Skull Woods)': (0x364, 0x80), 'Map (Skull Woods)': (0x368, 0x80),
|
||||||
@@ -1173,8 +1193,8 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
|
|
||||||
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] else 0x00)
|
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] else 0x00)
|
||||||
| (0x02 if world.bigkeyshuffle[player] else 0x00)
|
| (0x02 if world.bigkeyshuffle[player] else 0x00)
|
||||||
| (0x04 if world.compassshuffle[player] else 0x00)
|
| (0x04 if world.mapshuffle[player] else 0x00)
|
||||||
| (0x08 if world.mapshuffle[player] else 0x00))) # free roaming items in menu
|
| (0x08 if world.compassshuffle[player] else 0x00))) # free roaming items in menu
|
||||||
|
|
||||||
# Map reveals
|
# Map reveals
|
||||||
reveal_bytes = {
|
reveal_bytes = {
|
||||||
@@ -1232,6 +1252,7 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180185, [0,0,0]) # Uncle respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [0,0,0]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x18018B, [0,0,0]) # Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
bow_max, bomb_max, magic_max = 0, 0, 0
|
||||||
if world.mode[player] == 'standard':
|
if world.mode[player] == 'standard':
|
||||||
if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']:
|
if uncle_location.item is not None and uncle_location.item.name in ['Bow', 'Progressive Bow']:
|
||||||
rom.write_byte(0x18004E, 1) # Escape Fill (arrows)
|
rom.write_byte(0x18004E, 1) # Escape Fill (arrows)
|
||||||
@@ -1239,16 +1260,25 @@ def patch_rom(world, rom, player, team, enemized):
|
|||||||
rom.write_bytes(0x180185, [0,0,70]) # Uncle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180185, [0,0,70]) # Uncle respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x180188, [0,0,10]) # Zelda respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [0,0,10]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x18018B, [0,0,10]) # Mantle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x18018B, [0,0,10]) # Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
bow_max = 70
|
||||||
elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']:
|
elif uncle_location.item is not None and uncle_location.item.name in ['Bombs (10)']:
|
||||||
rom.write_byte(0x18004E, 2) # Escape Fill (bombs)
|
rom.write_byte(0x18004E, 2) # Escape Fill (bombs)
|
||||||
rom.write_bytes(0x180185, [0,50,0]) # Uncle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180185, [0,50,0]) # Uncle respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x180188, [0,3,0]) # Zelda respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [0,3,0]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x18018B, [0,3,0]) # Mantle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x18018B, [0,3,0]) # Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
bomb_max = 50
|
||||||
elif uncle_location.item is not None and uncle_location.item.name in ['Cane of Somaria', 'Cane of Byrna', 'Fire Rod']:
|
elif uncle_location.item is not None and uncle_location.item.name in ['Cane of Somaria', 'Cane of Byrna', 'Fire Rod']:
|
||||||
rom.write_byte(0x18004E, 4) # Escape Fill (magic)
|
rom.write_byte(0x18004E, 4) # Escape Fill (magic)
|
||||||
rom.write_bytes(0x180185, [0x80,0,0]) # Uncle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180185, [0x80,0,0]) # Uncle respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x180188, [0x20,0,0]) # Zelda respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x180188, [0x20,0,0]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
rom.write_bytes(0x18018B, [0x20,0,0]) # Mantle respawn refills (magic, bombs, arrows)
|
rom.write_bytes(0x18018B, [0x20,0,0]) # Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
magic_max = 0x80
|
||||||
|
if world.doorShuffle[player] == 'crossed':
|
||||||
|
# Uncle respawn refills (magic, bombs, arrows)
|
||||||
|
rom.write_bytes(0x180185, [max(0x20, magic_max), max(3, bomb_max), max(10, bow_max)])
|
||||||
|
rom.write_bytes(0x180188, [0x20, 3, 10]) # Zelda respawn refills (magic, bombs, arrows)
|
||||||
|
rom.write_bytes(0x18018B, [0x20, 3, 10]) # Mantle respawn refills (magic, bombs, arrows)
|
||||||
|
|
||||||
|
|
||||||
# patch swamp: Need to enable permanent drain of water as dam or swamp were moved
|
# patch swamp: Need to enable permanent drain of water as dam or swamp were moved
|
||||||
rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required[player] else 0x00)
|
rom.write_byte(0x18003D, 0x01 if world.swamp_patch_required[player] else 0x00)
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ def is_bundled():
|
|||||||
return getattr(sys, 'frozen', False)
|
return getattr(sys, 'frozen', False)
|
||||||
|
|
||||||
def local_path(path):
|
def local_path(path):
|
||||||
return path
|
|
||||||
|
|
||||||
if local_path.cached_path is not None:
|
if local_path.cached_path is not None:
|
||||||
return os.path.join(local_path.cached_path, path)
|
return os.path.join(local_path.cached_path, path)
|
||||||
|
|
||||||
@@ -269,17 +267,54 @@ def print_wiki_doors_by_region(d_regions, world, player):
|
|||||||
f.write(toprint)
|
f.write(toprint)
|
||||||
|
|
||||||
def update_deprecated_args(args):
|
def update_deprecated_args(args):
|
||||||
|
if args:
|
||||||
argVars = vars(args)
|
argVars = vars(args)
|
||||||
truthy = [ 1, True, "True", "true" ]
|
truthy = [ 1, True, "True", "true" ]
|
||||||
|
# Hints default to TRUE
|
||||||
|
# Don't do: Yes
|
||||||
|
# Do: No
|
||||||
|
if "no_hints" in argVars:
|
||||||
|
src = "no_hints"
|
||||||
|
if isinstance(argVars["hints"],dict):
|
||||||
|
tmp = {}
|
||||||
|
for idx in range(1,len(argVars["hints"]) + 1):
|
||||||
|
tmp[idx] = argVars[src] not in truthy # tmp = !src
|
||||||
|
args.hints = tmp # dest = tmp
|
||||||
|
else:
|
||||||
|
args.hints = args.no_hints not in truthy # dest = !src
|
||||||
|
# Don't do: No
|
||||||
|
# Do: Yes
|
||||||
|
if "hints" in argVars:
|
||||||
|
src = "hints"
|
||||||
|
if isinstance(argVars["hints"],dict):
|
||||||
|
tmp = {}
|
||||||
|
for idx in range(1,len(argVars["hints"]) + 1):
|
||||||
|
tmp[idx] = argVars[src] not in truthy # tmp = !src
|
||||||
|
args.no_hints = tmp # dest = tmp
|
||||||
|
else:
|
||||||
|
args.no_hints = args.hints not in truthy # dest = !src
|
||||||
|
|
||||||
|
# Spoiler defaults to FALSE
|
||||||
|
# Don't do: No
|
||||||
|
# Do: Yes
|
||||||
|
if "create_spoiler" in argVars:
|
||||||
|
args.suppress_spoiler = not args.create_spoiler in truthy
|
||||||
|
# Don't do: Yes
|
||||||
|
# Do: No
|
||||||
|
if "suppress_spoiler" in argVars:
|
||||||
|
args.create_spoiler = not args.suppress_spoiler in truthy
|
||||||
|
|
||||||
|
# ROM defaults to TRUE
|
||||||
# Don't do: Yes
|
# Don't do: Yes
|
||||||
# Do: No
|
# Do: No
|
||||||
if "suppress_rom" in argVars:
|
if "suppress_rom" in argVars:
|
||||||
args.create_rom = args.suppress_rom not in truthy
|
args.create_rom = not args.suppress_rom in truthy
|
||||||
# Don't do: No
|
# Don't do: No
|
||||||
# Do: Yes
|
# Do: Yes
|
||||||
if "create_rom" in argVars:
|
if "create_rom" in argVars:
|
||||||
args.suppress_rom = not args.create_rom in truthy
|
args.suppress_rom = not args.create_rom in truthy
|
||||||
|
|
||||||
|
# Shuffle Ganon defaults to TRUE
|
||||||
# Don't do: Yes
|
# Don't do: Yes
|
||||||
# Do: No
|
# Do: No
|
||||||
if "no_shuffleganon" in argVars:
|
if "no_shuffleganon" in argVars:
|
||||||
@@ -289,6 +324,7 @@ def update_deprecated_args(args):
|
|||||||
if "shuffleganon" in argVars:
|
if "shuffleganon" in argVars:
|
||||||
args.no_shuffleganon = not args.shuffleganon in truthy
|
args.no_shuffleganon = not args.shuffleganon in truthy
|
||||||
|
|
||||||
|
# Playthrough defaults to TRUE
|
||||||
# Don't do: Yes
|
# Don't do: Yes
|
||||||
# Do: No
|
# Do: No
|
||||||
if "skip_playthrough" in argVars:
|
if "skip_playthrough" in argVars:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ incsrc keydoors.asm
|
|||||||
incsrc overrides.asm
|
incsrc overrides.asm
|
||||||
incsrc edges.asm
|
incsrc edges.asm
|
||||||
incsrc math.asm
|
incsrc math.asm
|
||||||
|
incsrc hudadditions.asm
|
||||||
warnpc $279000
|
warnpc $279000
|
||||||
|
|
||||||
; Data Section
|
; Data Section
|
||||||
|
|||||||
@@ -1,3 +1,23 @@
|
|||||||
|
org $279500
|
||||||
|
TilesetTable:
|
||||||
|
; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler
|
||||||
|
db $13,$04,$04,$06,$0d,$ff,$08,$05,$06,$07,$07,$07,$0e,$0e,$0b,$ff
|
||||||
|
db $13,$04,$04,$0d,$0d,$0d,$08,$05,$06,$07,$07,$07,$0e,$0e,$0b,$0b
|
||||||
|
db $04,$04,$04,$0d,$0d,$ff,$08,$05,$08,$09,$07,$07,$06,$ff,$0b,$06
|
||||||
|
db $04,$05,$04,$12,$08,$08,$08,$08,$08,$09,$07,$07,$06,$0e,$0b,$0b
|
||||||
|
db $04,$04,$04,$12,$0a,$0a,$08,$ff,$ff,$09,$07,$07,$0e,$0e,$0b,$0b
|
||||||
|
db $04,$04,$04,$12,$08,$01,$09,$09,$09,$09,$07,$0e,$0e,$0e,$0b,$0b
|
||||||
|
db $04,$04,$04,$12,$0a,$0a,$08,$09,$09,$ff,$07,$0e,$0e,$0e,$0b,$ff
|
||||||
|
db $04,$04,$04,$12,$12,$12,$08,$05,$ff,$ff,$ff,$0e,$0e,$0e,$0b,$0b
|
||||||
|
db $04,$04,$04,$12,$12,$12,$ff,$05,$ff,$05,$ff,$0e,$0e,$0e,$0b,$ff
|
||||||
|
db $0c,$0c,$0c,$0c,$ff,$0e,$0e,$0c,$0c,$05,$ff,$0e,$0e,$0e,$0b,$0b
|
||||||
|
db $0c,$0c,$0c,$0c,$0d,$0e,$0e,$05,$05,$05,$05,$0a,$0a,$ff,$0b,$0b
|
||||||
|
db $04,$0c,$0c,$0c,$0d,$0d,$0d,$0d,$05,$05,$05,$0a,$0a,$ff,$0b,$0b
|
||||||
|
db $04,$0c,$0c,$0c,$0d,$0d,$0d,$0d,$05,$05,$ff,$0a,$0a,$ff,$0b,$ff
|
||||||
|
db $04,$0c,$0c,$ff,$ff,$0d,$0d,$ff,$05,$05,$05,$0a,$0a,$ff,$0b,$06
|
||||||
|
db $04,$06,$06,$06,$06,$06,$06,$06,$06,$ff,$06,$06,$ff,$06,$06,$06
|
||||||
|
db $06,$06,$03,$03,$03,$03,$ff,$ff,$06,$06,$06,$06,$ff,$06,$06,$06
|
||||||
|
|
||||||
org $279700
|
org $279700
|
||||||
KeyDoorOffset:
|
KeyDoorOffset:
|
||||||
; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler
|
; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler
|
||||||
@@ -545,3 +565,20 @@ db $58,$50,$30, $98,$50,$70 ; TT Ambush
|
|||||||
db $58,$50,$30 ; TT Nook
|
db $58,$50,$30 ; TT Nook
|
||||||
MultDivInfo: ; (1placeholder, 1, 2, 3, 4, 5, 6, 10, 20)
|
MultDivInfo: ; (1placeholder, 1, 2, 3, 4, 5, 6, 10, 20)
|
||||||
db $01, $01, $02, $03, $04, $05, $06, $0a, $14
|
db $01, $01, $02, $03, $04, $05, $06, $0a, $14
|
||||||
|
|
||||||
|
|
||||||
|
; dungeon tables
|
||||||
|
; HC HC EP DP AT SP PD MM SW IP TH TT TR GT
|
||||||
|
org $27f000
|
||||||
|
CompassBossIndicator:
|
||||||
|
dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000
|
||||||
|
TotalKeys: ;27f01c
|
||||||
|
db $04, $04, $02, $04, $04, $06, $06, $06, $05, $06, $01, $03, $06, $08
|
||||||
|
ChestKeys: ;27f02a
|
||||||
|
db $01, $01, $00, $01, $02, $01, $06, $03, $03, $02, $01, $01, $04, $04
|
||||||
|
BigKeyStatus: ;27f038 (status 2 indicate BnC guard)
|
||||||
|
dw $0002, $0002, $0001, $0001, $0000, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001, $0001
|
||||||
|
DungeonReminderTable: ;27f054
|
||||||
|
dw $2D50, $2D50, $2D51, $2D52, $2D54, $2D56, $2D55, $2D5A, $2D57, $2D59, $2D53, $2D58, $2D5B, $2D5C
|
||||||
|
;27f070
|
||||||
|
|
||||||
|
|||||||
+30
-2
@@ -38,7 +38,7 @@ org $029396 ; <- 11384 - Bank02.asm : 3641 (LDA $01C322, X)
|
|||||||
jsl StraightStairLayerFix
|
jsl StraightStairLayerFix
|
||||||
|
|
||||||
; Graphics fix
|
; Graphics fix
|
||||||
org $02895d
|
org $02895d ; Bank 02 line 1812 (JSL Dungeon_LoadRoom : JSL Dungeon_InitStarTileChr : JSL $00D6F9 : INC $B0)
|
||||||
Splicer:
|
Splicer:
|
||||||
jsl GfxFixer
|
jsl GfxFixer
|
||||||
lda $b1 : beq .done
|
lda $b1 : beq .done
|
||||||
@@ -46,10 +46,14 @@ rts
|
|||||||
nop #5
|
nop #5
|
||||||
.done
|
.done
|
||||||
|
|
||||||
org $00fda4
|
org $00d377 ;Bank 00 line 3185
|
||||||
|
DecompDungAnimatedTiles:
|
||||||
|
org $00fda4 ;Bank 00 line 8882
|
||||||
Dungeon_InitStarTileCh:
|
Dungeon_InitStarTileCh:
|
||||||
org $00d6ae ;(PC: 56ae)
|
org $00d6ae ;(PC: 56ae)
|
||||||
LoadTransAuxGfx:
|
LoadTransAuxGfx:
|
||||||
|
org $00d739 ;
|
||||||
|
LoadTransAuxGfx_Alt:
|
||||||
org $00df5a ;(PC: 5f5a)
|
org $00df5a ;(PC: 5f5a)
|
||||||
PrepTransAuxGfx:
|
PrepTransAuxGfx:
|
||||||
org $0ffd65 ;(PC: 07fd65)
|
org $0ffd65 ;(PC: 07fd65)
|
||||||
@@ -86,7 +90,31 @@ org $2081f2
|
|||||||
jsl MirrorCheckOverride2
|
jsl MirrorCheckOverride2
|
||||||
org $20825c
|
org $20825c
|
||||||
jsl MirrorCheckOverride2
|
jsl MirrorCheckOverride2
|
||||||
|
org $07a955 ; <- Bank07.asm : around 6564 (JP is a bit different) (STZ $05FC : STZ $05FD)
|
||||||
|
jsl BlockEraseFix
|
||||||
|
nop #2
|
||||||
|
|
||||||
|
org $02b82a
|
||||||
|
jsl FixShopCode
|
||||||
|
|
||||||
|
org $1ddeea ; <- Bank1D.asm : 286 (JSL Sprite_LoadProperties)
|
||||||
|
jsl VitreousKeyReset
|
||||||
|
|
||||||
|
org $1ed024 ; f5024 sprite_guruguru_bar.asm : 27 (LDA $040C : CMP.b #$12 : INY #2
|
||||||
|
jsl GuruguruFix : bra .next
|
||||||
|
nop #3
|
||||||
|
.next
|
||||||
|
|
||||||
|
; also rando's hooks.asm line 1360
|
||||||
|
org $a0ee11 ; <- 6FC4C - headsup_display.asm : 836 (LDA $7EF36E : AND.w #$00FF : ADD.w #$0007 : AND.w #$FFF8 : TAX)
|
||||||
|
jsl DrHudOverride
|
||||||
|
org $098638 ; rando's hooks.asm line 2192
|
||||||
|
jsl CountChestKeys
|
||||||
|
org $06D192 ; rando's hooks.asm line 457
|
||||||
|
jsl CountAbsorbedKeys
|
||||||
|
; rando's hooks.asm line 1020
|
||||||
|
org $05FC7E ; <- 2FC7E - sprite_dash_item.asm : 118 (LDA $7EF36F : INC A : STA $7EF36F)
|
||||||
|
jsl CountBonkItem
|
||||||
|
|
||||||
; These two, if enabled together, have implications for vanilla BK doors in IP/Hera/Mire
|
; 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
|
; IPBJ is common enough to consider not doing this. Mire is not a concern for vanilla - maybe glitched modes
|
||||||
|
|||||||
+14
-1
@@ -1,11 +1,24 @@
|
|||||||
GfxFixer:
|
GfxFixer:
|
||||||
{
|
{
|
||||||
lda $b1 : bne .stage2
|
lda DRMode : bne +
|
||||||
|
jsl LoadRoomHook ;this is the code we overwrote
|
||||||
|
jsl Dungeon_InitStarTileCh
|
||||||
|
jsl LoadTransAuxGfx_Alt
|
||||||
|
inc $b0
|
||||||
|
rtl
|
||||||
|
+ lda $b1 : bne .stage2
|
||||||
jsl LoadRoomHook ; this is the rando version - let's only call this guy once - may fix star tiles and slower loads
|
jsl LoadRoomHook ; this is the rando version - let's only call this guy once - may fix star tiles and slower loads
|
||||||
jsl Dungeon_InitStarTileCh
|
jsl Dungeon_InitStarTileCh
|
||||||
jsl LoadTransAuxGfx
|
jsl LoadTransAuxGfx
|
||||||
jsl Dungeon_LoadCustomTileAttr
|
jsl Dungeon_LoadCustomTileAttr
|
||||||
jsl PrepTransAuxGfx
|
jsl PrepTransAuxGfx
|
||||||
|
lda DRMode : cmp #$02 : bne + ; only do this in crossed mode
|
||||||
|
ldx $a0 : lda TilesetTable, x
|
||||||
|
cmp $0aa1 : beq + ; already eq no need to decomp
|
||||||
|
sta $0aa1
|
||||||
|
tax : lda $02802e, x : tay
|
||||||
|
jsl DecompDungAnimatedTiles
|
||||||
|
+
|
||||||
lda #$09 : sta $17 : sta $0710
|
lda #$09 : sta $17 : sta $0710
|
||||||
jsl Palette_SpriteAux3
|
jsl Palette_SpriteAux3
|
||||||
jsl Palette_SpriteAux2
|
jsl Palette_SpriteAux2
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
DrHudOverride:
|
||||||
|
{
|
||||||
|
jsl.l NewDrawHud
|
||||||
|
jsr HudAdditions
|
||||||
|
rtl
|
||||||
|
}
|
||||||
|
|
||||||
|
HudAdditions:
|
||||||
|
{
|
||||||
|
ldx $040c : cpx #$ff : bne + : rts : +
|
||||||
|
lda DRMode : bne + : rts : +
|
||||||
|
phb : phk : plb
|
||||||
|
lda $7ef364 : and.l $0098c0, x : beq +
|
||||||
|
lda CompassBossIndicator, x : and #$00ff : cmp $a0 : bne +
|
||||||
|
lda $1a : and #$0010 : beq +
|
||||||
|
lda #$345e : sta $7ec790 : bra .next
|
||||||
|
+ lda #$207f : sta $7ec790
|
||||||
|
.next lda DRMode : and #$0002 : bne + : plb : rts : +
|
||||||
|
lda $7ef36d : and #$00ff : beq +
|
||||||
|
lda DungeonReminderTable, x : bra .reminder
|
||||||
|
+ lda #$207f
|
||||||
|
.reminder sta $7ec702
|
||||||
|
+ lda DRFlags : and #$0004 : beq .restore
|
||||||
|
lda $7ef368 : and.l $0098c0, x : beq .restore
|
||||||
|
|
||||||
|
lda #$2811 : sta $7ec740
|
||||||
|
lda $7ef366 : and.l $0098c0, x : bne .check
|
||||||
|
lda BigKeyStatus, x : bne + ; change this, if bk status changes to one byte
|
||||||
|
lda #$2574 : bra ++
|
||||||
|
+ cmp #$0002 : bne +
|
||||||
|
lda #$2420 : bra ++
|
||||||
|
+ lda #$207f : bra ++
|
||||||
|
.check lda #$2826
|
||||||
|
++ sta $7ec742
|
||||||
|
txa : lsr : tax
|
||||||
|
|
||||||
|
lda $7ef4e0, x : jsr ConvertToDisplay : sta $7ec7a2
|
||||||
|
lda #$2830 : sta $7ec7a4
|
||||||
|
lda ChestKeys, x : jsr ConvertToDisplay : sta $7ec7a6
|
||||||
|
|
||||||
|
lda #$2871 : sta $7ec780
|
||||||
|
lda TotalKeys, x
|
||||||
|
sep #$20 : !sub $7ef4b0, x : rep #$20
|
||||||
|
jsr ConvertToDisplay : sta $7ec782
|
||||||
|
|
||||||
|
.restore
|
||||||
|
plb : rts
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertToDisplay:
|
||||||
|
and #$00ff : cmp #$000a : !blt +
|
||||||
|
!add #$2553 : rts
|
||||||
|
+ !add #$2490 : rts
|
||||||
|
|
||||||
|
|
||||||
|
CountChestKeys:
|
||||||
|
jsl ItemDowngradeFix
|
||||||
|
jsr CountChest
|
||||||
|
rtl
|
||||||
|
|
||||||
|
CountChest:
|
||||||
|
lda !MULTIWORLD_ITEM_PLAYER_ID : bne .end
|
||||||
|
cpy #$24 : beq +
|
||||||
|
cpy #$a0 : !blt .end
|
||||||
|
cpy #$ae : !bge .end
|
||||||
|
pha : phx
|
||||||
|
tya : and #$0f : bne ++
|
||||||
|
inc a
|
||||||
|
++ tax : bra .count
|
||||||
|
+ pha : phx
|
||||||
|
lda $040c : lsr : tax
|
||||||
|
.count
|
||||||
|
lda $7ef4b0, x : inc : sta $7ef4b0, x
|
||||||
|
lda $7ef4e0, x : inc : sta $7ef4e0, x
|
||||||
|
.restore plx : pla
|
||||||
|
.end rts
|
||||||
|
|
||||||
|
CountAbsorbedKeys:
|
||||||
|
jsl IncrementSmallKeysNoPrimary : phx
|
||||||
|
lda $040c : cmp #$ff : beq +
|
||||||
|
lsr : tax
|
||||||
|
lda $7ef4b0, x : inc : sta $7ef4b0, x
|
||||||
|
+ plx : rtl
|
||||||
|
|
||||||
|
CountBonkItem:
|
||||||
|
jsl GiveBonkItem
|
||||||
|
lda $a0 ; check room ID - only bonk keys in 2 rooms so we're just checking the lower byte
|
||||||
|
cmp #115 : bne + ; Desert Bonk Key
|
||||||
|
lda.l BonkKey_Desert
|
||||||
|
bra ++
|
||||||
|
+ : cmp #140 : bne + ; GTower Bonk Key
|
||||||
|
lda.l BonkKey_GTower
|
||||||
|
bra ++
|
||||||
|
+ lda.b #$24 ; default to small key
|
||||||
|
++
|
||||||
|
phy : tay : jsr CountChest : ply
|
||||||
|
rtl
|
||||||
+2
-1
@@ -12,8 +12,9 @@
|
|||||||
CheckIfDoorsOpen: {
|
CheckIfDoorsOpen: {
|
||||||
jsr TrapDoorFixer ; see normal.asm
|
jsr TrapDoorFixer ; see normal.asm
|
||||||
; note we are 16bit mode right now
|
; note we are 16bit mode right now
|
||||||
|
lda DRMode : beq +
|
||||||
lda $040c : cmp #$00ff : bne .gtg
|
lda $040c : cmp #$00ff : bne .gtg
|
||||||
lda $a0 : dec : tax : and #$000f ; hijacked code
|
+ lda $a0 : dec : tax : and #$000f ; hijacked code
|
||||||
sec : rtl ; set carry to indicate normal behavior
|
sec : rtl ; set carry to indicate normal behavior
|
||||||
|
|
||||||
.gtg
|
.gtg
|
||||||
|
|||||||
@@ -51,3 +51,26 @@ MirrorCheckOverride:
|
|||||||
|
|
||||||
MirrorCheckOverride2:
|
MirrorCheckOverride2:
|
||||||
lda $7ef353 : and #$02 : rtl
|
lda $7ef353 : and #$02 : rtl
|
||||||
|
|
||||||
|
|
||||||
|
BlockEraseFix:
|
||||||
|
lda $7ef353 : and #$02 : beq +
|
||||||
|
stz $05fc : stz $05fd
|
||||||
|
+ rtl
|
||||||
|
|
||||||
|
FixShopCode:
|
||||||
|
cpx #$300 : !bge +
|
||||||
|
sta $7ef000, x
|
||||||
|
+ rtl
|
||||||
|
|
||||||
|
VitreousKeyReset:
|
||||||
|
lda DRMode : beq +
|
||||||
|
stz $0cba, x
|
||||||
|
+ jsl $0db818 ;restore old code
|
||||||
|
rtl
|
||||||
|
|
||||||
|
GuruguruFix:
|
||||||
|
lda $a0 : cmp #$df : !bge +
|
||||||
|
and #$0f : cmp #$0e : !blt +
|
||||||
|
iny #2
|
||||||
|
+ rtl
|
||||||
@@ -7,6 +7,7 @@ RecordStairType: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpiralWarp: {
|
SpiralWarp: {
|
||||||
|
lda DRMode : beq .abort ; abort if not DR
|
||||||
lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon
|
lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon
|
||||||
lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A!
|
lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A!
|
||||||
cmp #$5f : beq .gtg
|
cmp #$5f : beq .gtg
|
||||||
@@ -66,6 +67,16 @@ SpiralWarp: {
|
|||||||
ldy #$01 : jsr SetCamera
|
ldy #$01 : jsr SetCamera
|
||||||
|
|
||||||
stz $045e ; clear the staircase flag
|
stz $045e ; clear the staircase flag
|
||||||
|
|
||||||
|
; animated tiles fix
|
||||||
|
lda DRMode : cmp #$02 : bne + ; only do this in crossed mode
|
||||||
|
ldx $a0 : lda TilesetTable, x
|
||||||
|
cmp $0aa1 : beq + ; already eq no need to decomp
|
||||||
|
sta $0aa1
|
||||||
|
tax : lda $02802e, x : tay
|
||||||
|
jsl DecompDungAnimatedTiles
|
||||||
|
+
|
||||||
|
|
||||||
ply : plx : plb ; pull the stuff we pushed
|
ply : plx : plb ; pull the stuff we pushed
|
||||||
lda $a2 : and #$0f ; this is the code we are hijacking
|
lda $a2 : and #$0f ; this is the code we are hijacking
|
||||||
rtl
|
rtl
|
||||||
|
|||||||
+4
-1
@@ -3,6 +3,9 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# Spec file
|
||||||
|
SPEC_FILE = os.path.join("DungeonRandomizer.spec")
|
||||||
|
|
||||||
# Destination is current dir
|
# Destination is current dir
|
||||||
DEST_DIRECTORY = '.'
|
DEST_DIRECTORY = '.'
|
||||||
|
|
||||||
@@ -16,7 +19,7 @@ if os.path.isdir("build") and not sys.platform.find("mac") and not sys.platform.
|
|||||||
shutil.rmtree("build")
|
shutil.rmtree("build")
|
||||||
|
|
||||||
# Run pyinstaller for DungeonRandomizer
|
# Run pyinstaller for DungeonRandomizer
|
||||||
subprocess.run(" ".join(["pyinstaller DungeonRandomizer.spec ",
|
subprocess.run(" ".join([f"pyinstaller {SPEC_FILE} ",
|
||||||
upx_string,
|
upx_string,
|
||||||
"-y ",
|
"-y ",
|
||||||
"--onefile ",
|
"--onefile ",
|
||||||
|
|||||||
+4
-1
@@ -3,6 +3,9 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# Spec file
|
||||||
|
SPEC_FILE = os.path.join("Gui.spec")
|
||||||
|
|
||||||
# Destination is current dir
|
# Destination is current dir
|
||||||
DEST_DIRECTORY = '.'
|
DEST_DIRECTORY = '.'
|
||||||
|
|
||||||
@@ -16,7 +19,7 @@ if os.path.isdir("build") and not sys.platform.find("mac") and not sys.platform.
|
|||||||
shutil.rmtree("build")
|
shutil.rmtree("build")
|
||||||
|
|
||||||
# Run pyinstaller for Gui
|
# Run pyinstaller for Gui
|
||||||
subprocess.run(" ".join(["pyinstaller Gui.spec ",
|
subprocess.run(" ".join([f"pyinstaller {SPEC_FILE} ",
|
||||||
upx_string,
|
upx_string,
|
||||||
"-y ",
|
"-y ",
|
||||||
"--onefile ",
|
"--onefile ",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
aioconsole==0.1.15
|
|
||||||
colorama==0.4.3
|
|
||||||
websockets==8.1
|
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
{
|
{
|
||||||
"lang": {},
|
"lang": {},
|
||||||
|
"diags": {
|
||||||
|
"action": "store_true",
|
||||||
|
"type": "bool"
|
||||||
|
},
|
||||||
"create_spoiler": {
|
"create_spoiler": {
|
||||||
"action": "store_true",
|
"action": "store_true",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
},
|
||||||
|
"suppress_spoiler": {
|
||||||
|
"action": "store_false",
|
||||||
|
"dest": "create_spoiler",
|
||||||
|
"help": "suppress"
|
||||||
|
},
|
||||||
"logic": {
|
"logic": {
|
||||||
"choices": [
|
"choices": [
|
||||||
"noglitches",
|
"noglitches",
|
||||||
@@ -195,9 +204,14 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hints": {
|
"hints": {
|
||||||
"action": "store_true",
|
"action": "store_false",
|
||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
},
|
||||||
|
"no_hints": {
|
||||||
|
"action": "store_true",
|
||||||
|
"dest": "hints",
|
||||||
|
"help": "suppress"
|
||||||
|
},
|
||||||
"heartbeep": {
|
"heartbeep": {
|
||||||
"choices": [
|
"choices": [
|
||||||
"normal",
|
"normal",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"made.rom": "Patched ROM: %s",
|
"made.rom": "Patched ROM: %s",
|
||||||
"made.playthrough": "Printed Playthrough: %s",
|
"made.playthrough": "Printed Playthrough: %s",
|
||||||
"made.spoiler": "Printed Spoiler: %s",
|
"made.spoiler": "Printed Spoiler: %s",
|
||||||
|
"used.enemizer": "Enemized: %s",
|
||||||
"done": "Done. Enjoy.",
|
"done": "Done. Enjoy.",
|
||||||
"total.time": "Total Time: %s",
|
"total.time": "Total Time: %s",
|
||||||
"finished.run": "Finished run",
|
"finished.run": "Finished run",
|
||||||
|
|||||||
@@ -154,7 +154,7 @@
|
|||||||
"randomizer.gameoptions.sprite.unchanged": "(unchanged)",
|
"randomizer.gameoptions.sprite.unchanged": "(unchanged)",
|
||||||
|
|
||||||
|
|
||||||
"randomizer.generation.spoiler": "Create Spoiler Log",
|
"randomizer.generation.createspoiler": "Create Spoiler Log",
|
||||||
"randomizer.generation.createrom": "Create Patched ROM",
|
"randomizer.generation.createrom": "Create Patched ROM",
|
||||||
"randomizer.generation.calcplaythrough": "Calculate Playthrough",
|
"randomizer.generation.calcplaythrough": "Calculate Playthrough",
|
||||||
"randomizer.generation.usestartinventory": "Use Starting Inventory",
|
"randomizer.generation.usestartinventory": "Use Starting Inventory",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"checkboxes": {
|
"checkboxes": {
|
||||||
"spoiler": { "type": "checkbox" },
|
"createspoiler": { "type": "checkbox" },
|
||||||
"createrom": { "type": "checkbox" },
|
"createrom": { "type": "checkbox" },
|
||||||
"calcplaythrough": { "type": "checkbox" },
|
"calcplaythrough": { "type": "checkbox" },
|
||||||
"usestartinventory": { "type": "checkbox" },
|
"usestartinventory": { "type": "checkbox" },
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def prepare_env():
|
|||||||
|
|
||||||
# get app version
|
# get app version
|
||||||
APP_VERSION = ""
|
APP_VERSION = ""
|
||||||
APP_VERSION_FILE = "./resources/app/meta/manifests/app_version.txt"
|
APP_VERSION_FILE = os.path.join(".","resources","app","meta","manifests","app_version.txt")
|
||||||
if os.path.isfile(APP_VERSION_FILE):
|
if os.path.isfile(APP_VERSION_FILE):
|
||||||
with open(APP_VERSION_FILE,"r") as f:
|
with open(APP_VERSION_FILE,"r") as f:
|
||||||
APP_VERSION = f.readlines()[0].strip()
|
APP_VERSION = f.readlines()[0].strip()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from shutil import unpack_archive
|
|||||||
|
|
||||||
# only do stuff if we don't have a UPX folder
|
# only do stuff if we don't have a UPX folder
|
||||||
|
|
||||||
if not os.path.isdir("./upx"):
|
if not os.path.isdir(os.path.join(".","upx")):
|
||||||
# get env vars
|
# get env vars
|
||||||
env = common.prepare_env()
|
env = common.prepare_env()
|
||||||
# set up download url
|
# set up download url
|
||||||
@@ -25,7 +25,7 @@ if not os.path.isdir("./upx"):
|
|||||||
|
|
||||||
print("Getting UPX: " + UPX_FILE)
|
print("Getting UPX: " + UPX_FILE)
|
||||||
|
|
||||||
with open("./" + UPX_FILE,"wb") as upx:
|
with open(os.path.join(".",UPX_FILE),"wb") as upx:
|
||||||
UPX_REQ = urllib.request.Request(
|
UPX_REQ = urllib.request.Request(
|
||||||
UPX_URL,
|
UPX_URL,
|
||||||
data=None
|
data=None
|
||||||
@@ -34,9 +34,9 @@ if not os.path.isdir("./upx"):
|
|||||||
UPX_DATA = UPX_REQ.read()
|
UPX_DATA = UPX_REQ.read()
|
||||||
upx.write(UPX_DATA)
|
upx.write(UPX_DATA)
|
||||||
|
|
||||||
unpack_archive(UPX_FILE,"./")
|
unpack_archive(UPX_FILE,os.path.join("."))
|
||||||
|
|
||||||
os.rename("./" + UPX_SLUG,"./upx")
|
os.rename(os.path.join(".",UPX_SLUG),os.path.join(".","upx"))
|
||||||
os.remove("./" + UPX_FILE)
|
os.remove(os.path.join(".",UPX_FILE))
|
||||||
|
|
||||||
print("UPX should " + ("not " if not os.path.isdir("./upx") else "") + "be available.")
|
print("UPX should " + ("not " if not os.path.isdir(os.path.join(".","upx")) else "") + "be available.")
|
||||||
|
|||||||
@@ -1,19 +1,28 @@
|
|||||||
import subprocess # do stuff at the shell level
|
import subprocess # do stuff at the shell level
|
||||||
|
import os
|
||||||
|
|
||||||
def git_clean():
|
def git_clean(clean_ignored=True, clean_user=False):
|
||||||
excludes = [
|
excludes = [
|
||||||
".vscode", # vscode IDE files
|
".vscode", # vscode IDE files
|
||||||
".idea", # idea IDE files
|
".idea", # idea IDE files
|
||||||
"*.json", # keep JSON files for that one time I just nuked all that I was working on, oops
|
"*.json", # keep JSON files for that one time I just nuked all that I was working on, oops
|
||||||
"*app*version.*" # keep appversion files
|
"*app*version.*", # keep appversion files
|
||||||
|
"EnemizerCLI" # keep EnemizerCLI files
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if not clean_user:
|
||||||
|
excludes.append(os.path.join("resources","user*")) # keep user resources
|
||||||
|
|
||||||
excludes = ['--exclude={0}'.format(exclude) for exclude in excludes]
|
excludes = ['--exclude={0}'.format(exclude) for exclude in excludes]
|
||||||
|
|
||||||
|
# d: directories, f: files, x: ignored files
|
||||||
|
switches = "df" + ("x" if clean_ignored else "")
|
||||||
|
|
||||||
# clean the git slate
|
# clean the git slate
|
||||||
subprocess.check_call([
|
subprocess.check_call([
|
||||||
"git", # run a git command
|
"git", # run a git command
|
||||||
"clean", # clean command
|
"clean", # clean command
|
||||||
"-dfx", # d: directories, f: files, x: ignored files
|
"-" + switches,
|
||||||
*excludes])
|
*excludes])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from git_clean import git_clean
|
||||||
|
|
||||||
|
git_clean(clean_user=True)
|
||||||
@@ -32,12 +32,13 @@ class SpriteSelector(object):
|
|||||||
webbrowser.open("http://alttpr.com/sprite_preview")
|
webbrowser.open("http://alttpr.com/sprite_preview")
|
||||||
|
|
||||||
def open_unofficial_sprite_dir(_evt):
|
def open_unofficial_sprite_dir(_evt):
|
||||||
|
if not os.path.isdir(self.unofficial_sprite_dir):
|
||||||
|
os.makedirs(self.unofficial_sprite_dir)
|
||||||
open_file(self.unofficial_sprite_dir)
|
open_file(self.unofficial_sprite_dir)
|
||||||
|
|
||||||
# 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/?mode=zelda3/link")
|
webbrowser.open("https://artheau.github.io/SpriteSomething/resources/app/snes/zelda3/link/sprites.html")
|
||||||
# webbrowser.open("https://artheau.github.io/SpriteSomething/resources/app/snes/zelda3/link/sprites.html")
|
|
||||||
|
|
||||||
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")
|
||||||
@@ -57,8 +58,8 @@ class SpriteSelector(object):
|
|||||||
spritesomething_title_link.pack(side=LEFT)
|
spritesomething_title_link.pack(side=LEFT)
|
||||||
spritesomething_title_link.bind("<Button-1>", open_spritesomething_listing)
|
spritesomething_title_link.bind("<Button-1>", open_spritesomething_listing)
|
||||||
|
|
||||||
self.icon_section(official_frametitle, self.official_sprite_dir+'/*', 'Official sprites not found. Click "Update official sprites" to download them.')
|
self.icon_section(official_frametitle, os.path.join(self.official_sprite_dir,"*"), 'Official sprites not found. Click "Update official sprites" to download them.')
|
||||||
self.icon_section(unofficial_frametitle, self.unofficial_sprite_dir+'/*', 'Put sprites in the unofficial sprites folder (see open link above) to have them appear here.')
|
self.icon_section(unofficial_frametitle, os.path.join(self.unofficial_sprite_dir,"*"), 'Put sprites in the unofficial sprites folder (see open link above) to have them appear here.')
|
||||||
|
|
||||||
frame = Frame(self.window)
|
frame = Frame(self.window)
|
||||||
frame.pack(side=BOTTOM, fill=X, pady=5)
|
frame.pack(side=BOTTOM, fill=X, pady=5)
|
||||||
@@ -150,10 +151,10 @@ class SpriteSelector(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
task.update_status("Determining needed sprites")
|
task.update_status("Determining needed sprites")
|
||||||
current_sprites = [os.path.basename(file) for file in glob(self.official_sprite_dir+'/*')]
|
current_sprites = [os.path.basename(file) for file in glob(os.path.join(self.official_sprite_dir,"*"))]
|
||||||
official_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr]
|
official_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr]
|
||||||
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in official_sprites if filename not in current_sprites]
|
needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in official_sprites if filename not in current_sprites]
|
||||||
bundled_sprites = [os.path.basename(file) for file in glob(self.local_official_sprite_dir+'/*')]
|
bundled_sprites = [os.path.basename(file) for file in glob(os.path.join(self.unofficial_sprite_dir,"*"))]
|
||||||
# todo: eventually use the above list to avoid downloading any sprites that we already have cached in the bundle.
|
# todo: eventually use the above list to avoid downloading any sprites that we already have cached in the bundle.
|
||||||
|
|
||||||
official_filenames = [filename for (_, filename) in official_sprites]
|
official_filenames = [filename for (_, filename) in official_sprites]
|
||||||
@@ -230,23 +231,23 @@ class SpriteSelector(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def official_sprite_dir(self):
|
def official_sprite_dir(self):
|
||||||
if is_bundled():
|
# if is_bundled():
|
||||||
return output_path("sprites/official")
|
# return output_path(os.path.join("sprites","official"))
|
||||||
return self.local_official_sprite_dir
|
return self.local_official_sprite_dir
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_official_sprite_dir(self):
|
def local_official_sprite_dir(self):
|
||||||
return local_path("data/sprites/official")
|
return local_path(os.path.join("data","sprites","official"))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unofficial_sprite_dir(self):
|
def unofficial_sprite_dir(self):
|
||||||
if is_bundled():
|
# if is_bundled():
|
||||||
return output_path("sprites/unofficial")
|
# return output_path(os.path.join("sprites","unofficial"))
|
||||||
return self.local_unofficial_sprite_dir
|
return self.local_unofficial_sprite_dir
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_unofficial_sprite_dir(self):
|
def local_unofficial_sprite_dir(self):
|
||||||
return local_path("data/sprites/unofficial")
|
return local_path(os.path.join("data","sprites","unofficial"))
|
||||||
|
|
||||||
|
|
||||||
def get_image_for_sprite(sprite):
|
def get_image_for_sprite(sprite):
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ SETTINGSTOPROCESS = {
|
|||||||
"uwpalettes": "uw_palettes"
|
"uwpalettes": "uw_palettes"
|
||||||
},
|
},
|
||||||
"generation": {
|
"generation": {
|
||||||
"spoiler": "create_spoiler",
|
"createspoiler": "create_spoiler",
|
||||||
"createrom": "create_rom",
|
"createrom": "create_rom",
|
||||||
"calcplaythrough": "calc_playthrough",
|
"calcplaythrough": "calc_playthrough",
|
||||||
"usestartinventory": "usestartinventory",
|
"usestartinventory": "usestartinventory",
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import platform, sys, os, subprocess
|
||||||
|
import pkg_resources
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def diagpad(str):
|
||||||
|
return str.ljust(len("ALttP Door Randomizer Version") + 5,'.')
|
||||||
|
|
||||||
|
def output(APP_VERSION):
|
||||||
|
lines = [
|
||||||
|
"ALttP Door Randomizer Diagnostics",
|
||||||
|
"=================================",
|
||||||
|
diagpad("UTC Time") + str(datetime.utcnow())[:19],
|
||||||
|
diagpad("ALttP Door Randomizer Version") + APP_VERSION,
|
||||||
|
diagpad("Python Version") + platform.python_version()
|
||||||
|
]
|
||||||
|
lines.append(diagpad("OS Version") + "%s %s" % (platform.system(), platform.release()))
|
||||||
|
if hasattr(sys, "executable"):
|
||||||
|
lines.append(diagpad("Executable") + sys.executable)
|
||||||
|
lines.append(diagpad("Build Date") + platform.python_build()[1])
|
||||||
|
lines.append(diagpad("Compiler") + platform.python_compiler())
|
||||||
|
if hasattr(sys, "api_version"):
|
||||||
|
lines.append(diagpad("Python API") + str(sys.api_version))
|
||||||
|
if hasattr(os, "sep"):
|
||||||
|
lines.append(diagpad("Filepath Separator") + os.sep)
|
||||||
|
if hasattr(os, "pathsep"):
|
||||||
|
lines.append(diagpad("Path Env Separator") + os.pathsep)
|
||||||
|
lines.append("")
|
||||||
|
lines.append("Packages")
|
||||||
|
lines.append("--------")
|
||||||
|
'''
|
||||||
|
#this breaks when run from the .exe
|
||||||
|
reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
|
||||||
|
installed_packages = [r.decode() for r in reqs.split()]
|
||||||
|
for pkg in installed_packages:
|
||||||
|
pkg = pkg.split("==")
|
||||||
|
lines.append(diagpad(pkg[0]) + pkg[1])
|
||||||
|
'''
|
||||||
|
installed_packages = [str(d) for d in pkg_resources.working_set] #this doesn't work from the .exe either, but it doesn't crash the program
|
||||||
|
installed_packages.sort()
|
||||||
|
for pkg in installed_packages:
|
||||||
|
pkg = pkg.split(' ')
|
||||||
|
lines.append(diagpad(pkg[0]) + pkg[1])
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise AssertionError(f"Called main() on utility library {__file__}")
|
||||||
@@ -104,7 +104,7 @@ def adjust_page(top, parent, settings):
|
|||||||
arg = options[option]
|
arg = options[option]
|
||||||
setattr(guiargs, arg, self.widgets[option].storageVar.get())
|
setattr(guiargs, arg, self.widgets[option].storageVar.get())
|
||||||
guiargs.rom = self.romVar2.get()
|
guiargs.rom = self.romVar2.get()
|
||||||
guiargs.baserom = top.pages["randomizer"].pages["generation"].romVar.get()
|
guiargs.baserom = top.pages["randomizer"].pages["generation"].widgets["rom"].storageVar.get()
|
||||||
guiargs.sprite = self.sprite
|
guiargs.sprite = self.sprite
|
||||||
try:
|
try:
|
||||||
adjust(args=guiargs)
|
adjust(args=guiargs)
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ def bottom_frame(self, parent, args=None):
|
|||||||
made = {}
|
made = {}
|
||||||
for k in [ "rom", "playthrough", "spoiler" ]:
|
for k in [ "rom", "playthrough", "spoiler" ]:
|
||||||
made[k] = parent.fish.translate("cli","cli","made." + k)
|
made[k] = parent.fish.translate("cli","cli","made." + k)
|
||||||
|
made["enemizer"] = parent.fish.translate("cli","cli","used.enemizer")
|
||||||
for k in made:
|
for k in made:
|
||||||
v = made[k]
|
v = made[k]
|
||||||
pattern = "([\w]+)(:)([\s]+)(.*)"
|
pattern = "([\w]+)(:)([\s]+)(.*)"
|
||||||
@@ -123,6 +124,7 @@ def bottom_frame(self, parent, args=None):
|
|||||||
successMsg += (made["rom"] % (YES if (guiargs.create_rom) else NO)) + "\n"
|
successMsg += (made["rom"] % (YES if (guiargs.create_rom) else NO)) + "\n"
|
||||||
successMsg += (made["playthrough"] % (YES if (guiargs.calc_playthrough) else NO)) + "\n"
|
successMsg += (made["playthrough"] % (YES if (guiargs.calc_playthrough) else NO)) + "\n"
|
||||||
successMsg += (made["spoiler"] % (YES if (not guiargs.jsonout and guiargs.create_spoiler) else NO)) + "\n"
|
successMsg += (made["spoiler"] % (YES if (not guiargs.jsonout and guiargs.create_spoiler) else NO)) + "\n"
|
||||||
|
successMsg += (made["enemizer"] % (YES if needEnemizer else NO)) + "\n"
|
||||||
# FIXME: English
|
# FIXME: English
|
||||||
successMsg += ("Seed%s: %s" % ('s' if len(seeds) > 1 else "", ','.join(str(x) for x in seeds)))
|
successMsg += ("Seed%s: %s" % ('s' if len(seeds) > 1 else "", ','.join(str(x) for x in seeds)))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user