Archipelago/worlds/smz3/TotalSMZ3/WorldState.py

170 lines
7.3 KiB
Python

from enum import Enum
from typing import List
from copy import copy
from .Patch import DropPrize
from .Region import RewardType
from .Config import OpenTower, GanonVulnerable, OpenTourian
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:])