170 lines
7.3 KiB
Python
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:]) |