 99c02a3eb3
			
		
	
	99c02a3eb3
	
	
	
		
			
			* 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. * Fix option typo * I lied, it's actually two lines --------- 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>
		
			
				
	
	
		
			244 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from .Types import HatInTimeLocation, HatInTimeItem
 | |
| from .Regions import create_region
 | |
| from BaseClasses import Region, LocationProgressType, ItemClassification
 | |
| from worlds.generic.Rules import add_rule
 | |
| from typing import List, TYPE_CHECKING
 | |
| from .Locations import death_wishes
 | |
| from .Options import EndGoal
 | |
| 
 | |
| if TYPE_CHECKING:
 | |
|     from . import HatInTimeWorld
 | |
| 
 | |
| 
 | |
| dw_prereqs = {
 | |
|     "So You're Back From Outer Space":  ["Beat the Heat"],
 | |
|     "Snatcher's Hit List":              ["Beat the Heat"],
 | |
|     "Snatcher Coins in Mafia Town":     ["So You're Back From Outer Space"],
 | |
|     "Rift Collapse: Mafia of Cooks":    ["So You're Back From Outer Space"],
 | |
|     "Collect-a-thon":                   ["So You're Back From Outer Space"],
 | |
|     "She Speedran from Outer Space":    ["Rift Collapse: Mafia of Cooks"],
 | |
|     "Mafia's Jumps":                    ["She Speedran from Outer Space"],
 | |
|     "Vault Codes in the Wind":          ["Collect-a-thon", "She Speedran from Outer Space"],
 | |
|     "Encore! Encore!":                  ["Collect-a-thon"],
 | |
| 
 | |
|     "Security Breach":                          ["Beat the Heat"],
 | |
|     "Rift Collapse: Dead Bird Studio":          ["Security Breach"],
 | |
|     "The Great Big Hootenanny":                 ["Security Breach"],
 | |
|     "10 Seconds until Self-Destruct":           ["The Great Big Hootenanny"],
 | |
|     "Killing Two Birds":                        ["Rift Collapse: Dead Bird Studio", "10 Seconds until Self-Destruct"],
 | |
|     "Community Rift: Rhythm Jump Studio":       ["10 Seconds until Self-Destruct"],
 | |
|     "Snatcher Coins in Battle of the Birds":    ["The Great Big Hootenanny"],
 | |
|     "Zero Jumps":                               ["Rift Collapse: Dead Bird Studio"],
 | |
|     "Snatcher Coins in Nyakuza Metro":          ["Killing Two Birds"],
 | |
| 
 | |
|     "Speedrun Well":                    ["Beat the Heat"],
 | |
|     "Rift Collapse: Sleepy Subcon":     ["Speedrun Well"],
 | |
|     "Boss Rush":                        ["Speedrun Well"],
 | |
|     "Quality Time with Snatcher":       ["Rift Collapse: Sleepy Subcon"],
 | |
|     "Breaching the Contract":           ["Boss Rush", "Quality Time with Snatcher"],
 | |
|     "Community Rift: Twilight Travels": ["Quality Time with Snatcher"],
 | |
|     "Snatcher Coins in Subcon Forest":  ["Rift Collapse: Sleepy Subcon"],
 | |
| 
 | |
|     "Bird Sanctuary":                       ["Beat the Heat"],
 | |
|     "Snatcher Coins in Alpine Skyline":     ["Bird Sanctuary"],
 | |
|     "Wound-Up Windmill":                    ["Bird Sanctuary"],
 | |
|     "Rift Collapse: Alpine Skyline":        ["Bird Sanctuary"],
 | |
|     "Camera Tourist":                       ["Rift Collapse: Alpine Skyline"],
 | |
|     "Community Rift: The Mountain Rift":    ["Rift Collapse: Alpine Skyline"],
 | |
|     "The Illness has Speedrun":             ["Rift Collapse: Alpine Skyline", "Wound-Up Windmill"],
 | |
| 
 | |
|     "The Mustache Gauntlet":            ["Wound-Up Windmill"],
 | |
|     "No More Bad Guys":                 ["The Mustache Gauntlet"],
 | |
|     "Seal the Deal":                    ["Encore! Encore!", "Killing Two Birds",
 | |
|                                          "Breaching the Contract", "No More Bad Guys"],
 | |
| 
 | |
|     "Rift Collapse: Deep Sea":          ["Rift Collapse: Mafia of Cooks", "Rift Collapse: Dead Bird Studio",
 | |
|                                          "Rift Collapse: Sleepy Subcon", "Rift Collapse: Alpine Skyline"],
 | |
| 
 | |
|     "Cruisin' for a Bruisin'":          ["Rift Collapse: Deep Sea"],
 | |
| }
 | |
| 
 | |
| dw_candles = [
 | |
|     "Snatcher's Hit List",
 | |
|     "Zero Jumps",
 | |
|     "Camera Tourist",
 | |
|     "Snatcher Coins in Mafia Town",
 | |
|     "Snatcher Coins in Battle of the Birds",
 | |
|     "Snatcher Coins in Subcon Forest",
 | |
|     "Snatcher Coins in Alpine Skyline",
 | |
|     "Snatcher Coins in Nyakuza Metro",
 | |
| ]
 | |
| 
 | |
| annoying_dws = [
 | |
|     "Vault Codes in the Wind",
 | |
|     "Boss Rush",
 | |
|     "Camera Tourist",
 | |
|     "The Mustache Gauntlet",
 | |
|     "Rift Collapse: Deep Sea",
 | |
|     "Cruisin' for a Bruisin'",
 | |
|     "Seal the Deal",  # Non-excluded if goal
 | |
| ]
 | |
| 
 | |
| # includes the above as well
 | |
| annoying_bonuses = [
 | |
|     "So You're Back From Outer Space",
 | |
|     "Encore! Encore!",
 | |
|     "Snatcher's Hit List",
 | |
|     "Vault Codes in the Wind",
 | |
|     "10 Seconds until Self-Destruct",
 | |
|     "Killing Two Birds",
 | |
|     "Zero Jumps",
 | |
|     "Boss Rush",
 | |
|     "Bird Sanctuary",
 | |
|     "The Mustache Gauntlet",
 | |
|     "Wound-Up Windmill",
 | |
|     "Camera Tourist",
 | |
|     "Rift Collapse: Deep Sea",
 | |
|     "Cruisin' for a Bruisin'",
 | |
|     "Seal the Deal",
 | |
| ]
 | |
| 
 | |
| dw_classes = {
 | |
|     "Beat the Heat":                    "Hat_SnatcherContract_DeathWish_HeatingUpHarder",
 | |
|     "So You're Back From Outer Space":  "Hat_SnatcherContract_DeathWish_BackFromSpace",
 | |
|     "Snatcher's Hit List":              "Hat_SnatcherContract_DeathWish_KillEverybody",
 | |
|     "Collect-a-thon":                   "Hat_SnatcherContract_DeathWish_PonFrenzy",
 | |
|     "Rift Collapse: Mafia of Cooks":    "Hat_SnatcherContract_DeathWish_RiftCollapse_MafiaTown",
 | |
|     "Encore! Encore!":                  "Hat_SnatcherContract_DeathWish_MafiaBossEX",
 | |
|     "She Speedran from Outer Space":    "Hat_SnatcherContract_DeathWish_Speedrun_MafiaAlien",
 | |
|     "Mafia's Jumps":                    "Hat_SnatcherContract_DeathWish_NoAPresses_MafiaAlien",
 | |
|     "Vault Codes in the Wind":          "Hat_SnatcherContract_DeathWish_MovingVault",
 | |
|     "Snatcher Coins in Mafia Town":     "Hat_SnatcherContract_DeathWish_Tokens_MafiaTown",
 | |
| 
 | |
|     "Security Breach":                          "Hat_SnatcherContract_DeathWish_DeadBirdStudioMoreGuards",
 | |
|     "The Great Big Hootenanny":                 "Hat_SnatcherContract_DeathWish_DifficultParade",
 | |
|     "Rift Collapse: Dead Bird Studio":          "Hat_SnatcherContract_DeathWish_RiftCollapse_Birds",
 | |
|     "10 Seconds until Self-Destruct":           "Hat_SnatcherContract_DeathWish_TrainRushShortTime",
 | |
|     "Killing Two Birds":                        "Hat_SnatcherContract_DeathWish_BirdBossEX",
 | |
|     "Snatcher Coins in Battle of the Birds":    "Hat_SnatcherContract_DeathWish_Tokens_Birds",
 | |
|     "Zero Jumps":                               "Hat_SnatcherContract_DeathWish_NoAPresses",
 | |
| 
 | |
|     "Speedrun Well":                    "Hat_SnatcherContract_DeathWish_Speedrun_SubWell",
 | |
|     "Rift Collapse: Sleepy Subcon":     "Hat_SnatcherContract_DeathWish_RiftCollapse_Subcon",
 | |
|     "Boss Rush":                        "Hat_SnatcherContract_DeathWish_BossRush",
 | |
|     "Quality Time with Snatcher":       "Hat_SnatcherContract_DeathWish_SurvivalOfTheFittest",
 | |
|     "Breaching the Contract":           "Hat_SnatcherContract_DeathWish_SnatcherEX",
 | |
|     "Snatcher Coins in Subcon Forest":  "Hat_SnatcherContract_DeathWish_Tokens_Subcon",
 | |
| 
 | |
|     "Bird Sanctuary":                   "Hat_SnatcherContract_DeathWish_NiceBirdhouse",
 | |
|     "Rift Collapse: Alpine Skyline":    "Hat_SnatcherContract_DeathWish_RiftCollapse_Alps",
 | |
|     "Wound-Up Windmill":                "Hat_SnatcherContract_DeathWish_FastWindmill",
 | |
|     "The Illness has Speedrun":         "Hat_SnatcherContract_DeathWish_Speedrun_Illness",
 | |
|     "Snatcher Coins in Alpine Skyline": "Hat_SnatcherContract_DeathWish_Tokens_Alps",
 | |
|     "Camera Tourist":                   "Hat_SnatcherContract_DeathWish_CameraTourist_1",
 | |
| 
 | |
|     "The Mustache Gauntlet":            "Hat_SnatcherContract_DeathWish_HardCastle",
 | |
|     "No More Bad Guys":                 "Hat_SnatcherContract_DeathWish_MuGirlEX",
 | |
| 
 | |
|     "Seal the Deal":                    "Hat_SnatcherContract_DeathWish_BossRushEX",
 | |
|     "Rift Collapse: Deep Sea":          "Hat_SnatcherContract_DeathWish_RiftCollapse_Cruise",
 | |
|     "Cruisin' for a Bruisin'":          "Hat_SnatcherContract_DeathWish_EndlessTasks",
 | |
| 
 | |
|     "Community Rift: Rhythm Jump Studio":   "Hat_SnatcherContract_DeathWish_CommunityRift_RhythmJump",
 | |
|     "Community Rift: Twilight Travels":     "Hat_SnatcherContract_DeathWish_CommunityRift_TwilightTravels",
 | |
|     "Community Rift: The Mountain Rift":    "Hat_SnatcherContract_DeathWish_CommunityRift_MountainRift",
 | |
| 
 | |
|     "Snatcher Coins in Nyakuza Metro":      "Hat_SnatcherContract_DeathWish_Tokens_Metro",
 | |
| }
 | |
| 
 | |
| 
 | |
| def create_dw_regions(world: "HatInTimeWorld"):
 | |
|     if world.options.DWExcludeAnnoyingContracts:
 | |
|         for name in annoying_dws:
 | |
|             world.excluded_dws.append(name)
 | |
| 
 | |
|     if not world.options.DWEnableBonus and world.options.DWAutoCompleteBonuses:
 | |
|         for name in death_wishes:
 | |
|             world.excluded_bonuses.append(name)
 | |
|     if world.options.DWExcludeAnnoyingBonuses and not world.options.DWAutoCompleteBonuses:
 | |
|         for name in annoying_bonuses:
 | |
|             world.excluded_bonuses.append(name)
 | |
| 
 | |
|     if world.options.DWExcludeCandles:
 | |
|         for name in dw_candles:
 | |
|             if name not in world.excluded_dws:
 | |
|                 world.excluded_dws.append(name)
 | |
| 
 | |
|     spaceship = world.multiworld.get_region("Spaceship", world.player)
 | |
|     dw_map: Region = create_region(world, "Death Wish Map")
 | |
|     entrance = spaceship.connect(dw_map, "-> Death Wish Map")
 | |
|     add_rule(entrance, lambda state: state.has("Time Piece", world.player, world.options.DWTimePieceRequirement))
 | |
| 
 | |
|     if world.options.DWShuffle:
 | |
|         # Connect Death Wishes randomly to one another in a linear sequence
 | |
|         dw_list: List[str] = []
 | |
|         for name in death_wishes.keys():
 | |
|             # Don't shuffle excluded or invalid Death Wishes
 | |
|             if not world.is_dlc2() and name == "Snatcher Coins in Nyakuza Metro" or world.is_dw_excluded(name):
 | |
|                 continue
 | |
| 
 | |
|             dw_list.append(name)
 | |
| 
 | |
|         world.random.shuffle(dw_list)
 | |
|         count = world.random.randint(world.options.DWShuffleCountMin.value, world.options.DWShuffleCountMax.value)
 | |
|         dw_shuffle: List[str] = []
 | |
|         total = min(len(dw_list), count)
 | |
|         for i in range(total):
 | |
|             dw_shuffle.append(dw_list[i])
 | |
| 
 | |
|         # Seal the Deal is always last if it's the goal
 | |
|         if world.options.EndGoal == EndGoal.option_seal_the_deal:
 | |
|             if "Seal the Deal" in dw_shuffle:
 | |
|                 dw_shuffle.remove("Seal the Deal")
 | |
| 
 | |
|             dw_shuffle.append("Seal the Deal")
 | |
| 
 | |
|         world.dw_shuffle = dw_shuffle
 | |
|         prev_dw = dw_map
 | |
|         for death_wish_name in dw_shuffle:
 | |
|             dw = create_region(world, death_wish_name)
 | |
|             prev_dw.connect(dw)
 | |
|             create_dw_locations(world, dw)
 | |
|             prev_dw = dw
 | |
|     else:
 | |
|         # DWShuffle is disabled, use vanilla connections
 | |
|         for key in death_wishes.keys():
 | |
|             if key == "Snatcher Coins in Nyakuza Metro" and not world.is_dlc2():
 | |
|                 world.excluded_dws.append(key)
 | |
|                 continue
 | |
| 
 | |
|             dw = create_region(world, key)
 | |
|             if key == "Beat the Heat":
 | |
|                 dw_map.connect(dw, f"{dw_map.name} -> Beat the Heat")
 | |
|             elif key in dw_prereqs.keys():
 | |
|                 for name in dw_prereqs[key]:
 | |
|                     parent = world.multiworld.get_region(name, world.player)
 | |
|                     parent.connect(dw, f"{parent.name} -> {key}")
 | |
| 
 | |
|             create_dw_locations(world, dw)
 | |
| 
 | |
| 
 | |
| def create_dw_locations(world: "HatInTimeWorld", dw: Region):
 | |
|     loc_id = death_wishes[dw.name]
 | |
|     main_objective = HatInTimeLocation(world.player, f"{dw.name} - Main Objective", loc_id, dw)
 | |
|     full_clear = HatInTimeLocation(world.player, f"{dw.name} - All Clear", loc_id + 1, dw)
 | |
|     main_stamp = HatInTimeLocation(world.player, f"Main Stamp - {dw.name}", None, dw)
 | |
|     bonus_stamps = HatInTimeLocation(world.player, f"Bonus Stamps - {dw.name}", None, dw)
 | |
|     main_stamp.show_in_spoiler = False
 | |
|     bonus_stamps.show_in_spoiler = False
 | |
|     dw.locations.append(main_stamp)
 | |
|     dw.locations.append(bonus_stamps)
 | |
|     main_stamp.place_locked_item(HatInTimeItem(f"1 Stamp - {dw.name}",
 | |
|                                                ItemClassification.progression, None, world.player))
 | |
|     bonus_stamps.place_locked_item(HatInTimeItem(f"2 Stamp - {dw.name}",
 | |
|                                                  ItemClassification.progression, None, world.player))
 | |
| 
 | |
|     if dw.name in world.excluded_dws:
 | |
|         main_objective.progress_type = LocationProgressType.EXCLUDED
 | |
|         full_clear.progress_type = LocationProgressType.EXCLUDED
 | |
|     elif world.is_bonus_excluded(dw.name):
 | |
|         full_clear.progress_type = LocationProgressType.EXCLUDED
 | |
| 
 | |
|     dw.locations.append(main_objective)
 | |
|     dw.locations.append(full_clear)
 |