LttP: Add Allow collect option, default Off. (#414)
* LttP: Add Allow collect option, default Off. * Add allow_collect to the sample yaml.
This commit is contained in:
parent
f7c601b863
commit
944571ea89
|
@ -53,6 +53,7 @@ def main():
|
||||||
''')
|
''')
|
||||||
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
|
parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
|
||||||
parser.add_argument('--deathlink', help='Enable DeathLink system.', action='store_true')
|
parser.add_argument('--deathlink', help='Enable DeathLink system.', action='store_true')
|
||||||
|
parser.add_argument('--allowcollect', help='Allow collection of other player items', action='store_true')
|
||||||
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
|
parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
|
||||||
parser.add_argument('--triforcehud', default='hide_goal', const='hide_goal', nargs='?',
|
parser.add_argument('--triforcehud', default='hide_goal', const='hide_goal', nargs='?',
|
||||||
choices=['normal', 'hide_goal', 'hide_required', 'hide_both'],
|
choices=['normal', 'hide_goal', 'hide_required', 'hide_both'],
|
||||||
|
@ -155,7 +156,7 @@ def adjust(args):
|
||||||
|
|
||||||
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.menuspeed, args.music,
|
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.menuspeed, args.music,
|
||||||
args.sprite, palettes_options, reduceflashing=args.reduceflashing or racerom, world=world,
|
args.sprite, palettes_options, reduceflashing=args.reduceflashing or racerom, world=world,
|
||||||
deathlink=args.deathlink)
|
deathlink=args.deathlink, allowcollect=args.allowcollect)
|
||||||
path = output_path(f'{os.path.basename(args.rom)[:-4]}_adjusted.sfc')
|
path = output_path(f'{os.path.basename(args.rom)[:-4]}_adjusted.sfc')
|
||||||
rom.write_to_file(path)
|
rom.write_to_file(path)
|
||||||
|
|
||||||
|
@ -210,6 +211,7 @@ def adjustGUI():
|
||||||
guiargs.music = bool(rom_vars.MusicVar.get())
|
guiargs.music = bool(rom_vars.MusicVar.get())
|
||||||
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
||||||
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
||||||
|
guiargs.allowcollect = bool(rom_vars.AllowCollectVar.get())
|
||||||
guiargs.rom = romVar2.get()
|
guiargs.rom = romVar2.get()
|
||||||
guiargs.baserom = romVar.get()
|
guiargs.baserom = romVar.get()
|
||||||
guiargs.sprite = rom_vars.sprite
|
guiargs.sprite = rom_vars.sprite
|
||||||
|
@ -246,6 +248,7 @@ def adjustGUI():
|
||||||
guiargs.music = bool(rom_vars.MusicVar.get())
|
guiargs.music = bool(rom_vars.MusicVar.get())
|
||||||
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
||||||
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
||||||
|
guiargs.allowcollect = bool(rom_vars.AllowCollectVar.get())
|
||||||
guiargs.baserom = romVar.get()
|
guiargs.baserom = romVar.get()
|
||||||
if isinstance(rom_vars.sprite, Sprite):
|
if isinstance(rom_vars.sprite, Sprite):
|
||||||
guiargs.sprite = rom_vars.sprite.name
|
guiargs.sprite = rom_vars.sprite.name
|
||||||
|
@ -508,6 +511,7 @@ def get_rom_options_frame(parent=None):
|
||||||
adjuster_settings.music = True
|
adjuster_settings.music = True
|
||||||
adjuster_settings.reduceflashing = True
|
adjuster_settings.reduceflashing = True
|
||||||
adjuster_settings.deathlink = False
|
adjuster_settings.deathlink = False
|
||||||
|
adjuster_settings.allowcollect = False
|
||||||
adjuster_settings.sprite = None
|
adjuster_settings.sprite = None
|
||||||
adjuster_settings.quickswap = True
|
adjuster_settings.quickswap = True
|
||||||
adjuster_settings.menuspeed = 'normal'
|
adjuster_settings.menuspeed = 'normal'
|
||||||
|
@ -542,6 +546,10 @@ def get_rom_options_frame(parent=None):
|
||||||
DeathLinkCheckbutton = Checkbutton(romOptionsFrame, text="DeathLink (Team Deaths)", variable=vars.DeathLinkVar)
|
DeathLinkCheckbutton = Checkbutton(romOptionsFrame, text="DeathLink (Team Deaths)", variable=vars.DeathLinkVar)
|
||||||
DeathLinkCheckbutton.grid(row=7, column=0, sticky=W)
|
DeathLinkCheckbutton.grid(row=7, column=0, sticky=W)
|
||||||
|
|
||||||
|
vars.AllowCollectVar = IntVar(value=adjuster_settings.allowcollect)
|
||||||
|
AllowCollectCheckbutton = Checkbutton(romOptionsFrame, text="Allow Collect", variable=vars.AllowCollectVar)
|
||||||
|
AllowCollectCheckbutton.grid(row=8, column=0, sticky=W)
|
||||||
|
|
||||||
spriteDialogFrame = Frame(romOptionsFrame)
|
spriteDialogFrame = Frame(romOptionsFrame)
|
||||||
spriteDialogFrame.grid(row=0, column=1)
|
spriteDialogFrame.grid(row=0, column=1)
|
||||||
baseSpriteLabel = Label(spriteDialogFrame, text='Sprite:')
|
baseSpriteLabel = Label(spriteDialogFrame, text='Sprite:')
|
||||||
|
@ -703,7 +711,7 @@ def get_rom_options_frame(parent=None):
|
||||||
|
|
||||||
vars.auto_apply = StringVar(value=adjuster_settings.auto_apply)
|
vars.auto_apply = StringVar(value=adjuster_settings.auto_apply)
|
||||||
autoApplyFrame = Frame(romOptionsFrame)
|
autoApplyFrame = Frame(romOptionsFrame)
|
||||||
autoApplyFrame.grid(row=8, column=0, columnspan=2, sticky=W)
|
autoApplyFrame.grid(row=9, column=0, columnspan=2, sticky=W)
|
||||||
filler = Label(autoApplyFrame, text="Automatically apply last used settings on opening .apbp files")
|
filler = Label(autoApplyFrame, text="Automatically apply last used settings on opening .apbp files")
|
||||||
filler.pack(side=TOP, expand=True, fill=X)
|
filler.pack(side=TOP, expand=True, fill=X)
|
||||||
askRadio = Radiobutton(autoApplyFrame, text='Ask', variable=vars.auto_apply, value='ask')
|
askRadio = Radiobutton(autoApplyFrame, text='Ask', variable=vars.auto_apply, value='ask')
|
||||||
|
|
18
SNIClient.py
18
SNIClient.py
|
@ -124,6 +124,7 @@ class Context(CommonContext):
|
||||||
self.snes_connector_lock = threading.Lock()
|
self.snes_connector_lock = threading.Lock()
|
||||||
self.death_state = DeathState.alive # for death link flop behaviour
|
self.death_state = DeathState.alive # for death link flop behaviour
|
||||||
self.killing_player_task = None
|
self.killing_player_task = None
|
||||||
|
self.allow_collect = False
|
||||||
|
|
||||||
self.awaiting_rom = False
|
self.awaiting_rom = False
|
||||||
self.rom = None
|
self.rom = None
|
||||||
|
@ -872,7 +873,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
location = Shops.SHOP_ID_START + cnt
|
location = Shops.SHOP_ID_START + cnt
|
||||||
if int(b) and location not in ctx.locations_checked:
|
if int(b) and location not in ctx.locations_checked:
|
||||||
new_check(location)
|
new_check(location)
|
||||||
if location in ctx.checked_locations and location not in ctx.locations_checked \
|
if ctx.allow_collect and location in ctx.checked_locations and location not in ctx.locations_checked \
|
||||||
and location in ctx.locations_info and ctx.locations_info[location].player != ctx.slot:
|
and location in ctx.locations_info and ctx.locations_info[location].player != ctx.slot:
|
||||||
if not int(b):
|
if not int(b):
|
||||||
shop_data[cnt] += 1
|
shop_data[cnt] += 1
|
||||||
|
@ -900,9 +901,9 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
uw_unchecked[location_id] = (roomid, mask)
|
uw_unchecked[location_id] = (roomid, mask)
|
||||||
uw_begin = min(uw_begin, roomid)
|
uw_begin = min(uw_begin, roomid)
|
||||||
uw_end = max(uw_end, roomid + 1)
|
uw_end = max(uw_end, roomid + 1)
|
||||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked and \
|
if ctx.allow_collect and location_id not in boss_locations and location_id in ctx.checked_locations \
|
||||||
location_id in ctx.locations_info and ctx.locations_info[location_id].player != ctx.slot and \
|
and location_id not in ctx.locations_checked and location_id in ctx.locations_info \
|
||||||
location_id not in boss_locations:
|
and ctx.locations_info[location_id].player != ctx.slot:
|
||||||
uw_begin = min(uw_begin, roomid)
|
uw_begin = min(uw_begin, roomid)
|
||||||
uw_end = max(uw_end, roomid + 1)
|
uw_end = max(uw_end, roomid + 1)
|
||||||
uw_checked[location_id] = (roomid, mask)
|
uw_checked[location_id] = (roomid, mask)
|
||||||
|
@ -933,7 +934,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
ow_unchecked[location_id] = screenid
|
ow_unchecked[location_id] = screenid
|
||||||
ow_begin = min(ow_begin, screenid)
|
ow_begin = min(ow_begin, screenid)
|
||||||
ow_end = max(ow_end, screenid + 1)
|
ow_end = max(ow_end, screenid + 1)
|
||||||
if location_id in ctx.checked_locations and location_id in ctx.locations_info \
|
if ctx.allow_collect and location_id in ctx.checked_locations and location_id in ctx.locations_info \
|
||||||
and ctx.locations_info[location_id].player != ctx.slot:
|
and ctx.locations_info[location_id].player != ctx.slot:
|
||||||
ow_checked[location_id] = screenid
|
ow_checked[location_id] = screenid
|
||||||
|
|
||||||
|
@ -957,7 +958,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
for location_id, mask in location_table_npc_id.items():
|
for location_id, mask in location_table_npc_id.items():
|
||||||
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
||||||
new_check(location_id)
|
new_check(location_id)
|
||||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
if ctx.allow_collect and location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
||||||
and location_id in ctx.locations_info and ctx.locations_info[location_id].player != ctx.slot:
|
and location_id in ctx.locations_info and ctx.locations_info[location_id].player != ctx.slot:
|
||||||
npc_value |= mask
|
npc_value |= mask
|
||||||
npc_value_changed = True
|
npc_value_changed = True
|
||||||
|
@ -974,7 +975,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
assert (0x3c6 <= offset <= 0x3c9)
|
assert (0x3c6 <= offset <= 0x3c9)
|
||||||
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
||||||
new_check(location_id)
|
new_check(location_id)
|
||||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
if ctx.allow_collect and location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
||||||
and location_id in ctx.locations_info and ctx.locations_info[location_id].player != ctx.slot:
|
and location_id in ctx.locations_info and ctx.locations_info[location_id].player != ctx.slot:
|
||||||
misc_data_changed = True
|
misc_data_changed = True
|
||||||
misc_data[offset - 0x3c6] |= mask
|
misc_data[offset - 0x3c6] |= mask
|
||||||
|
@ -1030,6 +1031,7 @@ async def game_watcher(ctx: Context):
|
||||||
death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR if ctx.game == GAME_ALTTP else
|
death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR if ctx.game == GAME_ALTTP else
|
||||||
SM_DEATH_LINK_ACTIVE_ADDR, 1)
|
SM_DEATH_LINK_ACTIVE_ADDR, 1)
|
||||||
if death_link:
|
if death_link:
|
||||||
|
ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||||
ctx.death_link_allow_survive = bool(death_link[0] & 0b10)
|
ctx.death_link_allow_survive = bool(death_link[0] & 0b10)
|
||||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||||
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
||||||
|
@ -1327,7 +1329,7 @@ def get_alttp_settings(romfile: str):
|
||||||
|
|
||||||
whitelist = {"music", "menuspeed", "heartbeep", "heartcolor", "ow_palettes", "quickswap",
|
whitelist = {"music", "menuspeed", "heartbeep", "heartcolor", "ow_palettes", "quickswap",
|
||||||
"uw_palettes", "sprite", "sword_palettes", "shield_palettes", "hud_palettes",
|
"uw_palettes", "sprite", "sword_palettes", "shield_palettes", "hud_palettes",
|
||||||
"reduceflashing", "deathlink"}
|
"reduceflashing", "deathlink", "allowcollect"}
|
||||||
printed_options = {name: value for name, value in vars(lastSettings).items() if name in whitelist}
|
printed_options = {name: value for name, value in vars(lastSettings).items() if name in whitelist}
|
||||||
if hasattr(lastSettings, "sprite_pool"):
|
if hasattr(lastSettings, "sprite_pool"):
|
||||||
sprite_pool = {}
|
sprite_pool = {}
|
||||||
|
|
2
Utils.py
2
Utils.py
|
@ -25,7 +25,7 @@ class Version(typing.NamedTuple):
|
||||||
build: int
|
build: int
|
||||||
|
|
||||||
|
|
||||||
__version__ = "0.3.1"
|
__version__ = "0.3.2"
|
||||||
version_tuple = tuplize_version(__version__)
|
version_tuple = tuplize_version(__version__)
|
||||||
|
|
||||||
from yaml import load, dump, SafeLoader
|
from yaml import load, dump, SafeLoader
|
||||||
|
|
|
@ -444,6 +444,11 @@ A Link to the Past:
|
||||||
death_link:
|
death_link:
|
||||||
false: 50
|
false: 50
|
||||||
true: 0
|
true: 0
|
||||||
|
|
||||||
|
allow_collect: # Allows for !collect / co-op to auto-open chests containing items for other players.
|
||||||
|
# Off by default, because it currently crashes on real hardware.
|
||||||
|
false: 50
|
||||||
|
true: 0
|
||||||
|
|
||||||
linked_options:
|
linked_options:
|
||||||
- name: crosskeys
|
- name: crosskeys
|
||||||
|
|
|
@ -299,6 +299,12 @@ class BeemizerTrapChance(BeemizerRange):
|
||||||
display_name = "Beemizer Trap Chance"
|
display_name = "Beemizer Trap Chance"
|
||||||
|
|
||||||
|
|
||||||
|
class AllowCollect(Toggle):
|
||||||
|
"""Allows for !collect / co-op to auto-open chests containing items for other players.
|
||||||
|
Off by default, because it currently crashes on real hardware."""
|
||||||
|
display_name = "Allow Collection of checks for other players"
|
||||||
|
|
||||||
|
|
||||||
alttp_options: typing.Dict[str, type(Option)] = {
|
alttp_options: typing.Dict[str, type(Option)] = {
|
||||||
"crystals_needed_for_gt": CrystalsTower,
|
"crystals_needed_for_gt": CrystalsTower,
|
||||||
"crystals_needed_for_ganon": CrystalsGanon,
|
"crystals_needed_for_ganon": CrystalsGanon,
|
||||||
|
@ -334,6 +340,6 @@ alttp_options: typing.Dict[str, type(Option)] = {
|
||||||
"glitch_boots": DefaultOnToggle,
|
"glitch_boots": DefaultOnToggle,
|
||||||
"beemizer_total_chance": BeemizerTotalChance,
|
"beemizer_total_chance": BeemizerTotalChance,
|
||||||
"beemizer_trap_chance": BeemizerTrapChance,
|
"beemizer_trap_chance": BeemizerTrapChance,
|
||||||
"death_link": DeathLink
|
"death_link": DeathLink,
|
||||||
|
"allow_collect": AllowCollect
|
||||||
}
|
}
|
||||||
|
|
|
@ -1765,7 +1765,7 @@ def hud_format_text(text):
|
||||||
|
|
||||||
def apply_rom_settings(rom, beep, color, quickswap, menuspeed, music: bool, sprite: str, palettes_options,
|
def apply_rom_settings(rom, beep, color, quickswap, menuspeed, music: bool, sprite: str, palettes_options,
|
||||||
world=None, player=1, allow_random_on_event=False, reduceflashing=False,
|
world=None, player=1, allow_random_on_event=False, reduceflashing=False,
|
||||||
triforcehud: str = None, deathlink: bool = False):
|
triforcehud: str = None, deathlink: bool = False, allowcollect: bool = False):
|
||||||
local_random = random if not world else world.slot_seeds[player]
|
local_random = random if not world else world.slot_seeds[player]
|
||||||
disable_music: bool = not music
|
disable_music: bool = not music
|
||||||
# enable instant item menu
|
# enable instant item menu
|
||||||
|
@ -1899,7 +1899,9 @@ def apply_rom_settings(rom, beep, color, quickswap, menuspeed, music: bool, spri
|
||||||
elif palettes_options['dungeon'] == 'random':
|
elif palettes_options['dungeon'] == 'random':
|
||||||
randomize_uw_palettes(rom, local_random)
|
randomize_uw_palettes(rom, local_random)
|
||||||
|
|
||||||
rom.write_byte(0x18008D, int(deathlink))
|
rom.write_byte(0x18008D, (0b00000001 if deathlink else 0) |
|
||||||
|
# 0b00000010 is already used for death_link_allow_survive in super metroid.
|
||||||
|
(0b00000100 if allowcollect else 0))
|
||||||
|
|
||||||
apply_random_sprite_on_event(rom, sprite, local_random, allow_random_on_event,
|
apply_random_sprite_on_event(rom, sprite, local_random, allow_random_on_event,
|
||||||
world.sprite_pool[player] if world else [])
|
world.sprite_pool[player] if world else [])
|
||||||
|
|
|
@ -295,7 +295,8 @@ class ALTTPWorld(World):
|
||||||
palettes_options, world, player, True,
|
palettes_options, world, player, True,
|
||||||
reduceflashing=world.reduceflashing[player] or world.is_race,
|
reduceflashing=world.reduceflashing[player] or world.is_race,
|
||||||
triforcehud=world.triforcehud[player].current_key,
|
triforcehud=world.triforcehud[player].current_key,
|
||||||
deathlink=world.death_link[player])
|
deathlink=world.death_link[player],
|
||||||
|
allowcollect=world.allow_collect[player])
|
||||||
|
|
||||||
outfilepname = f'_P{player}'
|
outfilepname = f'_P{player}'
|
||||||
outfilepname += f"_{world.get_file_safe_player_name(player).replace(' ', '_')}" \
|
outfilepname += f"_{world.get_file_safe_player_name(player).replace(' ', '_')}" \
|
||||||
|
@ -324,7 +325,7 @@ class ALTTPWorld(World):
|
||||||
multidata["connect_names"][new_name] = multidata["connect_names"][self.world.player_name[self.player]]
|
multidata["connect_names"][new_name] = multidata["connect_names"][self.world.player_name[self.player]]
|
||||||
|
|
||||||
def get_required_client_version(self) -> tuple:
|
def get_required_client_version(self) -> tuple:
|
||||||
return max((0, 3, 1), super(ALTTPWorld, self).get_required_client_version())
|
return max((0, 3, 2), super(ALTTPWorld, self).get_required_client_version())
|
||||||
|
|
||||||
def create_item(self, name: str) -> Item:
|
def create_item(self, name: str) -> Item:
|
||||||
return ALttPItem(name, self.player, **as_dict_item_table[name])
|
return ALttPItem(name, self.player, **as_dict_item_table[name])
|
||||||
|
|
Loading…
Reference in New Issue