AHIT: Generation error fixes and some other bug fixes (#3663)
* duh * Fuck it * Major fixes * a * b * Even more fixes * New option - NoFreeRoamFinale * a * Hat Logic Fix * Just to be safe * multiworld.random to world.random * KeyError fix * Update .gitignore * Update __init__.py * Zoinks Scoob * ffs * Ruh Roh Raggy, more r-r-r-random bugs! * 0.9b - cleanup + expanded logic difficulty * Update Rules.py * Update Regions.py * AttributeError fix * 0.10b - New Options * 1.0 Preparations * Docs * Docs 2 * Fixes * Update __init__.py * Fixes * variable capture my beloathed * Fixes * a * 10 Seconds logic fix * 1.1 * 1.2 * a * New client * More client changes * 1.3 * Final touch-ups for 1.3 * 1.3.1 * 1.3.3 * Zero Jumps gen error fix * more fixes * Formatting improvements * typo * Update __init__.py * Revert "Update __init__.py" This reverts commit e178a7c0a6904ace803241cab3021d7b97177e90. * init * Update to new options API * Missed some * Snatcher Coins fix * Missed some more * some slight touch ups * rewind * a * fix things * Revert "Merge branch 'main' of https://github.com/CookieCat45/Archipelago-ahit" This reverts commit a2360fe197e77a723bb70006c5eb5725c7ed3826, reversing changes made to b8948bc4958855c6e342e18bdb8dc81cfcf09455. * Update .gitignore * 1.3.6 * Final touch-ups * Fix client and leftover old options api * Delete setup-ahitclient.py * Update .gitignore * old python version fix * proper warnings for invalid act plandos * Update worlds/ahit/docs/en_A Hat in Time.md Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com> * Update worlds/ahit/docs/setup_en.md Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com> * 120 char per line * "settings" to "options" * Update DeathWishRules.py * Update worlds/ahit/docs/en_A Hat in Time.md Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com> * No more loading the data package * cleanup + act plando fixes * almost forgot * Update Rules.py * a * Update worlds/ahit/Options.py Co-authored-by: Ixrec <ericrhitchcock@gmail.com> * Options stuff * oop * no unnecessary type hints * warn about depot download length in setup guide * Update worlds/ahit/Options.py Co-authored-by: Ixrec <ericrhitchcock@gmail.com> * typo Co-authored-by: Ixrec <ericrhitchcock@gmail.com> * Update worlds/ahit/Rules.py Co-authored-by: Ixrec <ericrhitchcock@gmail.com> * review stuff * More stuff from review * comment * 1.5 Update * link fix? * link fix 2 * Update setup_en.md * Update setup_en.md * Update setup_en.md * Evil * Good fucking lord * Review stuff again + Logic fixes * More review stuff * Even more review stuff - we're almost done * DW review stuff * Finish up review stuff * remove leftover stuff * a * assert item * add A Hat in Time to readme/codeowners files * Fix range options not being corrected properly * 120 chars per line in docs * Update worlds/ahit/Regions.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * Update worlds/ahit/DeathWishLocations.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * Remove some unnecessary option.class.value * Remove data_version and more option.class.value * Update worlds/ahit/Items.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * Remove the rest of option.class.value * Update worlds/ahit/DeathWishLocations.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * review stuff * Replace connect_regions with Region.connect * review stuff * Remove unnecessary Optional from LocData * Remove HatType.NONE * Update worlds/ahit/test/TestActs.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * fix so default tests actually don't run * Improve performance for death wish rules * rename test file * change test imports * 1000 is probably unnecessary * a * change state.count to state.has * stuff * starting inventory hats fix * shouldn't have done this lol * make ship shape task goal equal to number of tasksanity checks if set to 0 * a * change act shuffle starting acts + logic updates * dumb * option groups + lambda capture cringe + typo * a * b * missing option in groups * c * Fix Your Contract Has Expired being placed on first level when it shouldn't * yche fix * formatting * major logic bug fix for death wish * Update Regions.py * Add missing indirect connections * Fix generation error from chapter 2 start with act shuffle off * a * Revert "a" This reverts commit df58bbcd998585760cc6ac9ea54b6fdf142b4fd1. * Revert "Fix generation error from chapter 2 start with act shuffle off" This reverts commit 0f4d441824af34bf7a7cff19f5f14161752d8661. * bunch of fixes * Update Regions.py * Update __init__.py * Update __init__.py * Update __init__.py * Update Regions.py * Update worlds/ahit/__init__.py Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> * Update __init__.py * Update __init__.py --------- Co-authored-by: Danaël V. <104455676+ReverM@users.noreply.github.com> Co-authored-by: Nicholas Saylor <79181893+nicholassaylor@users.noreply.github.com> Co-authored-by: Ixrec <ericrhitchcock@gmail.com> Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com> Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
parent
6994f863e5
commit
e5c9b8ad0c
|
@ -39,7 +39,7 @@ def create_itempool(world: "HatInTimeWorld") -> List[Item]:
|
|||
continue
|
||||
else:
|
||||
if name == "Scooter Badge":
|
||||
if world.options.CTRLogic is CTRLogic.option_scooter or get_difficulty(world) >= Difficulty.MODERATE:
|
||||
if world.options.CTRLogic == CTRLogic.option_scooter or get_difficulty(world) >= Difficulty.MODERATE:
|
||||
item_type = ItemClassification.progression
|
||||
elif name == "No Bonk Badge" and world.is_dw():
|
||||
item_type = ItemClassification.progression
|
||||
|
|
|
@ -659,6 +659,10 @@ def is_valid_act_combo(world: "HatInTimeWorld", entrance_act: Region,
|
|||
if exit_act.name not in chapter_finales:
|
||||
return False
|
||||
|
||||
exit_chapter: str = act_chapters.get(exit_act.name)
|
||||
# make sure that certain time rift combinations never happen
|
||||
always_block: bool = exit_chapter != "Mafia Town" and exit_chapter != "Subcon Forest"
|
||||
if not ignore_certain_rules or always_block:
|
||||
if entrance_act.name in rift_access_regions and exit_act.name in rift_access_regions[entrance_act.name]:
|
||||
return False
|
||||
|
||||
|
@ -684,9 +688,12 @@ def is_valid_first_act(world: "HatInTimeWorld", act: Region) -> bool:
|
|||
if act.name not in guaranteed_first_acts:
|
||||
return False
|
||||
|
||||
if world.options.ActRandomizer == ActRandomizer.option_light and "Time Rift" in act.name:
|
||||
return False
|
||||
|
||||
# If there's only a single level in the starting chapter, only allow Mafia Town or Subcon Forest levels
|
||||
start_chapter = world.options.StartingChapter
|
||||
if start_chapter is ChapterIndex.ALPINE or start_chapter is ChapterIndex.SUBCON:
|
||||
if start_chapter == ChapterIndex.ALPINE or start_chapter == ChapterIndex.SUBCON:
|
||||
if "Time Rift" in act.name:
|
||||
return False
|
||||
|
||||
|
@ -723,7 +730,8 @@ def is_valid_first_act(world: "HatInTimeWorld", act: Region) -> bool:
|
|||
elif act.name == "Contractual Obligations" and world.options.ShuffleSubconPaintings:
|
||||
return False
|
||||
|
||||
if world.options.ShuffleSubconPaintings and act_chapters.get(act.name, "") == "Subcon Forest":
|
||||
if world.options.ShuffleSubconPaintings and "Time Rift" not in act.name \
|
||||
and act_chapters.get(act.name, "") == "Subcon Forest":
|
||||
# Only allow Subcon levels if painting skips are allowed
|
||||
if diff < Difficulty.MODERATE or world.options.NoPaintingSkips:
|
||||
return False
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from worlds.AutoWorld import CollectionState
|
||||
from worlds.generic.Rules import add_rule, set_rule
|
||||
from .Locations import location_table, zipline_unlocks, is_location_valid, contract_locations, \
|
||||
shop_locations, event_locs
|
||||
from .Locations import location_table, zipline_unlocks, is_location_valid, shop_locations, event_locs
|
||||
from .Types import HatType, ChapterIndex, hat_type_to_item, Difficulty, HitType
|
||||
from BaseClasses import Location, Entrance, Region
|
||||
from typing import TYPE_CHECKING, List, Callable, Union, Dict
|
||||
|
@ -148,14 +147,14 @@ def set_rules(world: "HatInTimeWorld"):
|
|||
if world.is_dlc1():
|
||||
chapter_list.append(ChapterIndex.CRUISE)
|
||||
|
||||
if world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
if world.is_dlc2() and final_chapter != ChapterIndex.METRO:
|
||||
chapter_list.append(ChapterIndex.METRO)
|
||||
|
||||
chapter_list.remove(starting_chapter)
|
||||
world.random.shuffle(chapter_list)
|
||||
|
||||
# Make sure Alpine is unlocked before any DLC chapters are, as the Alpine door needs to be open to access them
|
||||
if starting_chapter is not ChapterIndex.ALPINE and (world.is_dlc1() or world.is_dlc2()):
|
||||
if starting_chapter != ChapterIndex.ALPINE and (world.is_dlc1() or world.is_dlc2()):
|
||||
index1 = 69
|
||||
index2 = 69
|
||||
pos: int
|
||||
|
@ -165,7 +164,7 @@ def set_rules(world: "HatInTimeWorld"):
|
|||
if world.is_dlc1():
|
||||
index1 = chapter_list.index(ChapterIndex.CRUISE)
|
||||
|
||||
if world.is_dlc2() and final_chapter is not ChapterIndex.METRO:
|
||||
if world.is_dlc2() and final_chapter != ChapterIndex.METRO:
|
||||
index2 = chapter_list.index(ChapterIndex.METRO)
|
||||
|
||||
lowest_index = min(index1, index2)
|
||||
|
@ -242,9 +241,6 @@ def set_rules(world: "HatInTimeWorld"):
|
|||
if not is_location_valid(world, key):
|
||||
continue
|
||||
|
||||
if key in contract_locations.keys():
|
||||
continue
|
||||
|
||||
loc = world.multiworld.get_location(key, world.player)
|
||||
|
||||
for hat in data.required_hats:
|
||||
|
@ -256,7 +252,7 @@ def set_rules(world: "HatInTimeWorld"):
|
|||
if data.paintings > 0 and world.options.ShuffleSubconPaintings:
|
||||
add_rule(loc, lambda state, paintings=data.paintings: has_paintings(state, world, paintings))
|
||||
|
||||
if data.hit_type is not HitType.none and world.options.UmbrellaLogic:
|
||||
if data.hit_type != HitType.none and world.options.UmbrellaLogic:
|
||||
if data.hit_type == HitType.umbrella:
|
||||
add_rule(loc, lambda state: state.has("Umbrella", world.player))
|
||||
|
||||
|
@ -518,7 +514,7 @@ def set_hard_rules(world: "HatInTimeWorld"):
|
|||
lambda state: can_use_hat(state, world, HatType.ICE))
|
||||
|
||||
# Hard: clear Rush Hour with Brewing Hat only
|
||||
if world.options.NoTicketSkips is not NoTicketSkips.option_true:
|
||||
if world.options.NoTicketSkips != NoTicketSkips.option_true:
|
||||
set_rule(world.multiworld.get_location("Act Completion (Rush Hour)", world.player),
|
||||
lambda state: can_use_hat(state, world, HatType.BREWING))
|
||||
else:
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
from BaseClasses import Item, ItemClassification, Tutorial, Location, MultiWorld
|
||||
from .Items import item_table, create_item, relic_groups, act_contracts, create_itempool, get_shop_trap_name, \
|
||||
calculate_yarn_costs
|
||||
calculate_yarn_costs, alps_hooks
|
||||
from .Regions import create_regions, randomize_act_entrances, chapter_act_info, create_events, get_shuffled_region
|
||||
from .Locations import location_table, contract_locations, is_location_valid, get_location_names, TASKSANITY_START_ID, \
|
||||
get_total_locations
|
||||
from .Rules import set_rules
|
||||
from .Rules import set_rules, has_paintings
|
||||
from .Options import AHITOptions, slot_data_options, adjust_options, RandomizeHatOrder, EndGoal, create_option_groups
|
||||
from .Types import HatType, ChapterIndex, HatInTimeItem, hat_type_to_item
|
||||
from .Types import HatType, ChapterIndex, HatInTimeItem, hat_type_to_item, Difficulty
|
||||
from .DeathWishLocations import create_dw_regions, dw_classes, death_wishes
|
||||
from .DeathWishRules import set_dw_rules, create_enemy_events, hit_list, bosses
|
||||
from worlds.AutoWorld import World, WebWorld, CollectionState
|
||||
from worlds.generic.Rules import add_rule
|
||||
from typing import List, Dict, TextIO
|
||||
from worlds.LauncherComponents import Component, components, icon_paths, launch_subprocess, Type
|
||||
from Utils import local_path
|
||||
|
@ -86,19 +87,27 @@ class HatInTimeWorld(World):
|
|||
if self.is_dw_only():
|
||||
return
|
||||
|
||||
# If our starting chapter is 4 and act rando isn't on, force hookshot into inventory
|
||||
# If starting chapter is 3 and painting shuffle is enabled, and act rando isn't, give one free painting unlock
|
||||
start_chapter: ChapterIndex = ChapterIndex(self.options.StartingChapter)
|
||||
# Take care of some extremely restrictive starts in other chapters with act shuffle off
|
||||
if not self.options.ActRandomizer:
|
||||
start_chapter = self.options.StartingChapter
|
||||
if start_chapter == ChapterIndex.ALPINE:
|
||||
self.multiworld.push_precollected(self.create_item("Hookshot Badge"))
|
||||
if self.options.UmbrellaLogic:
|
||||
self.multiworld.push_precollected(self.create_item("Umbrella"))
|
||||
|
||||
if start_chapter == ChapterIndex.ALPINE or start_chapter == ChapterIndex.SUBCON:
|
||||
if not self.options.ActRandomizer:
|
||||
if start_chapter == ChapterIndex.ALPINE:
|
||||
self.multiworld.push_precollected(self.create_item("Hookshot Badge"))
|
||||
if self.options.UmbrellaLogic:
|
||||
self.multiworld.push_precollected(self.create_item("Umbrella"))
|
||||
|
||||
if start_chapter == ChapterIndex.SUBCON and self.options.ShuffleSubconPaintings:
|
||||
if self.options.ShuffleAlpineZiplines:
|
||||
ziplines = list(alps_hooks.keys())
|
||||
ziplines.remove("Zipline Unlock - The Twilight Bell Path") # not enough checks from this one
|
||||
self.multiworld.push_precollected(self.create_item(self.random.choice(ziplines)))
|
||||
elif start_chapter == ChapterIndex.SUBCON:
|
||||
if self.options.ShuffleSubconPaintings:
|
||||
self.multiworld.push_precollected(self.create_item("Progressive Painting Unlock"))
|
||||
elif start_chapter == ChapterIndex.BIRDS:
|
||||
if self.options.UmbrellaLogic:
|
||||
if self.options.LogicDifficulty < Difficulty.EXPERT:
|
||||
self.multiworld.push_precollected(self.create_item("Umbrella"))
|
||||
elif self.options.LogicDifficulty < Difficulty.MODERATE:
|
||||
self.multiworld.push_precollected(self.create_item("Umbrella"))
|
||||
|
||||
def create_regions(self):
|
||||
# noinspection PyClassVar
|
||||
|
@ -119,7 +128,10 @@ class HatInTimeWorld(World):
|
|||
# place vanilla contract locations if contract shuffle is off
|
||||
if not self.options.ShuffleActContracts:
|
||||
for name in contract_locations.keys():
|
||||
self.multiworld.get_location(name, self.player).place_locked_item(create_item(self, name))
|
||||
loc = self.get_location(name)
|
||||
loc.place_locked_item(create_item(self, name))
|
||||
if self.options.ShuffleSubconPaintings and loc.name != "Snatcher's Contract - The Subcon Well":
|
||||
add_rule(loc, lambda state: has_paintings(state, self, 1))
|
||||
|
||||
def create_items(self):
|
||||
if self.has_yarn():
|
||||
|
@ -317,7 +329,7 @@ class HatInTimeWorld(World):
|
|||
|
||||
def remove(self, state: "CollectionState", item: "Item") -> bool:
|
||||
old_count: int = state.count(item.name, self.player)
|
||||
change = super().collect(state, item)
|
||||
change = super().remove(state, item)
|
||||
if change and old_count == 1:
|
||||
if "Stamp" in item.name:
|
||||
if "2 Stamp" in item.name:
|
||||
|
|
Loading…
Reference in New Issue