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
794 lines
31 KiB
Python
794 lines
31 KiB
Python
"""Contains functions related to setting up the pool of shuffled items."""
|
|
|
|
import itertools
|
|
|
|
from randomizer.Enums.Events import Events
|
|
import randomizer.Enums.Kongs as KongObject
|
|
from randomizer.Enums.Items import Items
|
|
from randomizer.Enums.Locations import Locations
|
|
from randomizer.Enums.Plandomizer import GetItemsFromPlandoItem, PlandoItems
|
|
from randomizer.Enums.Settings import (
|
|
ClimbingStatus,
|
|
HardModeSelected,
|
|
MoveRando,
|
|
ShockwaveStatus,
|
|
ShuffleLoadingZones,
|
|
TrainingBarrels,
|
|
CBRando,
|
|
)
|
|
from randomizer.Enums.Types import Types
|
|
from randomizer.Enums.Levels import Levels
|
|
from randomizer.Lists.Item import ItemFromKong
|
|
from randomizer.Lists.LevelInfo import LevelInfoList
|
|
from randomizer.Lists.ShufflableExit import ShufflableExits
|
|
from randomizer.Patching.Library.Generic import getIceTrapCount, IsItemSelected
|
|
from randomizer.ShuffleBosses import PlandoBosses
|
|
|
|
|
|
def getHelmKey(settings) -> Items:
|
|
"""Get the item that will be placed in the final room in Helm."""
|
|
key_item = Items.HideoutHelmKey
|
|
if settings.shuffle_loading_zones == ShuffleLoadingZones.levels:
|
|
level_index = None
|
|
key_items = [
|
|
Items.JungleJapesKey,
|
|
Items.AngryAztecKey,
|
|
Items.FranticFactoryKey,
|
|
Items.GloomyGalleonKey,
|
|
Items.FungiForestKey,
|
|
Items.CrystalCavesKey,
|
|
Items.CreepyCastleKey,
|
|
Items.HideoutHelmKey,
|
|
]
|
|
for x in range(8):
|
|
if settings.level_order[x + 1] == Levels.HideoutHelm:
|
|
key_item = key_items[x]
|
|
level_index = x
|
|
break
|
|
if level_index is None:
|
|
raise Exception("Unable to find Helm in the level order to remove Helm Key constant")
|
|
return key_item
|
|
|
|
|
|
def PlaceConstants(spoiler):
|
|
"""Place items which are to be put in a hard-coded location."""
|
|
# Settings-dependent locations
|
|
settings = spoiler.settings
|
|
# Determine what types of locations are being shuffled
|
|
typesOfItemsShuffled = [Types.PreGivenMove] # Your starting moves are always eligible to be shuffled if needed
|
|
if settings.kong_rando:
|
|
typesOfItemsShuffled.append(Types.Kong)
|
|
if settings.move_rando != MoveRando.off:
|
|
typesOfItemsShuffled.append(Types.Shop)
|
|
if settings.training_barrels == TrainingBarrels.shuffled:
|
|
typesOfItemsShuffled.append(Types.TrainingBarrel)
|
|
if settings.climbing_status == ClimbingStatus.shuffled:
|
|
typesOfItemsShuffled.append(Types.Climbing)
|
|
if settings.shuffle_loading_zones == ShuffleLoadingZones.levels:
|
|
typesOfItemsShuffled.append(Types.Key)
|
|
typesOfItemsShuffled.extend(settings.shuffled_location_types)
|
|
# Invert this list because I think it'll be faster
|
|
typesOfItemsNotShuffled = [typ for typ in Types if typ not in typesOfItemsShuffled]
|
|
# Place the default item at every location of a type we're not shuffling
|
|
for location in spoiler.LocationList:
|
|
if spoiler.LocationList[location].type in typesOfItemsNotShuffled:
|
|
spoiler.LocationList[location].PlaceDefaultItem(spoiler)
|
|
# If we're placing a vanilla training move, we have to make the location available
|
|
if spoiler.LocationList[location].type in (Types.TrainingBarrel, Types.Climbing, Types.PreGivenMove):
|
|
spoiler.LocationList[location].inaccessible = False
|
|
else:
|
|
spoiler.LocationList[location].constant = False
|
|
spoiler.LocationList[location].item = None
|
|
# While we're looping here, also reset shops that became inaccessible due to fill lockouts
|
|
if spoiler.LocationList[location].type == Types.Shop:
|
|
spoiler.LocationList[location].inaccessible = spoiler.LocationList[location].smallerShopsInaccessible
|
|
spoiler.LocationList[location].tooExpensiveInaccessible = False
|
|
# Make extra sure the Helm Key is right
|
|
if settings.key_8_helm:
|
|
helm_key = getHelmKey(spoiler.settings)
|
|
if helm_key in KeysToPlace(spoiler.settings, excludeHelmKey=False):
|
|
spoiler.LocationList[Locations.HelmKey].PlaceConstantItem(spoiler, helm_key)
|
|
else:
|
|
spoiler.LocationList[Locations.HelmKey].PlaceConstantItem(spoiler, Items.NoItem)
|
|
# If no CB rando in isles, clear these locations
|
|
if not IsItemSelected(spoiler.settings.cb_rando_enabled, spoiler.settings.cb_rando_list_selected, Levels.DKIsles):
|
|
for x in range(5):
|
|
spoiler.LocationList[Locations.IslesDonkeyMedal + x].PlaceConstantItem(spoiler, Items.NoItem)
|
|
# Handle key placements
|
|
if settings.shuffle_loading_zones == ShuffleLoadingZones.levels and Types.Key not in settings.shuffled_location_types:
|
|
# Place keys in the lobbies they normally belong in
|
|
# Ex. Whatever level is in the Japes lobby entrance will always have the Japes key
|
|
for level in LevelInfoList.values():
|
|
# If level exit isn't shuffled, use vanilla key
|
|
if not ShufflableExits[level.TransitionTo].shuffled:
|
|
spoiler.LocationList[level.KeyLocation].PlaceConstantItem(spoiler, level.KeyItem)
|
|
else:
|
|
# Find the transition this exit is attached to, and use that to get the proper location to place this key
|
|
dest = ShufflableExits[level.TransitionTo].shuffledId
|
|
shuffledTo = [x for x in LevelInfoList.values() if x.TransitionTo == dest][0]
|
|
spoiler.LocationList[shuffledTo.KeyLocation].PlaceConstantItem(spoiler, level.KeyItem)
|
|
# The End of Helm is always a Key in these settings (unless you start with it)
|
|
helm_key = getHelmKey(spoiler.settings)
|
|
if helm_key in KeysToPlace(spoiler.settings, excludeHelmKey=False):
|
|
spoiler.LocationList[Locations.HelmKey].PlaceConstantItem(spoiler, getHelmKey(spoiler.settings))
|
|
else:
|
|
spoiler.LocationList[Locations.HelmKey].PlaceConstantItem(spoiler, Items.NoItem)
|
|
|
|
# Empty out some locations based on the settings
|
|
if settings.starting_kongs_count == 5:
|
|
spoiler.LocationList[Locations.DiddyKong].PlaceConstantItem(spoiler, Items.NoItem)
|
|
spoiler.LocationList[Locations.LankyKong].PlaceConstantItem(spoiler, Items.NoItem)
|
|
spoiler.LocationList[Locations.TinyKong].PlaceConstantItem(spoiler, Items.NoItem)
|
|
spoiler.LocationList[Locations.ChunkyKong].PlaceConstantItem(spoiler, Items.NoItem)
|
|
if settings.start_with_slam:
|
|
spoiler.LocationList[Locations.IslesFirstMove].PlaceConstantItem(spoiler, Items.ProgressiveSlam)
|
|
spoiler.LocationList[Locations.IslesFirstMove].inaccessible = False
|
|
|
|
# Plando items are placed with constants but should not change locations to Constant type
|
|
settings.plandomizer_items_placed = []
|
|
if settings.enable_plandomizer:
|
|
blueprints_planned = []
|
|
for location_id, plando_item in settings.plandomizer_dict["locations"].items():
|
|
if plando_item in [
|
|
PlandoItems.DonkeyBlueprint,
|
|
PlandoItems.DiddyBlueprint,
|
|
PlandoItems.LankyBlueprint,
|
|
PlandoItems.TinyBlueprint,
|
|
PlandoItems.ChunkyBlueprint,
|
|
]:
|
|
item = settings.random.choice([x for x in GetItemsFromPlandoItem(plando_item) if x not in blueprints_planned])
|
|
blueprints_planned.append(item)
|
|
else:
|
|
item = settings.random.choice(GetItemsFromPlandoItem(plando_item))
|
|
spoiler.LocationList[int(location_id)].PlaceItem(spoiler, item)
|
|
settings.plandomizer_items_placed.append(item)
|
|
# If any bosses are plando'd, do it now ahead of placing any items randomly.
|
|
if spoiler.settings.boss_plando:
|
|
# Doing it here has the added benefit of rerolling on fill failure.
|
|
PlandoBosses(spoiler)
|
|
|
|
|
|
def AllItemsUnrestricted(settings):
|
|
"""Return all placeable items regardless of shuffle status."""
|
|
allItems = []
|
|
allItems.extend(Blueprints())
|
|
allItems.extend(GoldenBananaItems())
|
|
allItems.extend(ToughGoldenBananaItems())
|
|
allItems.extend(NintendoCoinItems())
|
|
allItems.extend(RarewareCoinItems())
|
|
allItems.extend(BattleCrownItems())
|
|
allItems.extend(Keys())
|
|
allItems.extend(BananaMedalItems(settings))
|
|
allItems.extend(MiscItemRandoItems())
|
|
allItems.extend(FairyItems())
|
|
allItems.extend(RainbowCoinItems())
|
|
allItems.extend(MelonCrateItems())
|
|
allItems.extend(EnemyItems())
|
|
allItems.extend(FakeItems(settings))
|
|
allItems.extend(JunkItems(settings))
|
|
allItems.extend(DonkeyMoves)
|
|
allItems.extend(DiddyMoves)
|
|
allItems.extend(LankyMoves)
|
|
allItems.extend(TinyMoves)
|
|
allItems.extend(ChunkyMoves)
|
|
allItems.extend(ImportantSharedMoves)
|
|
allItems.extend(JunkSharedMoves)
|
|
allItems.extend(TrainingBarrelAbilities().copy())
|
|
allItems.extend(ClimbingAbilities().copy())
|
|
if settings.shockwave_status == ShockwaveStatus.shuffled_decoupled:
|
|
allItems.append(Items.Camera)
|
|
allItems.append(Items.Shockwave)
|
|
else:
|
|
allItems.append(Items.CameraAndShockwave)
|
|
allItems.extend(Kongs(settings))
|
|
allItems.extend(CrankyItems())
|
|
allItems.extend(FunkyItems())
|
|
allItems.extend(CandyItems())
|
|
allItems.extend(SnideItems())
|
|
return allItems
|
|
|
|
|
|
def AllItems(settings):
|
|
"""Return all shuffled items."""
|
|
allItems = []
|
|
if Types.Blueprint in settings.shuffled_location_types:
|
|
allItems.extend(Blueprints())
|
|
if Types.Banana in settings.shuffled_location_types:
|
|
allItems.extend(GoldenBananaItems())
|
|
if Types.ToughBanana in settings.shuffled_location_types:
|
|
allItems.extend(ToughGoldenBananaItems())
|
|
if Types.NintendoCoin in settings.shuffled_location_types:
|
|
allItems.extend(NintendoCoinItems())
|
|
if Types.RarewareCoin in settings.shuffled_location_types:
|
|
allItems.extend(RarewareCoinItems())
|
|
if Types.Crown in settings.shuffled_location_types:
|
|
allItems.extend(BattleCrownItems())
|
|
if Types.Key in settings.shuffled_location_types:
|
|
allItems.extend(Keys())
|
|
if Types.Medal in settings.shuffled_location_types:
|
|
allItems.extend(BananaMedalItems(settings))
|
|
if Types.Bean in settings.shuffled_location_types: # Could check for pearls as well
|
|
allItems.extend(MiscItemRandoItems())
|
|
if Types.Fairy in settings.shuffled_location_types:
|
|
allItems.extend(FairyItems())
|
|
if Types.RainbowCoin in settings.shuffled_location_types:
|
|
allItems.extend(RainbowCoinItems())
|
|
if Types.CrateItem in settings.shuffled_location_types:
|
|
allItems.extend(MelonCrateItems())
|
|
if Types.Hint in settings.shuffled_location_types:
|
|
allItems.extend(HintItems())
|
|
if Types.Enemies in settings.shuffled_location_types:
|
|
allItems.extend(EnemyItems())
|
|
if Types.Cranky in settings.shuffled_location_types:
|
|
allItems.extend(CrankyItems())
|
|
if Types.Funky in settings.shuffled_location_types:
|
|
allItems.extend(FunkyItems())
|
|
if Types.Candy in settings.shuffled_location_types:
|
|
allItems.extend(CandyItems())
|
|
if Types.Snide in settings.shuffled_location_types:
|
|
allItems.extend(SnideItems())
|
|
if Types.FakeItem in settings.shuffled_location_types:
|
|
allItems.extend(FakeItems(settings))
|
|
if Types.JunkItem in settings.shuffled_location_types:
|
|
allItems.extend(JunkItems(settings))
|
|
if settings.move_rando != MoveRando.off:
|
|
allItems.extend(DonkeyMoves)
|
|
allItems.extend(DiddyMoves)
|
|
allItems.extend(LankyMoves)
|
|
allItems.extend(TinyMoves)
|
|
allItems.extend(ChunkyMoves)
|
|
allItems.extend(ImportantSharedMoves)
|
|
|
|
if settings.training_barrels == TrainingBarrels.shuffled:
|
|
allItems.extend(TrainingBarrelAbilities().copy())
|
|
if settings.climbing_status == ClimbingStatus.shuffled:
|
|
allItems.extend(ClimbingAbilities().copy())
|
|
if settings.shockwave_status == ShockwaveStatus.shuffled_decoupled:
|
|
allItems.append(Items.Camera)
|
|
allItems.append(Items.Shockwave)
|
|
else:
|
|
allItems.append(Items.CameraAndShockwave)
|
|
if settings.kong_rando or Types.Kong in settings.shuffled_location_types:
|
|
allItems.extend(Kongs(settings))
|
|
return allItems
|
|
|
|
|
|
def AllItemsForMovePlacement(settings):
|
|
"""Return all shuffled items we need to assume for move placement."""
|
|
allItems = []
|
|
if Types.Blueprint in settings.shuffled_location_types:
|
|
allItems.extend(Blueprints())
|
|
if Types.Banana in settings.shuffled_location_types:
|
|
allItems.extend(GoldenBananaItems())
|
|
if Types.ToughBanana in settings.shuffled_location_types:
|
|
allItems.extend(ToughGoldenBananaItems())
|
|
if Types.NintendoCoin in settings.shuffled_location_types:
|
|
allItems.extend(NintendoCoinItems())
|
|
if Types.RarewareCoin in settings.shuffled_location_types:
|
|
allItems.extend(RarewareCoinItems())
|
|
if Types.Crown in settings.shuffled_location_types:
|
|
allItems.extend(BattleCrownItems())
|
|
if Types.Key in settings.shuffled_location_types:
|
|
allItems.extend(Keys())
|
|
if Types.Medal in settings.shuffled_location_types:
|
|
allItems.extend(BananaMedalItems(settings))
|
|
if Types.Bean in settings.shuffled_location_types: # Could check for pearls as well
|
|
allItems.extend(MiscItemRandoItems())
|
|
if Types.Fairy in settings.shuffled_location_types:
|
|
allItems.extend(FairyItems())
|
|
if Types.RainbowCoin in settings.shuffled_location_types:
|
|
allItems.extend(RainbowCoinItems())
|
|
if Types.CrateItem in settings.shuffled_location_types:
|
|
allItems.extend(MelonCrateItems())
|
|
if Types.Hint in settings.shuffled_location_types:
|
|
allItems.extend(HintItems())
|
|
if Types.Enemies in settings.shuffled_location_types:
|
|
allItems.extend(EnemyItems())
|
|
if Types.Cranky in settings.shuffled_location_types:
|
|
allItems.extend(CrankyItems())
|
|
if Types.Funky in settings.shuffled_location_types:
|
|
allItems.extend(FunkyItems())
|
|
if Types.Candy in settings.shuffled_location_types:
|
|
allItems.extend(CandyItems())
|
|
if Types.Snide in settings.shuffled_location_types:
|
|
allItems.extend(SnideItems())
|
|
if Types.FakeItem in settings.shuffled_location_types:
|
|
allItems.extend(FakeItems(settings))
|
|
if Types.JunkItem in settings.shuffled_location_types:
|
|
allItems.extend(JunkItems(settings))
|
|
return allItems
|
|
|
|
|
|
def AllKongMoves():
|
|
"""Return all moves."""
|
|
allMoves = []
|
|
allMoves.extend(DonkeyMoves)
|
|
allMoves.extend(DiddyMoves)
|
|
allMoves.extend(LankyMoves)
|
|
allMoves.extend(TinyMoves)
|
|
allMoves.extend(ChunkyMoves)
|
|
allMoves.extend(ImportantSharedMoves)
|
|
return allMoves
|
|
|
|
|
|
def AllMovesForOwnedKongs(kongs):
|
|
"""Return all moves for the given list of Kongs."""
|
|
kongMoves = []
|
|
if KongObject.Kongs.donkey in kongs:
|
|
kongMoves.extend(DonkeyMoves)
|
|
if KongObject.Kongs.diddy in kongs:
|
|
kongMoves.extend(DiddyMoves)
|
|
if KongObject.Kongs.lanky in kongs:
|
|
kongMoves.extend(LankyMoves)
|
|
if KongObject.Kongs.tiny in kongs:
|
|
kongMoves.extend(TinyMoves)
|
|
if KongObject.Kongs.chunky in kongs:
|
|
kongMoves.extend(ChunkyMoves)
|
|
kongMoves.extend(ImportantSharedMoves)
|
|
return kongMoves
|
|
|
|
|
|
def ShockwaveTypeItems(settings):
|
|
"""Return the Shockwave-type items for the given settings."""
|
|
if settings.shockwave_status == ShockwaveStatus.shuffled_decoupled:
|
|
return [Items.Camera, Items.Shockwave]
|
|
else:
|
|
return [Items.CameraAndShockwave]
|
|
|
|
|
|
def Blueprints():
|
|
"""Return all blueprint items."""
|
|
blueprints = [
|
|
Items.DKIslesDonkeyBlueprint,
|
|
Items.DKIslesDiddyBlueprint,
|
|
Items.DKIslesLankyBlueprint,
|
|
Items.DKIslesTinyBlueprint,
|
|
Items.DKIslesChunkyBlueprint,
|
|
Items.JungleJapesDonkeyBlueprint,
|
|
Items.JungleJapesDiddyBlueprint,
|
|
Items.JungleJapesLankyBlueprint,
|
|
Items.JungleJapesTinyBlueprint,
|
|
Items.JungleJapesChunkyBlueprint,
|
|
Items.AngryAztecDonkeyBlueprint,
|
|
Items.AngryAztecDiddyBlueprint,
|
|
Items.AngryAztecLankyBlueprint,
|
|
Items.AngryAztecTinyBlueprint,
|
|
Items.AngryAztecChunkyBlueprint,
|
|
Items.FranticFactoryDonkeyBlueprint,
|
|
Items.FranticFactoryDiddyBlueprint,
|
|
Items.FranticFactoryLankyBlueprint,
|
|
Items.FranticFactoryTinyBlueprint,
|
|
Items.FranticFactoryChunkyBlueprint,
|
|
Items.GloomyGalleonDonkeyBlueprint,
|
|
Items.GloomyGalleonDiddyBlueprint,
|
|
Items.GloomyGalleonLankyBlueprint,
|
|
Items.GloomyGalleonTinyBlueprint,
|
|
Items.GloomyGalleonChunkyBlueprint,
|
|
Items.FungiForestDonkeyBlueprint,
|
|
Items.FungiForestDiddyBlueprint,
|
|
Items.FungiForestLankyBlueprint,
|
|
Items.FungiForestTinyBlueprint,
|
|
Items.FungiForestChunkyBlueprint,
|
|
Items.CrystalCavesDonkeyBlueprint,
|
|
Items.CrystalCavesDiddyBlueprint,
|
|
Items.CrystalCavesLankyBlueprint,
|
|
Items.CrystalCavesTinyBlueprint,
|
|
Items.CrystalCavesChunkyBlueprint,
|
|
Items.CreepyCastleDonkeyBlueprint,
|
|
Items.CreepyCastleDiddyBlueprint,
|
|
Items.CreepyCastleLankyBlueprint,
|
|
Items.CreepyCastleTinyBlueprint,
|
|
Items.CreepyCastleChunkyBlueprint,
|
|
]
|
|
return blueprints
|
|
|
|
|
|
def Keys():
|
|
"""Return all key items."""
|
|
return [
|
|
Items.JungleJapesKey,
|
|
Items.AngryAztecKey,
|
|
Items.FranticFactoryKey,
|
|
Items.GloomyGalleonKey,
|
|
Items.FungiForestKey,
|
|
Items.CrystalCavesKey,
|
|
Items.CreepyCastleKey,
|
|
Items.HideoutHelmKey,
|
|
]
|
|
|
|
|
|
def KeysToPlace(settings, excludeHelmKey=True):
|
|
"""Return all keys that are non-starting keys."""
|
|
keysToPlace = []
|
|
for keyEvent in settings.krool_keys_required:
|
|
if keyEvent == Events.JapesKeyTurnedIn:
|
|
keysToPlace.append(Items.JungleJapesKey)
|
|
elif keyEvent == Events.AztecKeyTurnedIn:
|
|
keysToPlace.append(Items.AngryAztecKey)
|
|
elif keyEvent == Events.FactoryKeyTurnedIn:
|
|
keysToPlace.append(Items.FranticFactoryKey)
|
|
elif keyEvent == Events.GalleonKeyTurnedIn:
|
|
keysToPlace.append(Items.GloomyGalleonKey)
|
|
elif keyEvent == Events.ForestKeyTurnedIn:
|
|
keysToPlace.append(Items.FungiForestKey)
|
|
elif keyEvent == Events.CavesKeyTurnedIn:
|
|
keysToPlace.append(Items.CrystalCavesKey)
|
|
elif keyEvent == Events.CastleKeyTurnedIn:
|
|
keysToPlace.append(Items.CreepyCastleKey)
|
|
elif keyEvent == Events.HelmKeyTurnedIn:
|
|
keysToPlace.append(Items.HideoutHelmKey)
|
|
if settings.key_8_helm and excludeHelmKey:
|
|
key_item = getHelmKey(settings)
|
|
if key_item in keysToPlace:
|
|
keysToPlace.remove(key_item)
|
|
return keysToPlace
|
|
|
|
|
|
def Kongs(settings):
|
|
"""Return Kong items depending on settings."""
|
|
kongs = []
|
|
if settings.starting_kongs_count != 5:
|
|
kongs = [Items.Donkey, Items.Diddy, Items.Lanky, Items.Tiny, Items.Chunky]
|
|
kongs.remove(ItemFromKong(settings.starting_kong))
|
|
return kongs
|
|
|
|
|
|
def GetKongForItem(item):
|
|
"""Return Kong object from kong-type item."""
|
|
if item == Items.Donkey:
|
|
return KongObject.Kongs.donkey
|
|
elif item == Items.Diddy:
|
|
return KongObject.Kongs.diddy
|
|
elif item == Items.Lanky:
|
|
return KongObject.Kongs.lanky
|
|
elif item == Items.Tiny:
|
|
return KongObject.Kongs.tiny
|
|
else:
|
|
return KongObject.Kongs.chunky
|
|
|
|
|
|
def Guns(settings):
|
|
"""Return all gun items."""
|
|
return [Items.Coconut, Items.Peanut, Items.Grape, Items.Feather, Items.Pineapple]
|
|
|
|
|
|
def Instruments(settings):
|
|
"""Return all instrument items."""
|
|
return [Items.Bongos, Items.Guitar, Items.Trombone, Items.Saxophone, Items.Triangle]
|
|
|
|
|
|
def TrainingBarrelAbilities():
|
|
"""Return all training barrel abilities."""
|
|
barrelAbilities = [Items.Vines, Items.Swim, Items.Oranges, Items.Barrels]
|
|
return barrelAbilities
|
|
|
|
|
|
def ClimbingAbilities():
|
|
"""Return all climbing abilities."""
|
|
return [Items.Climbing]
|
|
|
|
|
|
def Upgrades(settings):
|
|
"""Return all upgrade items."""
|
|
upgrades = []
|
|
# Add training barrel items to item pool if shuffled
|
|
if settings.training_barrels == TrainingBarrels.shuffled:
|
|
upgrades.extend(TrainingBarrelAbilities())
|
|
# Add climbing to item pool if shuffled
|
|
if settings.climbing_status == ClimbingStatus.shuffled:
|
|
upgrades.extend(ClimbingAbilities())
|
|
# Add either progressive upgrade items or individual ones depending on settings
|
|
slam_count = 3
|
|
if settings.start_with_slam:
|
|
slam_count = 2
|
|
upgrades.extend(itertools.repeat(Items.ProgressiveSlam, slam_count))
|
|
upgrades.extend(
|
|
[
|
|
Items.BaboonBlast,
|
|
Items.StrongKong,
|
|
Items.GorillaGrab,
|
|
Items.ChimpyCharge,
|
|
Items.RocketbarrelBoost,
|
|
Items.SimianSpring,
|
|
Items.Orangstand,
|
|
Items.BaboonBalloon,
|
|
Items.OrangstandSprint,
|
|
Items.MiniMonkey,
|
|
Items.PonyTailTwirl,
|
|
Items.Monkeyport,
|
|
Items.HunkyChunky,
|
|
Items.PrimatePunch,
|
|
Items.GorillaGone,
|
|
]
|
|
)
|
|
upgrades.append(Items.HomingAmmo)
|
|
upgrades.append(Items.SniperSight)
|
|
upgrades.extend(itertools.repeat(Items.ProgressiveAmmoBelt, 2))
|
|
upgrades.extend(itertools.repeat(Items.ProgressiveInstrumentUpgrade, 3))
|
|
if settings.shockwave_status != ShockwaveStatus.start_with:
|
|
if settings.shockwave_status == ShockwaveStatus.vanilla or settings.shockwave_status == ShockwaveStatus.shuffled:
|
|
upgrades.append(Items.CameraAndShockwave)
|
|
else:
|
|
upgrades.append(Items.Camera)
|
|
upgrades.append(Items.Shockwave)
|
|
|
|
return upgrades
|
|
|
|
|
|
def HighPriorityItems(settings):
|
|
"""Get all items which are of high importance logically."""
|
|
itemPool = []
|
|
itemPool.extend(Kongs(settings))
|
|
itemPool.extend(Guns(settings))
|
|
itemPool.extend(Instruments(settings))
|
|
itemPool.extend(Upgrades(settings))
|
|
itemPool.extend(CrankyItems())
|
|
itemPool.extend(CandyItems())
|
|
itemPool.extend(FunkyItems())
|
|
itemPool.extend(SnideItems())
|
|
return itemPool
|
|
|
|
|
|
def NintendoCoinItems():
|
|
"""Return Nintendo Coin."""
|
|
return [Items.NintendoCoin]
|
|
|
|
|
|
def RarewareCoinItems():
|
|
"""Return Rareware Coin."""
|
|
return [Items.RarewareCoin]
|
|
|
|
|
|
TOUGH_BANANA_COUNT = 13
|
|
|
|
|
|
def GoldenBananaItems():
|
|
"""Return a list of GBs to be placed."""
|
|
itemPool = []
|
|
itemPool.extend(itertools.repeat(Items.GoldenBanana, 161 - TOUGH_BANANA_COUNT)) # 40 Blueprint GBs are always already placed (see Types.BlueprintBanana)
|
|
return itemPool
|
|
|
|
|
|
def ToughGoldenBananaItems():
|
|
"""Return a list of GBs to be placed."""
|
|
itemPool = []
|
|
itemPool.extend(itertools.repeat(Items.GoldenBanana, TOUGH_BANANA_COUNT))
|
|
return itemPool
|
|
|
|
|
|
def BananaMedalItems(settings):
|
|
"""Return a list of Banana Medals to be placed."""
|
|
itemPool = []
|
|
count = 40
|
|
if IsItemSelected(settings.cb_rando_enabled, settings.cb_rando_list_selected, Levels.DKIsles):
|
|
count = 45
|
|
itemPool.extend(itertools.repeat(Items.BananaMedal, count))
|
|
return itemPool
|
|
|
|
|
|
def BattleCrownItems():
|
|
"""Return a list of Crowns to be placed."""
|
|
itemPool = []
|
|
itemPool.extend(itertools.repeat(Items.BattleCrown, 10))
|
|
return itemPool
|
|
|
|
|
|
def MiscItemRandoItems():
|
|
"""Return a list of Items that are classed as miscellaneous."""
|
|
itemPool = []
|
|
itemPool.append(Items.Bean)
|
|
itemPool.extend(itertools.repeat(Items.Pearl, 5))
|
|
return itemPool
|
|
|
|
|
|
def RainbowCoinItems():
|
|
"""Return a list of Rainbow Coins to be placed."""
|
|
itemPool = []
|
|
itemPool.extend(itertools.repeat(Items.RainbowCoin, 16))
|
|
return itemPool
|
|
|
|
|
|
def MelonCrateItems():
|
|
"""Return a list of No Items to be placed."""
|
|
return []
|
|
|
|
|
|
def EnemyItems():
|
|
"""Return a list of No Items to be placed."""
|
|
return []
|
|
|
|
|
|
def FairyItems():
|
|
"""Return a list of Fairies to be placed."""
|
|
itemPool = []
|
|
itemPool.extend(itertools.repeat(Items.BananaFairy, 20))
|
|
return itemPool
|
|
|
|
|
|
def FakeItems(settings):
|
|
"""Return a list of Fake Items to be placed."""
|
|
itemPool = []
|
|
total_count = getIceTrapCount(settings)
|
|
slow_count = int(total_count / 3)
|
|
reverse_count = int(total_count / 3)
|
|
bubble_count = total_count - (slow_count + reverse_count)
|
|
itemPool.extend(itertools.repeat(Items.IceTrapBubble, bubble_count))
|
|
itemPool.extend(itertools.repeat(Items.IceTrapReverse, reverse_count))
|
|
itemPool.extend(itertools.repeat(Items.IceTrapSlow, slow_count))
|
|
return itemPool
|
|
|
|
|
|
def CrankyItems():
|
|
"""Return a list of Cranky shop owners to be placed."""
|
|
return [Items.Cranky]
|
|
|
|
|
|
def FunkyItems():
|
|
"""Return a list of Funky shop owners to be placed."""
|
|
return [Items.Funky]
|
|
|
|
|
|
def CandyItems():
|
|
"""Return a list of Candy shop owners to be placed."""
|
|
return [Items.Candy]
|
|
|
|
|
|
def SnideItems():
|
|
"""Return a list of Snide shop owners to be placed."""
|
|
return [Items.Snide]
|
|
|
|
|
|
def HintItems():
|
|
"""Return a list of Hint Items to be placed."""
|
|
return [
|
|
Items.JapesDonkeyHint,
|
|
Items.JapesDiddyHint,
|
|
Items.JapesLankyHint,
|
|
Items.JapesTinyHint,
|
|
Items.JapesChunkyHint,
|
|
Items.AztecDonkeyHint,
|
|
Items.AztecDiddyHint,
|
|
Items.AztecLankyHint,
|
|
Items.AztecTinyHint,
|
|
Items.AztecChunkyHint,
|
|
Items.FactoryDonkeyHint,
|
|
Items.FactoryDiddyHint,
|
|
Items.FactoryLankyHint,
|
|
Items.FactoryTinyHint,
|
|
Items.FactoryChunkyHint,
|
|
Items.GalleonDonkeyHint,
|
|
Items.GalleonDiddyHint,
|
|
Items.GalleonLankyHint,
|
|
Items.GalleonTinyHint,
|
|
Items.GalleonChunkyHint,
|
|
Items.ForestDonkeyHint,
|
|
Items.ForestDiddyHint,
|
|
Items.ForestLankyHint,
|
|
Items.ForestTinyHint,
|
|
Items.ForestChunkyHint,
|
|
Items.CavesDonkeyHint,
|
|
Items.CavesDiddyHint,
|
|
Items.CavesLankyHint,
|
|
Items.CavesTinyHint,
|
|
Items.CavesChunkyHint,
|
|
Items.CastleDonkeyHint,
|
|
Items.CastleDiddyHint,
|
|
Items.CastleLankyHint,
|
|
Items.CastleTinyHint,
|
|
Items.CastleChunkyHint,
|
|
]
|
|
|
|
|
|
def JunkItems(settings):
|
|
"""Return a list of Junk Items to be placed."""
|
|
junk_count = min(100, 116 - getIceTrapCount(settings))
|
|
if Types.Enemies in settings.shuffled_location_types:
|
|
junk_count += 427
|
|
itemPool = []
|
|
# items_to_place = (Items.JunkAmmo, Items.JunkCrystal, Items.JunkFilm, Items.JunkMelon, Items.JunkOrange)
|
|
# items_to_place = (Items.JunkAmmo, Items.JunkCrystal, Items.JunkMelon, Items.JunkOrange)
|
|
items_to_place = [Items.JunkMelon]
|
|
lim = int(junk_count / len(items_to_place))
|
|
for item_type in items_to_place:
|
|
itemPool.extend(itertools.repeat(item_type, lim))
|
|
return itemPool
|
|
|
|
|
|
def GetItemsNeedingToBeAssumed(settings, placed_types, placed_items=[]):
|
|
"""Return a list of all items that will be assumed for immediate item placement."""
|
|
itemPool = []
|
|
unplacedTypes = [typ for typ in settings.shuffled_location_types if typ not in placed_types]
|
|
if Types.Banana in unplacedTypes:
|
|
itemPool.extend(GoldenBananaItems())
|
|
if Types.ToughBanana in unplacedTypes:
|
|
itemPool.extend(ToughGoldenBananaItems())
|
|
if Types.Shop in unplacedTypes:
|
|
itemPool.extend(AllKongMoves())
|
|
if Types.Blueprint in unplacedTypes:
|
|
itemPool.extend(Blueprints())
|
|
if Types.Fairy in unplacedTypes:
|
|
itemPool.extend(FairyItems())
|
|
if Types.Key in unplacedTypes:
|
|
itemPool.extend(Keys())
|
|
if Types.Crown in unplacedTypes:
|
|
itemPool.extend(BattleCrownItems())
|
|
if Types.NintendoCoin in unplacedTypes:
|
|
itemPool.extend(NintendoCoinItems())
|
|
if Types.RarewareCoin in unplacedTypes:
|
|
itemPool.extend(RarewareCoinItems())
|
|
if Types.TrainingBarrel in unplacedTypes:
|
|
itemPool.extend(TrainingBarrelAbilities())
|
|
if Types.Climbing in unplacedTypes:
|
|
itemPool.extend(ClimbingAbilities())
|
|
if Types.Kong in unplacedTypes:
|
|
itemPool.extend(Kongs(settings))
|
|
if Types.Medal in unplacedTypes:
|
|
itemPool.extend(BananaMedalItems(settings))
|
|
if Types.Shockwave in unplacedTypes:
|
|
itemPool.extend(ShockwaveTypeItems(settings))
|
|
if Types.Bean in unplacedTypes:
|
|
itemPool.extend(MiscItemRandoItems()) # Covers Bean and Pearls
|
|
if Types.RainbowCoin in unplacedTypes:
|
|
itemPool.extend(RainbowCoinItems())
|
|
if Types.CrateItem in unplacedTypes:
|
|
itemPool.extend(MelonCrateItems())
|
|
if Types.Enemies in unplacedTypes:
|
|
itemPool.extend(EnemyItems())
|
|
if Types.ToughBanana in unplacedTypes:
|
|
itemPool.extend(ToughGoldenBananaItems())
|
|
if Types.Cranky in unplacedTypes:
|
|
itemPool.extend(CrankyItems())
|
|
if Types.Funky in unplacedTypes:
|
|
itemPool.extend(FunkyItems())
|
|
if Types.Candy in unplacedTypes:
|
|
itemPool.extend(CandyItems())
|
|
if Types.Snide in unplacedTypes:
|
|
itemPool.extend(SnideItems())
|
|
# Never logic-affecting items
|
|
# if Types.FakeItem in unplacedTypes:
|
|
# itemPool.extend(FakeItems())
|
|
# if Types.JunkItem in unplacedTypes:
|
|
# itemPool.extend(JunkItems())
|
|
if Types.Hint in unplacedTypes:
|
|
itemPool.extend(HintItems())
|
|
# If shops are not part of the larger item pool and are not placed, we may still need to assume them
|
|
# It is worth noting that TrainingBarrel and Shockwave type items are contingent on Shop type items being in the item rando pool
|
|
if Types.Shop not in settings.shuffled_location_types and Types.Shop not in placed_types and settings.move_rando != MoveRando.off:
|
|
itemPool.extend(AllKongMoves())
|
|
if settings.training_barrels == TrainingBarrels.shuffled:
|
|
itemPool.extend(TrainingBarrelAbilities().copy())
|
|
if settings.climbing_status == ClimbingStatus.shuffled:
|
|
itemPool.extend(ClimbingAbilities().copy())
|
|
# With a list of specifically placed items, we can't assume those
|
|
for item in placed_items:
|
|
if item in itemPool:
|
|
itemPool.remove(item) # Remove one instance of the item (do not filter!)
|
|
# If there is a Key forced into Helm, be sure it's not being assumed
|
|
if settings.key_8_helm or Types.Key not in settings.shuffled_location_types:
|
|
key_forced_into_helm = getHelmKey(settings)
|
|
if key_forced_into_helm in itemPool:
|
|
itemPool.remove(key_forced_into_helm)
|
|
return itemPool
|
|
|
|
|
|
DonkeyMoves = [Items.Coconut, Items.Bongos, Items.BaboonBlast, Items.StrongKong, Items.GorillaGrab]
|
|
DiddyMoves = [Items.Peanut, Items.Guitar, Items.ChimpyCharge, Items.RocketbarrelBoost, Items.SimianSpring]
|
|
LankyMoves = [Items.Grape, Items.Trombone, Items.Orangstand, Items.BaboonBalloon, Items.OrangstandSprint]
|
|
TinyMoves = [Items.Feather, Items.Saxophone, Items.MiniMonkey, Items.PonyTailTwirl, Items.Monkeyport]
|
|
ChunkyMoves = [Items.Pineapple, Items.Triangle, Items.HunkyChunky, Items.PrimatePunch, Items.GorillaGone]
|
|
ImportantSharedMoves = [
|
|
Items.ProgressiveSlam,
|
|
Items.ProgressiveSlam,
|
|
Items.ProgressiveSlam,
|
|
Items.SniperSight,
|
|
Items.HomingAmmo,
|
|
]
|
|
JunkSharedMoves = [
|
|
Items.ProgressiveAmmoBelt,
|
|
Items.ProgressiveAmmoBelt,
|
|
Items.ProgressiveInstrumentUpgrade,
|
|
Items.ProgressiveInstrumentUpgrade,
|
|
Items.ProgressiveInstrumentUpgrade,
|
|
]
|
|
ProgressiveSharedMovesSet = {Items.ProgressiveAmmoBelt, Items.ProgressiveInstrumentUpgrade, Items.ProgressiveSlam}
|