forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
204 lines
9.5 KiB
Python
204 lines
9.5 KiB
Python
"""Shuffle Dirt Patch Locations."""
|
|
|
|
from randomizer.Enums.Plandomizer import PlandoItems
|
|
from randomizer.Lists import Exceptions
|
|
|
|
import randomizer.LogicFiles.AngryAztec
|
|
import randomizer.LogicFiles.CreepyCastle
|
|
import randomizer.LogicFiles.CrystalCaves
|
|
import randomizer.LogicFiles.DKIsles
|
|
import randomizer.LogicFiles.FranticFactory
|
|
import randomizer.LogicFiles.FungiForest
|
|
import randomizer.LogicFiles.GloomyGalleon
|
|
import randomizer.LogicFiles.JungleJapes
|
|
from randomizer.Enums.Levels import Levels
|
|
from randomizer.Enums.Locations import Locations
|
|
from randomizer.Lists.CustomLocations import CustomLocation, CustomLocations, LocationTypes
|
|
from randomizer.LogicClasses import LocationLogic
|
|
|
|
|
|
def addPatch(spoiler, patch: CustomLocation, enum_val: int, name: str, level: Levels):
|
|
"""Add patch to relevant Logic Region."""
|
|
level_to_name = {
|
|
Levels.DKIsles: "Isles",
|
|
Levels.JungleJapes: "Japes",
|
|
Levels.AngryAztec: "Aztec",
|
|
Levels.FranticFactory: "Factory",
|
|
Levels.GloomyGalleon: "Galleon",
|
|
Levels.FungiForest: "Forest",
|
|
Levels.CrystalCaves: "Caves",
|
|
Levels.CreepyCastle: "Castle",
|
|
}
|
|
spoiler.RegionList[patch.logic_region].locations.append(LocationLogic(enum_val, patch.logic))
|
|
spoiler.LocationList[enum_val].name = f"{level_to_name[level]} Dirt: {name}"
|
|
spoiler.LocationList[enum_val].default_mapid_data[0].map = patch.map
|
|
spoiler.LocationList[enum_val].level = level
|
|
|
|
|
|
def removePatches(spoiler):
|
|
"""Remove all patches from Logic regions."""
|
|
level_logic_regions = [
|
|
randomizer.LogicFiles.DKIsles.LogicRegions,
|
|
randomizer.LogicFiles.JungleJapes.LogicRegions,
|
|
randomizer.LogicFiles.AngryAztec.LogicRegions,
|
|
randomizer.LogicFiles.FranticFactory.LogicRegions,
|
|
randomizer.LogicFiles.GloomyGalleon.LogicRegions,
|
|
randomizer.LogicFiles.FungiForest.LogicRegions,
|
|
randomizer.LogicFiles.CrystalCaves.LogicRegions,
|
|
randomizer.LogicFiles.CreepyCastle.LogicRegions,
|
|
]
|
|
for level in level_logic_regions:
|
|
for region in level:
|
|
region_data = spoiler.RegionList[region]
|
|
region_data.locations = [x for x in region_data.locations if x.id < Locations.RainbowCoin_Location00 or x.id > Locations.RainbowCoin_Location15]
|
|
|
|
|
|
def fillPlandoDict(plando_dict: dict, plando_input):
|
|
"""Fill the plando_dict variable, using input from the plandomizer_dict."""
|
|
for patch in plando_input:
|
|
if patch["level"] != -1:
|
|
plando_dict[patch["level"]].append(patch["location"])
|
|
|
|
|
|
def getPlandoDirtDistribution(random, plando_dict: dict):
|
|
"""Adapt the dirt patch balance to the user's plandomizer input."""
|
|
distribution = []
|
|
for level in plando_dict.keys():
|
|
distribution.append(len(plando_dict[level]))
|
|
running_total = sum(distribution)
|
|
if running_total < 16:
|
|
# Make sure as many levels as possible have 1+ dirt patch
|
|
for level in range(len(distribution)):
|
|
if distribution[level] < 1:
|
|
distribution[level] += 1
|
|
running_total += 1
|
|
if running_total >= 16:
|
|
break
|
|
# Make sure the amount of levels with 2+ dirt patches is as close to 6 (including Isles) as possible
|
|
if running_total < 16:
|
|
level_priority = [0]
|
|
random_levels = list(range(1, 8))
|
|
random.shuffle(random_levels)
|
|
level_priority.extend(random_levels)
|
|
amount_of_levels = 6
|
|
for level in range(len(distribution)):
|
|
if distribution[level_priority[level]] < 2:
|
|
distribution[level_priority[level]] += 1
|
|
running_total += 1
|
|
amount_of_levels -= 1
|
|
if running_total >= 16 or amount_of_levels <= 0:
|
|
break
|
|
# Give the rest to DK Isles
|
|
if running_total < 16:
|
|
distribution[0] += 16 - running_total
|
|
return distribution
|
|
|
|
|
|
def ShufflePatches(spoiler, human_spoiler):
|
|
"""Shuffle Dirt Patch Locations."""
|
|
removePatches(spoiler)
|
|
spoiler.dirt_patch_placement = []
|
|
total_dirt_patch_list = {
|
|
Levels.DKIsles: [],
|
|
Levels.JungleJapes: [],
|
|
Levels.AngryAztec: [],
|
|
Levels.FranticFactory: [],
|
|
Levels.GloomyGalleon: [],
|
|
Levels.FungiForest: [],
|
|
Levels.CrystalCaves: [],
|
|
Levels.CreepyCastle: [],
|
|
}
|
|
for key in total_dirt_patch_list:
|
|
human_spoiler[key.name] = [] # Ensure order
|
|
|
|
plando_dict = {
|
|
Levels.DKIsles: [],
|
|
Levels.JungleJapes: [],
|
|
Levels.AngryAztec: [],
|
|
Levels.FranticFactory: [],
|
|
Levels.GloomyGalleon: [],
|
|
Levels.FungiForest: [],
|
|
Levels.CrystalCaves: [],
|
|
Levels.CreepyCastle: [],
|
|
}
|
|
if spoiler.settings.enable_plandomizer and spoiler.settings.plandomizer_dict["plando_dirt_patches"] != []:
|
|
fillPlandoDict(plando_dict, spoiler.settings.plandomizer_dict["plando_dirt_patches"])
|
|
|
|
for key in total_dirt_patch_list.keys():
|
|
for SingleDirtPatchLocation in CustomLocations[key]:
|
|
if SingleDirtPatchLocation.is_fungi_hidden_patch or SingleDirtPatchLocation.isValidLocation(LocationTypes.DirtPatch):
|
|
SingleDirtPatchLocation.setCustomLocation(False)
|
|
if not spoiler.settings.enable_plandomizer or (SingleDirtPatchLocation.name not in spoiler.settings.plandomizer_dict["reserved_custom_locations"][key]):
|
|
total_dirt_patch_list[key].append(SingleDirtPatchLocation)
|
|
|
|
# Make sure plandomized Dirt Patches are handled first
|
|
if spoiler.settings.enable_plandomizer and spoiler.settings.plandomizer_dict["plando_dirt_patches"] != []:
|
|
distribution = getPlandoDirtDistribution(spoiler.settings.random, plando_dict)
|
|
count = 0
|
|
for level in plando_dict.keys():
|
|
area_dirt = total_dirt_patch_list[level]
|
|
select_random_dirt_from_area(area_dirt, distribution[count], level, spoiler, human_spoiler, plando_dict)
|
|
del total_dirt_patch_list[level]
|
|
count += 1
|
|
else:
|
|
select_random_dirt_from_area(total_dirt_patch_list[Levels.DKIsles], 4, Levels.DKIsles, spoiler, human_spoiler, plando_dict)
|
|
del total_dirt_patch_list[Levels.DKIsles]
|
|
|
|
for SingleDirtPatchLocation in range(5):
|
|
area_key = spoiler.settings.random.choice(list(total_dirt_patch_list.keys()))
|
|
area_dirt = total_dirt_patch_list[area_key]
|
|
select_random_dirt_from_area(area_dirt, 2, area_key, spoiler, human_spoiler, plando_dict)
|
|
del total_dirt_patch_list[area_key]
|
|
|
|
for area_key in total_dirt_patch_list.keys():
|
|
area_dirt = total_dirt_patch_list[area_key]
|
|
select_random_dirt_from_area(area_dirt, 1, area_key, spoiler, human_spoiler, plando_dict)
|
|
|
|
# Create the locations for dirt patches
|
|
sorted_patches = spoiler.dirt_patch_placement.copy()
|
|
sorted_patches = sorted(sorted_patches, key=lambda d: d["score"])
|
|
for patch_index, patch in enumerate(sorted_patches):
|
|
patch["enum"] = Locations.RainbowCoin_Location00 + patch_index
|
|
addPatch(spoiler, patch["patch"], patch["enum"], patch["name"], patch["level"])
|
|
patch["patch"] = None
|
|
# Resolve location-item combinations for plando
|
|
if spoiler.settings.enable_plandomizer and spoiler.settings.plandomizer_dict["plando_dirt_patches"] != []:
|
|
for item_placement in spoiler.settings.plandomizer_dict["plando_dirt_patches"]:
|
|
for patch_index, patch in enumerate(sorted_patches):
|
|
if item_placement["location"] == patch["name"] and item_placement["level"] == patch["level"] and item_placement["reward"] != -1:
|
|
spoiler.settings.plandomizer_dict["locations"][patch["enum"]] = item_placement["reward"]
|
|
return human_spoiler.copy()
|
|
|
|
|
|
def select_random_dirt_from_area(area_dirt, amount, level, spoiler, human_spoiler, plando_input):
|
|
"""Select <amount> random dirt patches from <area_dirt>, which is a list of dirt patches. Makes sure max 1 dirt patch per group is selected."""
|
|
human_spoiler[level.name] = []
|
|
for iterations in range(amount):
|
|
allow_same_group_dirt = False
|
|
selected_patch = spoiler.settings.random.choice(area_dirt) # selects a random patch from the list
|
|
selected_patch_name = selected_patch.name
|
|
# Give plandomizer an opportunity to get the final say
|
|
if spoiler.settings.enable_plandomizer and spoiler.settings.plandomizer_dict["plando_dirt_patches"] != []:
|
|
if len(plando_input[level]) > 1:
|
|
allow_same_group_dirt = True
|
|
if len(plando_input[level]) > iterations:
|
|
selected_patch_name = plando_input[level][iterations]
|
|
for patch in CustomLocations[level]: # enables the selected patch
|
|
if patch.name == selected_patch_name:
|
|
patch.setCustomLocation(True)
|
|
human_spoiler[level.name].append(patch.name)
|
|
local_map_index = len([x for x in spoiler.dirt_patch_placement if x["map"] == patch.map])
|
|
spoiler.dirt_patch_placement.append(
|
|
{
|
|
"name": patch.name,
|
|
"map": patch.map,
|
|
"patch": patch,
|
|
"level": level,
|
|
"score": (patch.map * 100) + local_map_index,
|
|
}
|
|
)
|
|
area_dirt.remove(selected_patch)
|
|
break
|
|
if amount > 1 and not allow_same_group_dirt: # if multiple patches are picked, remove patches from the same group, prevent them from being picked
|
|
area_dirt = [dirt for dirt in area_dirt if dirt.group != selected_patch.group]
|