Merge branch 'ArchipelagoMW:main' into tunc-combat-logic

This commit is contained in:
Scipio Wright
2024-07-15 09:42:21 -04:00
committed by GitHub
8 changed files with 64 additions and 49 deletions

View File

@@ -29,7 +29,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
def _cmd_patch(self):
"""Patch the game. Only use this command if /auto_patch fails."""
if isinstance(self.ctx, UndertaleContext):
os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True)
os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True)
self.ctx.patch_game()
self.output("Patched.")
@@ -43,7 +43,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
def _cmd_auto_patch(self, steaminstall: typing.Optional[str] = None):
"""Patch the game automatically."""
if isinstance(self.ctx, UndertaleContext):
os.makedirs(name=os.path.join(os.getcwd(), "Undertale"), exist_ok=True)
os.makedirs(name=Utils.user_path("Undertale"), exist_ok=True)
tempInstall = steaminstall
if not os.path.isfile(os.path.join(tempInstall, "data.win")):
tempInstall = None
@@ -62,7 +62,7 @@ class UndertaleCommandProcessor(ClientCommandProcessor):
for file_name in os.listdir(tempInstall):
if file_name != "steam_api.dll":
shutil.copy(os.path.join(tempInstall, file_name),
os.path.join(os.getcwd(), "Undertale", file_name))
Utils.user_path("Undertale", file_name))
self.ctx.patch_game()
self.output("Patching successful!")
@@ -111,12 +111,12 @@ class UndertaleContext(CommonContext):
self.save_game_folder = os.path.expandvars(r"%localappdata%/UNDERTALE")
def patch_game(self):
with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "rb") as f:
with open(Utils.user_path("Undertale", "data.win"), "rb") as f:
patchedFile = bsdiff4.patch(f.read(), undertale.data_path("patch.bsdiff"))
with open(os.path.join(os.getcwd(), "Undertale", "data.win"), "wb") as f:
with open(Utils.user_path("Undertale", "data.win"), "wb") as f:
f.write(patchedFile)
os.makedirs(name=os.path.join(os.getcwd(), "Undertale", "Custom Sprites"), exist_ok=True)
with open(os.path.expandvars(os.path.join(os.getcwd(), "Undertale", "Custom Sprites",
os.makedirs(name=Utils.user_path("Undertale", "Custom Sprites"), exist_ok=True)
with open(os.path.expandvars(Utils.user_path("Undertale", "Custom Sprites",
"Which Character.txt")), "w") as f:
f.writelines(["// Put the folder name of the sprites you want to play as, make sure it is the only "
"line other than this one.\n", "frisk"])

View File

@@ -325,10 +325,12 @@ def run_server_process(name: str, ponyconfig: dict, static_server_data: dict,
def run(self):
while 1:
next_room = rooms_to_run.get(block=True, timeout=None)
gc.collect(0)
task = asyncio.run_coroutine_threadsafe(start_room(next_room), loop)
self._tasks.append(task)
task.add_done_callback(self._done)
logging.info(f"Starting room {next_room} on {name}.")
del task # delete reference to task object
starter = Starter()
starter.daemon = True

View File

@@ -292,6 +292,9 @@ blacklisted_combos = {
# See above comment
"Time Rift - Deep Sea": ["Alpine Free Roam", "Nyakuza Free Roam", "Contractual Obligations",
"Murder on the Owl Express"],
# was causing test failures
"Time Rift - Balcony": ["Alpine Free Roam"],
}

View File

@@ -863,6 +863,8 @@ def set_rift_rules(world: "HatInTimeWorld", regions: Dict[str, Region]):
if world.is_dlc1():
for entrance in regions["Time Rift - Balcony"].entrances:
add_rule(entrance, lambda state: can_clear_required_act(state, world, "The Arctic Cruise - Finale"))
reg_act_connection(world, world.multiworld.get_entrance("The Arctic Cruise - Finale",
world.player).connected_region, entrance)
for entrance in regions["Time Rift - Deep Sea"].entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))
@@ -939,6 +941,7 @@ def set_default_rift_rules(world: "HatInTimeWorld"):
if world.is_dlc1():
for entrance in world.multiworld.get_region("Time Rift - Balcony", world.player).entrances:
add_rule(entrance, lambda state: can_clear_required_act(state, world, "The Arctic Cruise - Finale"))
reg_act_connection(world, "Rock the Boat", entrance.name)
for entrance in world.multiworld.get_region("Time Rift - Deep Sea", world.player).entrances:
add_rule(entrance, lambda state: has_relic_combo(state, world, "Cake"))

View File

@@ -558,6 +558,10 @@ def set_rules(world: "PokemonEmeraldWorld") -> None:
get_location("NPC_GIFT_GOT_BASEMENT_KEY_FROM_WATTSON"),
lambda state: state.has("EVENT_DEFEAT_NORMAN", world.player)
)
set_rule(
get_location("NPC_GIFT_RECEIVED_COIN_CASE"),
lambda state: state.has("EVENT_BUY_HARBOR_MAIL", world.player)
)
# Route 117
set_rule(
@@ -1638,10 +1642,6 @@ def set_rules(world: "PokemonEmeraldWorld") -> None:
get_location("NPC_GIFT_GOT_TM_THUNDERBOLT_FROM_WATTSON"),
lambda state: state.has("EVENT_DEFEAT_NORMAN", world.player) and state.has("EVENT_TURN_OFF_GENERATOR", world.player)
)
set_rule(
get_location("NPC_GIFT_RECEIVED_COIN_CASE"),
lambda state: state.has("EVENT_BUY_HARBOR_MAIL", world.player)
)
# Fallarbor Town
set_rule(

View File

@@ -1,4 +1,5 @@
from Options import Range, Toggle, DefaultOnToggle, Choice, DeathLink
from dataclasses import dataclass
from Options import Range, Toggle, DefaultOnToggle, Choice, DeathLink, PerGameCommonOptions
class MinimumResourcePackAmount(Range):
"""The minimum amount of resources available in a resource pack"""
@@ -47,6 +48,8 @@ class IslandFrequencyLocations(Choice):
option_progressive = 4
option_anywhere = 5
default = 2
def is_filling_frequencies_in_world(self):
return self.value <= self.option_random_on_island_random_order
class IslandGenerationDistance(Choice):
"""Sets how far away islands spawn from you when you input their coordinates into the Receiver."""
@@ -76,16 +79,16 @@ class PaddleboardMode(Toggle):
"""Sets later story islands to be in logic without an Engine or Steering Wheel. May require lots of paddling."""
display_name = "Paddleboard Mode"
raft_options = {
"minimum_resource_pack_amount": MinimumResourcePackAmount,
"maximum_resource_pack_amount": MaximumResourcePackAmount,
"duplicate_items": DuplicateItems,
"filler_item_types": FillerItemTypes,
"island_frequency_locations": IslandFrequencyLocations,
"island_generation_distance": IslandGenerationDistance,
"expensive_research": ExpensiveResearch,
"progressive_items": ProgressiveItems,
"big_island_early_crafting": BigIslandEarlyCrafting,
"paddleboard_mode": PaddleboardMode,
"death_link": DeathLink
}
@dataclass
class RaftOptions(PerGameCommonOptions):
minimum_resource_pack_amount: MinimumResourcePackAmount
maximum_resource_pack_amount: MaximumResourcePackAmount
duplicate_items: DuplicateItems
filler_item_types: FillerItemTypes
island_frequency_locations: IslandFrequencyLocations
island_generation_distance: IslandGenerationDistance
expensive_research: ExpensiveResearch
progressive_items: ProgressiveItems
big_island_early_crafting: BigIslandEarlyCrafting
paddleboard_mode: PaddleboardMode
death_link: DeathLink

View File

@@ -5,10 +5,10 @@ from ..AutoWorld import LogicMixin
class RaftLogic(LogicMixin):
def raft_paddleboard_mode_enabled(self, player):
return self.multiworld.paddleboard_mode[player].value
return bool(self.multiworld.worlds[player].options.paddleboard_mode)
def raft_big_islands_available(self, player):
return self.multiworld.big_island_early_crafting[player].value or self.raft_can_access_radio_tower(player)
return bool(self.multiworld.worlds[player].options.big_island_early_crafting) or self.raft_can_access_radio_tower(player)
def raft_can_smelt_items(self, player):
return self.has("Smelter", player)

View File

@@ -6,7 +6,7 @@ from .Items import (createResourcePackName, item_table, progressive_table, progr
from .Regions import create_regions, getConnectionName
from .Rules import set_rules
from .Options import raft_options
from .Options import RaftOptions
from BaseClasses import Region, Entrance, Location, MultiWorld, Item, ItemClassification, Tutorial
from ..AutoWorld import World, WebWorld
@@ -37,16 +37,17 @@ class RaftWorld(World):
lastItemId = max(filter(lambda val: val is not None, item_name_to_id.values()))
location_name_to_id = locations_lookup_name_to_id
option_definitions = raft_options
options_dataclass = RaftOptions
options: RaftOptions
required_client_version = (0, 3, 4)
def create_items(self):
minRPSpecified = self.multiworld.minimum_resource_pack_amount[self.player].value
maxRPSpecified = self.multiworld.maximum_resource_pack_amount[self.player].value
minRPSpecified = self.options.minimum_resource_pack_amount.value
maxRPSpecified = self.options.maximum_resource_pack_amount.value
minimumResourcePackAmount = min(minRPSpecified, maxRPSpecified)
maximumResourcePackAmount = max(minRPSpecified, maxRPSpecified)
isFillingFrequencies = self.multiworld.island_frequency_locations[self.player].value <= 3
isFillingFrequencies = self.options.island_frequency_locations.is_filling_frequencies_in_world()
# Generate item pool
pool = []
frequencyItems = []
@@ -64,20 +65,20 @@ class RaftWorld(World):
extraItemNamePool = []
extras = len(location_table) - len(item_table) - 1 # Victory takes up 1 unaccounted-for slot
if extras > 0:
if (self.multiworld.filler_item_types[self.player].value != 1): # Use resource packs
if (self.options.filler_item_types != self.options.filler_item_types.option_duplicates): # Use resource packs
for packItem in resourcePackItems:
for i in range(minimumResourcePackAmount, maximumResourcePackAmount + 1):
extraItemNamePool.append(createResourcePackName(i, packItem))
if self.multiworld.filler_item_types[self.player].value != 0: # Use duplicate items
if self.options.filler_item_types != self.options.filler_item_types.option_resource_packs: # Use duplicate items
dupeItemPool = item_table.copy()
# Remove frequencies if necessary
if self.multiworld.island_frequency_locations[self.player].value != 5: # Not completely random locations
if self.options.island_frequency_locations != self.options.island_frequency_locations.option_anywhere: # Not completely random locations
# If we let frequencies stay in with progressive-frequencies, the progressive-frequency item
# will be included 7 times. This is a massive flood of progressive-frequency items, so we
# instead add progressive-frequency as its own item a smaller amount of times to prevent
# flooding the duplicate item pool with them.
if self.multiworld.island_frequency_locations[self.player].value == 4:
if self.options.island_frequency_locations == self.options.island_frequency_locations.option_progressive:
for _ in range(2):
# Progressives are not in item_pool, need to create faux item for duplicate item pool
# This can still be filtered out later by duplicate_items setting
@@ -86,9 +87,9 @@ class RaftWorld(World):
dupeItemPool = (itm for itm in dupeItemPool if "Frequency" not in itm["name"])
# Remove progression or non-progression items if necessary
if (self.multiworld.duplicate_items[self.player].value == 0): # Progression only
if (self.options.duplicate_items == self.options.duplicate_items.option_progression): # Progression only
dupeItemPool = (itm for itm in dupeItemPool if itm["progression"] == True)
elif (self.multiworld.duplicate_items[self.player].value == 1): # Non-progression only
elif (self.options.duplicate_items == self.options.duplicate_items.option_non_progression): # Non-progression only
dupeItemPool = (itm for itm in dupeItemPool if itm["progression"] == False)
dupeItemPool = list(dupeItemPool)
@@ -115,14 +116,14 @@ class RaftWorld(World):
create_regions(self.multiworld, self.player)
def get_pre_fill_items(self):
if self.multiworld.island_frequency_locations[self.player] in [0, 1, 2, 3]:
if self.options.island_frequency_locations.is_filling_frequencies_in_world():
return [loc.item for loc in self.multiworld.get_filled_locations()]
return []
def create_item_replaceAsNecessary(self, name: str) -> Item:
isFrequency = "Frequency" in name
shouldUseProgressive = ((isFrequency and self.multiworld.island_frequency_locations[self.player].value == 4)
or (not isFrequency and self.multiworld.progressive_items[self.player].value))
shouldUseProgressive = bool((isFrequency and self.options.island_frequency_locations == self.options.island_frequency_locations.option_progressive)
or (not isFrequency and self.options.progressive_items))
if shouldUseProgressive and name in progressive_table:
name = progressive_table[name]
return self.create_item(name)
@@ -152,7 +153,7 @@ class RaftWorld(World):
return super(RaftWorld, self).collect_item(state, item, remove)
def pre_fill(self):
if self.multiworld.island_frequency_locations[self.player] == 0: # Vanilla
if self.options.island_frequency_locations == self.options.island_frequency_locations.option_vanilla:
self.setLocationItem("Radio Tower Frequency to Vasagatan", "Vasagatan Frequency")
self.setLocationItem("Vasagatan Frequency to Balboa", "Balboa Island Frequency")
self.setLocationItem("Relay Station quest", "Caravan Island Frequency")
@@ -160,7 +161,7 @@ class RaftWorld(World):
self.setLocationItem("Tangaroa Frequency to Varuna Point", "Varuna Point Frequency")
self.setLocationItem("Varuna Point Frequency to Temperance", "Temperance Frequency")
self.setLocationItem("Temperance Frequency to Utopia", "Utopia Frequency")
elif self.multiworld.island_frequency_locations[self.player] == 1: # Random on island
elif self.options.island_frequency_locations == self.options.island_frequency_locations.option_random_on_island:
self.setLocationItemFromRegion("RadioTower", "Vasagatan Frequency")
self.setLocationItemFromRegion("Vasagatan", "Balboa Island Frequency")
self.setLocationItemFromRegion("BalboaIsland", "Caravan Island Frequency")
@@ -168,7 +169,10 @@ class RaftWorld(World):
self.setLocationItemFromRegion("Tangaroa", "Varuna Point Frequency")
self.setLocationItemFromRegion("Varuna Point", "Temperance Frequency")
self.setLocationItemFromRegion("Temperance", "Utopia Frequency")
elif self.multiworld.island_frequency_locations[self.player] in [2, 3]:
elif self.options.island_frequency_locations in [
self.options.island_frequency_locations.option_random_island_order,
self.options.island_frequency_locations.option_random_on_island_random_order
]:
locationToFrequencyItemMap = {
"Vasagatan": "Vasagatan Frequency",
"BalboaIsland": "Balboa Island Frequency",
@@ -196,9 +200,9 @@ class RaftWorld(World):
else:
currentLocation = availableLocationList[0] # Utopia (only one left in list)
availableLocationList.remove(currentLocation)
if self.multiworld.island_frequency_locations[self.player] == 2: # Random island order
if self.options.island_frequency_locations == self.options.island_frequency_locations.option_random_island_order:
self.setLocationItem(locationToVanillaFrequencyLocationMap[previousLocation], locationToFrequencyItemMap[currentLocation])
elif self.multiworld.island_frequency_locations[self.player] == 3: # Random on island random order
elif self.options.island_frequency_locations == self.options.island_frequency_locations.option_random_on_island_random_order:
self.setLocationItemFromRegion(previousLocation, locationToFrequencyItemMap[currentLocation])
previousLocation = currentLocation
@@ -215,9 +219,9 @@ class RaftWorld(World):
def fill_slot_data(self):
return {
"IslandGenerationDistance": self.multiworld.island_generation_distance[self.player].value,
"ExpensiveResearch": bool(self.multiworld.expensive_research[self.player].value),
"DeathLink": bool(self.multiworld.death_link[self.player].value)
"IslandGenerationDistance": self.options.island_generation_distance.value,
"ExpensiveResearch": bool(self.options.expensive_research),
"DeathLink": bool(self.options.death_link)
}
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):