Archipelago/worlds/smz3/TotalSMZ3/WorldState.py

170 lines
7.3 KiB
Python
Raw Normal View History

2022-08-15 14:48:13 +00:00
from enum import Enum
from typing import List
from copy import copy
2023-04-08 20:52:34 +00:00
from .Patch import DropPrize
from .Region import RewardType
from .Config import OpenTower, GanonVulnerable, OpenTourian
2022-08-15 14:48:13 +00:00
class Medallion(Enum):
Bombos = 0
Ether = 1
Quake = 2
class DropPrizeRecord:
Packs: List[DropPrize]
TreePulls: List[DropPrize]
CrabContinous: DropPrize
CrabFinal: DropPrize
Stun: DropPrize
Fish: DropPrize
def __init__(self, Packs, TreePulls, CrabContinous, CrabFinal, Stun, Fish):
self.Packs = Packs
self.TreePulls = TreePulls
self.CrabContinous = CrabContinous
self.CrabFinal = CrabFinal
self.Stun = Stun
self.Fish = Fish
class WorldState:
Rewards: List[RewardType]
Medallions: List[Medallion]
TowerCrystals: int
GanonCrystals: int
TourianBossTokens: int
DropPrizes: DropPrizeRecord
def __init__(self, config, rnd):
self.Rewards = self.DistributeRewards(rnd)
self.Medallions = self.GenerateMedallions(rnd)
self.TowerCrystals = rnd.randint(0, 7) if config.OpenTower == OpenTower.Random else config.OpenTower.value
self.GanonCrystals = rnd.randint(0, 7) if config.GanonVulnerable == GanonVulnerable.Random else config.GanonVulnerable.value
self.TourianBossTokens = rnd.randint(0, 4) if config.OpenTourian == OpenTourian.Random else config.OpenTourian.value
self.DropPrizes = self.ShuffleDropPrizes(rnd)
@staticmethod
def Generate(config, rnd):
return WorldState(config, rnd)
BaseRewards = [
RewardType.PendantGreen, RewardType.PendantNonGreen, RewardType.PendantNonGreen, RewardType.CrystalRed, RewardType.CrystalRed,
RewardType.CrystalBlue, RewardType.CrystalBlue, RewardType.CrystalBlue, RewardType.CrystalBlue, RewardType.CrystalBlue,
RewardType.AnyBossToken, RewardType.AnyBossToken, RewardType.AnyBossToken, RewardType.AnyBossToken,
]
BossTokens = [
RewardType.BossTokenKraid, RewardType.BossTokenPhantoon, RewardType.BossTokenDraygon, RewardType.BossTokenRidley
]
@staticmethod
def DistributeRewards(rnd):
#// Assign four rewards for SM using a "loot table", randomized result
gen = WorldState.Distribution().Generate(lambda dist: dist.Hit(rnd.randrange(dist.Sum)))
smRewards = [next(gen) for x in range(4)]
#// Exclude the SM rewards to get the Z3 lineup
z3Rewards = WorldState.BaseRewards[:]
for reward in smRewards:
z3Rewards.remove(reward)
rnd.shuffle(z3Rewards)
#// Replace "any token" with random specific tokens
rewards = z3Rewards + smRewards
tokens = WorldState.BossTokens[:]
rnd.shuffle(tokens)
rewards = [tokens.pop() if reward == RewardType.AnyBossToken else reward for reward in rewards]
return rewards
class Distribution:
factor = 3
def __init__(self, distribution = None, boss = None, blue = None, red = None, pend = None, green = None):
self.Boss = 4 * self.factor
self.Blue = 5 * self.factor
self.Red = 2 * self.factor
self.Pend = 2
self.Green = 1
if (distribution is not None):
self = copy(distribution)
if (boss is not None):
self.Boss = boss
if (blue is not None):
self.Blue = blue
if (red is not None):
self.Red = red
if (pend is not None):
self.Pend = pend
if (green is not None):
self.Green = green
@property
def Sum(self):
return self.Boss + self.Blue + self.Red + self.Pend + self.Green
def Hit(self, p):
p -= self.Boss
if (p < 0): return (RewardType.AnyBossToken, WorldState.Distribution(self, boss = self.Boss - WorldState.Distribution.factor))
p -= self.Blue
if (p - self.Blue < 0): return (RewardType.CrystalBlue, WorldState.Distribution(self, blue = self.Blue - WorldState.Distribution.factor))
p -= self.Red
if (p - self.Red < 0): return (RewardType.CrystalRed, WorldState.Distribution(self, red = self.Red - WorldState.Distribution.factor))
p -= self.Pend
if (p - self.Pend < 0): return (RewardType.PendantNonGreen, WorldState.Distribution(self, pend = self.Pend - 1))
return (RewardType.PendantGreen, WorldState.Distribution(self, green = self.Green - 1))
def Generate(self, func):
result = None
while (True):
(result, newSelf) = func(self)
self.Boss = newSelf.Boss
self.Blue = newSelf.Blue
self.Red = newSelf.Red
self.Pend = newSelf.Pend
self.Green = newSelf.Green
yield result
@staticmethod
def GenerateMedallions(rnd):
return [
Medallion(rnd.randrange(3)),
Medallion(rnd.randrange(3)),
]
BaseDropPrizes = [
DropPrize.Heart, DropPrize.Heart, DropPrize.Heart, DropPrize.Heart, DropPrize.Green, DropPrize.Heart, DropPrize.Heart, DropPrize.Green, #// pack 1
DropPrize.Blue, DropPrize.Green, DropPrize.Blue, DropPrize.Red, DropPrize.Blue, DropPrize.Green, DropPrize.Blue, DropPrize.Blue, #// pack 2
DropPrize.FullMagic, DropPrize.Magic, DropPrize.Magic, DropPrize.Blue, DropPrize.FullMagic, DropPrize.Magic, DropPrize.Heart, DropPrize.Magic, #// pack 3
DropPrize.Bomb1, DropPrize.Bomb1, DropPrize.Bomb1, DropPrize.Bomb4, DropPrize.Bomb1, DropPrize.Bomb1, DropPrize.Bomb8, DropPrize.Bomb1, #// pack 4
DropPrize.Arrow5, DropPrize.Heart, DropPrize.Arrow5, DropPrize.Arrow10, DropPrize.Arrow5, DropPrize.Heart, DropPrize.Arrow5, DropPrize.Arrow10,#// pack 5
DropPrize.Magic, DropPrize.Green, DropPrize.Heart, DropPrize.Arrow5, DropPrize.Magic, DropPrize.Bomb1, DropPrize.Green, DropPrize.Heart, #// pack 6
DropPrize.Heart, DropPrize.Fairy, DropPrize.FullMagic, DropPrize.Red, DropPrize.Bomb8, DropPrize.Heart, DropPrize.Red, DropPrize.Arrow10, #// pack 7
DropPrize.Green, DropPrize.Blue, DropPrize.Red,#// from pull trees
DropPrize.Green, DropPrize.Red,#// from prize crab
DropPrize.Green, #// stunned prize
DropPrize.Red,#// saved fish prize
]
@staticmethod
def ShuffleDropPrizes(rnd):
nrPackDrops = 8 * 7
nrTreePullDrops = 3
prizes = WorldState.BaseDropPrizes[:]
rnd.shuffle(prizes)
(packs, prizes) = (prizes[:nrPackDrops], prizes[nrPackDrops:])
(treePulls, prizes) = (prizes[:nrTreePullDrops], prizes[nrTreePullDrops:])
(crabContinous, crabFinalDrop, prizes) = (prizes[0], prizes[1], prizes[2:])
(stun, prizes) = (prizes[0], prizes[1:])
fish = prizes[0]
return DropPrizeRecord(packs, treePulls, crabContinous, crabFinalDrop, stun, fish)
@staticmethod
def SplitOff(source, count):
return (source[:count], source[count:])