Skip to content

Commit

Permalink
0.10b - New Options
Browse files Browse the repository at this point in the history
  • Loading branch information
CookieCat45 committed Sep 2, 2023
1 parent 1f916e8 commit 215594d
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 53 deletions.
4 changes: 4 additions & 0 deletions worlds/ahit/Locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ def is_location_valid(world: World, location: str) -> bool:
if location in shop_locations and location not in world.shop_locs:
return False

data = location_table.get(location) or event_locs.get(location)
if data.region == "Time Rift - Tour" and world.multiworld.ExcludeTour[world.player].value > 0:
return False

return True


Expand Down
57 changes: 32 additions & 25 deletions worlds/ahit/Options.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import typing
from worlds.AutoWorld import World
from Options import Option, Range, Toggle, DeathLink, Choice
from Options import Option, Range, Toggle, DeathLink, Choice, OptionDict
from .Items import get_total_time_pieces


Expand Down Expand Up @@ -72,26 +72,22 @@ class ActRandomizer(Choice):
default = 1


class ActPlando(OptionDict):
"""Plando acts onto other acts. For example, \"Train Rush\": \"Alpine Free Roam\""""
display_name = "Act Plando"


class ShuffleAlpineZiplines(Toggle):
"""If enabled, Alpine's zipline paths leading to the peaks will be locked behind items."""
display_name = "Shuffle Alpine Ziplines"
default = 0


class VanillaAlpine(Choice):
"""If enabled, force Alpine (and optionally its finale) onto their vanilla locations in act shuffle."""
display_name = "Vanilla Alpine Skyline"
option_false = 0
option_true = 1
option_finale = 2
class FinaleShuffle(Toggle):
"""If enabled, chapter finales will only be shuffled amongst each other in act shuffle."""
default = 0


class NoFreeRoamFinale(Toggle):
"""If enabled, prevent Free Roam acts from being shuffled onto chapter finales."""
default = 1


class LogicDifficulty(Choice):
"""Choose the difficulty setting for logic."""
display_name = "Logic Difficulty"
Expand Down Expand Up @@ -221,6 +217,22 @@ class TasksanityCheckCount(Range):
default = 18


class ExcludeTour(Toggle):
"""Removes the Tour time rift from the game. This option is recommended if you don't want to deal with
important levels being shuffled onto the Tour time rift, or important items being shuffled onto Tour pages
when your goal is Time's End."""
display_name = "Exclude Tour Time Rift"
default = 0


class ShipShapeCustomTaskGoal(Range):
"""Change the amount of tasks required to complete Ship Shape. This will not affect Cruisin' for a Bruisin'."""
display_name = "Ship Shape Custom Task Goal"
range_start = 5
range_end = 30
default = 18


class EnableDLC2(Toggle):
"""Shuffle content from Nyakuza Metro (Chapter 7) into the game.
DO NOT ENABLE THIS OPTION IF YOU DO NOT HAVE NYAKUZA METRO DLC INSTALLED!!!"""
Expand All @@ -238,7 +250,7 @@ class MetroMinPonCost(Range):

class MetroMaxPonCost(Range):
"""The most expensive an item can be in any Nyakuza Metro shop. Includes ticket booths."""
display_name = "Metro Shops Minimum Pon Cost"
display_name = "Metro Shops Maximum Pon Cost"
range_start = 10
range_end = 800
default = 200
Expand Down Expand Up @@ -267,14 +279,6 @@ class BaseballBat(Toggle):
default = 0


class VanillaMetro(Choice):
"""Force Nyakuza Metro (and optionally its finale) onto their vanilla locations in act shuffle."""
display_name = "Vanilla Metro"
option_false = 0
option_true = 1
option_finale = 2


class ChapterCostIncrement(Range):
"""Lower values mean chapter costs increase slower. Higher values make the cost differences more steep."""
display_name = "Chapter Cost Increment"
Expand Down Expand Up @@ -357,7 +361,7 @@ class DWExcludeAnnoyingContracts(Toggle):

class DWExcludeAnnoyingBonuses(Toggle):
"""NOT IMPLEMENTED If Death Wish full completions are shuffled in, exclude particularly tedious Death Wish full completions
from the pool"""
from the pool. DANGER! DISABLE AT YOUR OWN RISK! THIS OPTION WHEN DISABLED CAN CREATE VERY DIFFICULT SEEDS!!!"""
display_name = "Exclude Annoying Death Wish Full Completions"
default = 1

Expand Down Expand Up @@ -459,9 +463,9 @@ class ParadeTrapWeight(Range):

"EndGoal": EndGoal,
"ActRandomizer": ActRandomizer,
"ActPlando": ActPlando,
"ShuffleAlpineZiplines": ShuffleAlpineZiplines,
"VanillaAlpine": VanillaAlpine,
"NoFreeRoamFinale": NoFreeRoamFinale,
"FinaleShuffle": FinaleShuffle,
"LogicDifficulty": LogicDifficulty,
"KnowledgeChecks": KnowledgeChecks,
"YarnBalancePercent": YarnBalancePercent,
Expand All @@ -480,11 +484,12 @@ class ParadeTrapWeight(Range):
"Tasksanity": Tasksanity,
"TasksanityTaskStep": TasksanityTaskStep,
"TasksanityCheckCount": TasksanityCheckCount,
"ExcludeTour": ExcludeTour,
"ShipShapeCustomTaskGoal": ShipShapeCustomTaskGoal,

"EnableDeathWish": EnableDeathWish,
"EnableDLC2": EnableDLC2,
"BaseballBat": BaseballBat,
"VanillaMetro": VanillaMetro,
"MetroMinPonCost": MetroMinPonCost,
"MetroMaxPonCost": MetroMaxPonCost,
"NyakuzaThugMinShopItems": NyakuzaThugMinShopItems,
Expand Down Expand Up @@ -534,6 +539,8 @@ class ParadeTrapWeight(Range):
"Tasksanity": Tasksanity,
"TasksanityTaskStep": TasksanityTaskStep,
"TasksanityCheckCount": TasksanityCheckCount,
"ShipShapeCustomTaskGoal": ShipShapeCustomTaskGoal,
"ExcludeTour": ExcludeTour,

"EnableDeathWish": EnableDeathWish,

Expand Down
129 changes: 102 additions & 27 deletions worlds/ahit/Regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,16 @@
"Battle of the Birds - Finale A": "Award Ceremony",
}

# Blacklisted act shuffle combinations to help prevent impossible layouts. Mostly for free roam acts.
blacklisted_combos = {
"The Illness has Spread": ["Alpine Free Roam"],
"Rush Hour": ["Nyakuza Free Roam"],
"Time Rift - The Owl Express": ["Alpine Free Roam", "Nyakuza Free Roam"],
"Time Rift - The Moon": ["Alpine Free Roam", "Nyakuza Free Roam"],
"Time Rift - Dead Bird Studio": ["Alpine Free Roam", "Nyakuza Free Roam"],
"Time Rift - Rumbi Factory": ["Alpine Free Roam"],
}


def create_regions(world: World):
w = world
Expand Down Expand Up @@ -371,7 +381,9 @@ def create_regions(world: World):
connect_regions(ac_act3, cruise_ship, "Cruise Ship Entrance RTB", p)
create_rift_connections(w, create_region(w, "Time Rift - Balcony"))
create_rift_connections(w, create_region(w, "Time Rift - Deep Sea"))
create_rift_connections(w, create_region(w, "Time Rift - Tour"))

if mw.ExcludeTour[world.player].value == 0:
create_rift_connections(w, create_region(w, "Time Rift - Tour"))

if mw.Tasksanity[p].value > 0:
create_tasksanity_locations(w)
Expand Down Expand Up @@ -419,9 +431,52 @@ def create_tasksanity_locations(world: World):
ship_shape.locations.append(location)


def is_valid_plando(world: World, region: str) -> bool:
if region in blacklisted_acts.values():
return False

if region not in world.multiworld.ActPlando[world.player].keys():
return False

act = world.multiworld.ActPlando[world.player].get(region)
if act in blacklisted_acts.values():
return False

# Don't allow plando-ing things onto the first act that aren't completable with nothing
is_first_act: bool = act_chapters[region] == get_first_chapter_region(world).name \
and region in act_entrances.keys() and ("Act 1" in act_entrances[region] or "Free Roam" in act_entrances[region])

if is_first_act:
if act_chapters[act] == "Subcon Forest" and world.multiworld.ShuffleSubconPaintings[world.player].value > 0:
return False

if world.multiworld.UmbrellaLogic[world.player].value > 0 \
and (act == "Heating Up Mafia Town" or act == "Queen Vanessa's Manor"):
return False

if act not in guaranteed_first_acts:
return False

# Don't allow straight up impossible mappings
if region == "The Illness has Spread" and act == "Alpine Free Roam":
return False

if region == "Rush Hour" and act == "Nyakuza Free Roam":
return False

if region == "Time Rift - Rumbi Factory" and act == "Nyakuza Free Roam":
return False

if region == "Time Rift - The Owl Express" and act == "Murder on the Owl Express":
return False

return any(a.name == world.multiworld.ActPlando[world.player].get(region) for a in
world.multiworld.get_regions(world.player))


def randomize_act_entrances(world: World):
region_list: typing.List[Region] = get_act_regions(world)
world.multiworld.random.shuffle(region_list)
world.random.shuffle(region_list)

separate_rifts: bool = bool(world.multiworld.ActRandomizer[world.player].value == 1)

Expand All @@ -436,12 +491,21 @@ def randomize_act_entrances(world: World):
region_list.remove(region)
region_list.append(region)

# We want to do these first as well, since they can be blocked from being shuffled onto freeroam
for region in region_list.copy():
if region.name in chapter_finales or region.name == "Cheating the Race":
if region.name in chapter_finales:
region_list.remove(region)
region_list.append(region)

for region in region_list.copy():
if region.name in world.multiworld.ActPlando[world.player].keys():
if is_valid_plando(world, region.name):
region_list.remove(region)
region_list.append(region)
else:
print("Disallowing act plando for",
world.multiworld.player_name[world.player],
"-", region.name, ":", world.multiworld.ActPlando[world.player].get(region.name))

# Reverse the list, so we can do what we want to do first
region_list.reverse()

Expand All @@ -465,6 +529,9 @@ def randomize_act_entrances(world: World):
and "Free Roam" not in act_entrances[region.name]:
continue

if region.name in world.multiworld.ActPlando[world.player].keys() and is_valid_plando(world, region.name):
has_guaranteed = True

i = 0

# Already mapped to something else
Expand All @@ -481,6 +548,9 @@ def randomize_act_entrances(world: World):
if candidate.name not in guaranteed_first_acts:
continue

if candidate.name in world.multiworld.ActPlando[world.player].values():
continue

# Not completable without Umbrella
if world.multiworld.UmbrellaLogic[world.player].value > 0 \
and (candidate.name == "Heating Up Mafia Town" or candidate.name == "Queen Vanessa's Manor"):
Expand All @@ -495,6 +565,12 @@ def randomize_act_entrances(world: World):
has_guaranteed = True
break

if region.name in world.multiworld.ActPlando[world.player].keys() and is_valid_plando(world, region.name):
candidate_list.clear()
candidate_list.append(
world.multiworld.get_region(world.multiworld.ActPlando[world.player].get(region.name), world.player))
break

# Already mapped onto something else
if candidate in shuffled_list:
continue
Expand All @@ -513,27 +589,30 @@ def randomize_act_entrances(world: World):
or region.name not in purple_time_rifts and candidate.name in purple_time_rifts:
continue

# Don't map Alpine to its own finale
if region.name == "The Illness has Spread" and candidate.name == "Alpine Free Roam":
continue

# Ditto for Metro
if region.name == "Rush Hour" and candidate.name == "Nyakuza Free Roam":
if region.name in blacklisted_combos.keys() and candidate.name in blacklisted_combos[region.name]:
continue

# CTR entrance and Tour aren't a finale, but have a fuck ton of unlock requirements
if world.multiworld.NoFreeRoamFinale[world.player].value > 0 and "Free Roam" in candidate.name:
if region.name in chapter_finales or region.name == "Cheating the Race" \
or world.multiworld.EndGoal[world.player].value == 1 and region.name == "Time Rift - Tour":
if world.multiworld.FinaleShuffle[world.player].value > 0 and region.name in chapter_finales:
if candidate.name not in chapter_finales:
continue

if region.name in rift_access_regions and candidate.name in rift_access_regions[region.name]:
continue

candidate_list.append(candidate)

candidate: Region = candidate_list[world.multiworld.random.randint(0, len(candidate_list)-1)]
candidate: Region
if len(candidate_list) > 0:
candidate = candidate_list[world.multiworld.random.randint(0, len(candidate_list)-1)]
else:
# plando can still break certain rules, so acts may not always end up shuffled.
for c in region_list:
if c not in shuffled_list:
candidate = c
break

shuffled_list.append(candidate)
# print(region, candidate)

# Vanilla
if candidate.name == region.name:
Expand Down Expand Up @@ -588,21 +667,17 @@ def get_act_regions(world: World) -> typing.List[Region]:


def is_act_blacklisted(world: World, name: str) -> bool:
if name == "The Finale":
return world.multiworld.EndGoal[world.player].value == 1
plando: bool = name in world.multiworld.ActPlando[world.player].keys() \
or name in world.multiworld.ActPlando[world.player].values()

if name == "Alpine Free Roam":
return world.multiworld.VanillaAlpine[world.player].value > 0

if name == "The Illness has Spread":
return world.multiworld.VanillaAlpine[world.player].value == 2

if name == "Nyakuza Free Roam":
return world.multiworld.VanillaMetro[world.player].value > 0
if name == "The Finale":
return not plando and world.multiworld.EndGoal[world.player].value == 1

if name == "Rush Hour":
return world.multiworld.EndGoal[world.player].value == 2 \
or world.multiworld.VanillaMetro[world.player].value == 2
return not plando and world.multiworld.EndGoal[world.player].value == 2

if name == "Time Rift - Tour":
return world.multiworld.ExcludeTour[world.player].value > 0

return name in blacklisted_acts.values()

Expand Down
2 changes: 1 addition & 1 deletion worlds/ahit/Rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def set_rules(world: World):
if data.hit_requirement > 0:
if data.hit_requirement == 1:
add_rule(location, lambda state: can_hit(state, world))
else: # Can bypass with Dweller Mask (dweller bells)
elif data.hit_requirement == 2: # Can bypass with Dweller Mask (dweller bells)
add_rule(location, lambda state: can_hit(state, world) or can_use_hat(state, world, HatType.DWELLER))

if get_difficulty(world) >= 1:
Expand Down

0 comments on commit 215594d

Please sign in to comment.