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('--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('--triforcehud', default='hide_goal', const='hide_goal', nargs='?',
|
||||
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,
|
||||
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')
|
||||
rom.write_to_file(path)
|
||||
|
||||
|
@ -210,6 +211,7 @@ def adjustGUI():
|
|||
guiargs.music = bool(rom_vars.MusicVar.get())
|
||||
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
||||
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
||||
guiargs.allowcollect = bool(rom_vars.AllowCollectVar.get())
|
||||
guiargs.rom = romVar2.get()
|
||||
guiargs.baserom = romVar.get()
|
||||
guiargs.sprite = rom_vars.sprite
|
||||
|
@ -246,6 +248,7 @@ def adjustGUI():
|
|||
guiargs.music = bool(rom_vars.MusicVar.get())
|
||||
guiargs.reduceflashing = bool(rom_vars.disableFlashingVar.get())
|
||||
guiargs.deathlink = bool(rom_vars.DeathLinkVar.get())
|
||||
guiargs.allowcollect = bool(rom_vars.AllowCollectVar.get())
|
||||
guiargs.baserom = romVar.get()
|
||||
if isinstance(rom_vars.sprite, Sprite):
|
||||
guiargs.sprite = rom_vars.sprite.name
|
||||
|
@ -508,6 +511,7 @@ def get_rom_options_frame(parent=None):
|
|||
adjuster_settings.music = True
|
||||
adjuster_settings.reduceflashing = True
|
||||
adjuster_settings.deathlink = False
|
||||
adjuster_settings.allowcollect = False
|
||||
adjuster_settings.sprite = None
|
||||
adjuster_settings.quickswap = True
|
||||
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.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.grid(row=0, column=1)
|
||||
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)
|
||||
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.pack(side=TOP, expand=True, fill=X)
|
||||
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.death_state = DeathState.alive # for death link flop behaviour
|
||||
self.killing_player_task = None
|
||||
self.allow_collect = False
|
||||
|
||||
self.awaiting_rom = False
|
||||
self.rom = None
|
||||
|
@ -872,7 +873,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
location = Shops.SHOP_ID_START + cnt
|
||||
if int(b) and location not in ctx.locations_checked:
|
||||
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:
|
||||
if not int(b):
|
||||
shop_data[cnt] += 1
|
||||
|
@ -900,9 +901,9 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
uw_unchecked[location_id] = (roomid, mask)
|
||||
uw_begin = min(uw_begin, roomid)
|
||||
uw_end = max(uw_end, roomid + 1)
|
||||
if 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 not in boss_locations:
|
||||
if ctx.allow_collect and location_id not in boss_locations 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:
|
||||
uw_begin = min(uw_begin, roomid)
|
||||
uw_end = max(uw_end, roomid + 1)
|
||||
uw_checked[location_id] = (roomid, mask)
|
||||
|
@ -933,7 +934,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
ow_unchecked[location_id] = screenid
|
||||
ow_begin = min(ow_begin, screenid)
|
||||
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:
|
||||
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():
|
||||
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
||||
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:
|
||||
npc_value |= mask
|
||||
npc_value_changed = True
|
||||
|
@ -974,7 +975,7 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
assert (0x3c6 <= offset <= 0x3c9)
|
||||
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
||||
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:
|
||||
misc_data_changed = True
|
||||
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
|
||||
SM_DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
if death_link:
|
||||
ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||
ctx.death_link_allow_survive = bool(death_link[0] & 0b10)
|
||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
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",
|
||||
"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}
|
||||
if hasattr(lastSettings, "sprite_pool"):
|
||||
sprite_pool = {}
|
||||
|
|
2
Utils.py
2
Utils.py
|
@ -25,7 +25,7 @@ class Version(typing.NamedTuple):
|
|||
build: int
|
||||
|
||||
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "0.3.2"
|
||||
version_tuple = tuplize_version(__version__)
|
||||
|
||||
from yaml import load, dump, SafeLoader
|
||||
|
|
|
@ -444,6 +444,11 @@ A Link to the Past:
|
|||
death_link:
|
||||
false: 50
|
||||
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:
|
||||
- name: crosskeys
|
||||
|
|
|
@ -299,6 +299,12 @@ class BeemizerTrapChance(BeemizerRange):
|
|||
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)] = {
|
||||
"crystals_needed_for_gt": CrystalsTower,
|
||||
"crystals_needed_for_ganon": CrystalsGanon,
|
||||
|
@ -334,6 +340,6 @@ alttp_options: typing.Dict[str, type(Option)] = {
|
|||
"glitch_boots": DefaultOnToggle,
|
||||
"beemizer_total_chance": BeemizerTotalChance,
|
||||
"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,
|
||||
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]
|
||||
disable_music: bool = not music
|
||||
# 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':
|
||||
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,
|
||||
world.sprite_pool[player] if world else [])
|
||||
|
|
|
@ -295,7 +295,8 @@ class ALTTPWorld(World):
|
|||
palettes_options, world, player, True,
|
||||
reduceflashing=world.reduceflashing[player] or world.is_race,
|
||||
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"_{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]]
|
||||
|
||||
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:
|
||||
return ALttPItem(name, self.player, **as_dict_item_table[name])
|
||||
|
|
Loading…
Reference in New Issue