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
128 lines
6.9 KiB
Python
128 lines
6.9 KiB
Python
"""Select Coin Location selection."""
|
|
|
|
import js
|
|
import randomizer.CollectibleLogicFiles.AngryAztec
|
|
import randomizer.CollectibleLogicFiles.CreepyCastle
|
|
import randomizer.CollectibleLogicFiles.CrystalCaves
|
|
import randomizer.CollectibleLogicFiles.DKIsles
|
|
import randomizer.CollectibleLogicFiles.FranticFactory
|
|
import randomizer.CollectibleLogicFiles.FungiForest
|
|
import randomizer.CollectibleLogicFiles.GloomyGalleon
|
|
import randomizer.CollectibleLogicFiles.JungleJapes
|
|
import randomizer.Fill as Fill
|
|
import randomizer.Lists.Exceptions as Ex
|
|
from randomizer.Enums.Collectibles import Collectibles
|
|
from randomizer.Enums.Kongs import Kongs
|
|
from randomizer.Enums.Levels import Levels
|
|
from randomizer.Lists.BananaCoinLocations import BananaCoinGroupList
|
|
from randomizer.LogicClasses import Collectible
|
|
|
|
KONG_COIN_REQUIREMENT = 100
|
|
KONG_COIN_CAP = 125 # Can never exceed 175 due to overflow if you collect over 255 coins
|
|
|
|
level_data = {
|
|
Levels.DKIsles: randomizer.CollectibleLogicFiles.DKIsles.LogicRegions,
|
|
Levels.JungleJapes: randomizer.CollectibleLogicFiles.JungleJapes.LogicRegions,
|
|
Levels.AngryAztec: randomizer.CollectibleLogicFiles.AngryAztec.LogicRegions,
|
|
Levels.FranticFactory: randomizer.CollectibleLogicFiles.FranticFactory.LogicRegions,
|
|
Levels.GloomyGalleon: randomizer.CollectibleLogicFiles.GloomyGalleon.LogicRegions,
|
|
Levels.FungiForest: randomizer.CollectibleLogicFiles.FungiForest.LogicRegions,
|
|
Levels.CrystalCaves: randomizer.CollectibleLogicFiles.CrystalCaves.LogicRegions,
|
|
Levels.CreepyCastle: randomizer.CollectibleLogicFiles.CreepyCastle.LogicRegions,
|
|
Levels.DKIsles: randomizer.CollectibleLogicFiles.DKIsles.LogicRegions,
|
|
}
|
|
|
|
|
|
def getCoinRequirement(random) -> int:
|
|
"""Get requirement for a kong's coin amount."""
|
|
return int(random.randint(KONG_COIN_REQUIREMENT, KONG_COIN_CAP) / 8)
|
|
|
|
|
|
def ShuffleCoins(spoiler):
|
|
"""Shuffle Coins selected from location files."""
|
|
retries = 0
|
|
while True:
|
|
try:
|
|
total_coins = 0
|
|
coin_data = []
|
|
# First, remove all placed coins (excl. Rabbit Race R1)
|
|
for region_id in spoiler.CollectibleRegions.keys():
|
|
spoiler.CollectibleRegions[region_id] = [collectible for collectible in spoiler.CollectibleRegions[region_id] if collectible.type != Collectibles.coin or collectible.locked]
|
|
for level_index, level in enumerate(level_data):
|
|
level_placement = []
|
|
global_divisor = 7 - level_index
|
|
kong_specific_left = {
|
|
Kongs.donkey: getCoinRequirement(spoiler.settings.random),
|
|
Kongs.diddy: getCoinRequirement(spoiler.settings.random),
|
|
Kongs.lanky: getCoinRequirement(spoiler.settings.random),
|
|
Kongs.tiny: getCoinRequirement(spoiler.settings.random),
|
|
Kongs.chunky: getCoinRequirement(spoiler.settings.random),
|
|
}
|
|
coins_left = (KONG_COIN_CAP * 5) - total_coins
|
|
coins_lower = max(int(coins_left / (8 - level_index)) - 10, 0)
|
|
if global_divisor == 0:
|
|
coins_upper = min(coins_left, int((5 * ((5 * KONG_COIN_CAP) - total_coins) - sum(kong_specific_left)) / 4)) # Places a hard cap of 1127 total singles+bunches
|
|
else:
|
|
coins_upper = min(int(coins_left / (8 - level_index)) + 10, int(coins_left / global_divisor))
|
|
groupIds = list(range(1, len(BananaCoinGroupList[level]) + 1))
|
|
spoiler.settings.random.shuffle(groupIds)
|
|
selected_coin_count = spoiler.settings.random.randint(min(coins_lower, coins_upper), max(coins_lower, coins_upper))
|
|
placed_coins = 0
|
|
for groupId in groupIds:
|
|
group_weight = 0
|
|
coin_groups = [group for group in BananaCoinGroupList[level] if group.group == groupId]
|
|
coin_kongs = list(kong_specific_left.keys())
|
|
for group in coin_groups:
|
|
coin_kongs = list(set(coin_kongs) & set(group.kongs.copy()))
|
|
group_weight = len(group.locations)
|
|
if len(coin_kongs) > 0 and (selected_coin_count >= placed_coins + group_weight):
|
|
selected_kong = spoiler.settings.random.choice(coin_kongs)
|
|
kong_specific_left[selected_kong] -= group_weight # Remove Coins for kong
|
|
# When a kong goes under/equal to 0 remaining in this level, we no longer need to consider it
|
|
if kong_specific_left[selected_kong] <= 0:
|
|
del kong_specific_left[selected_kong]
|
|
for group in coin_groups:
|
|
# Calculate the number of coins we have to place by lesser group so different coins in the same group can have different logic
|
|
coins_in_group = len(group.locations)
|
|
if coins_in_group > 0:
|
|
if group.region not in spoiler.CollectibleRegions:
|
|
spoiler.CollectibleRegions[group.region] = []
|
|
spoiler.CollectibleRegions[group.region].append(
|
|
Collectible(
|
|
Collectibles.coin,
|
|
selected_kong,
|
|
group.logic,
|
|
None,
|
|
coins_in_group,
|
|
name=group.name,
|
|
)
|
|
)
|
|
level_placement.append(
|
|
{
|
|
"group": group.group,
|
|
"name": group.name,
|
|
"kong": selected_kong,
|
|
"level": level,
|
|
"map": group.map,
|
|
"locations": group.locations,
|
|
}
|
|
)
|
|
placed_coins += group_weight
|
|
# If all kongs have 0 unplaced, we're done here
|
|
if len(kong_specific_left.keys()) == 0:
|
|
break
|
|
|
|
# Placement is valid
|
|
coin_data.extend(level_placement.copy())
|
|
spoiler.Reset()
|
|
if not Fill.VerifyWorld(spoiler):
|
|
raise Ex.CoinFillFailureException
|
|
spoiler.coin_placements = coin_data
|
|
return
|
|
except Ex.CoinFillFailureException:
|
|
if retries >= 10:
|
|
js.postMessage("Coin Randomizer failed to fill. REPORT THIS TO THE DEVS!!")
|
|
raise Ex.CoinFillFailureException
|
|
retries += 1
|
|
js.postMessage("Coin Randomizer failed to fill. Tries: " + str(retries))
|