Super Metroid: Replace random module with world random in variaRandomizer (#4429)

This commit is contained in:
Mysteryem
2025-04-01 17:14:47 +01:00
committed by GitHub
parent 5a6b02dbd3
commit ca08e4b950
16 changed files with 154 additions and 142 deletions

View File

@@ -1,4 +1,3 @@
import random
from ..utils import log
from ..utils.utils import getRangeDict, chooseFromRange
from ..rando.ItemLocContainer import ItemLocation
@@ -23,8 +22,9 @@ class Choice(object):
# simple random choice, that chooses an item first, then a locatio to put it in
class ItemThenLocChoice(Choice):
def __init__(self, restrictions):
def __init__(self, restrictions, random):
super(ItemThenLocChoice, self).__init__(restrictions)
self.random = random
def chooseItemLoc(self, itemLocDict, isProg):
itemList = self.getItemList(itemLocDict)
@@ -49,7 +49,7 @@ class ItemThenLocChoice(Choice):
return self.chooseItemRandom(itemList)
def chooseItemRandom(self, itemList):
return random.choice(itemList)
return self.random.choice(itemList)
def chooseLocation(self, locList, item, isProg):
if len(locList) == 0:
@@ -63,12 +63,12 @@ class ItemThenLocChoice(Choice):
return self.chooseLocationRandom(locList)
def chooseLocationRandom(self, locList):
return random.choice(locList)
return self.random.choice(locList)
# Choice specialization for prog speed based filler
class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
def __init__(self, restrictions, progSpeedParams, distanceProp, services):
super(ItemThenLocChoiceProgSpeed, self).__init__(restrictions)
def __init__(self, restrictions, progSpeedParams, distanceProp, services, random):
super(ItemThenLocChoiceProgSpeed, self).__init__(restrictions, random)
self.progSpeedParams = progSpeedParams
self.distanceProp = distanceProp
self.services = services
@@ -104,7 +104,7 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
if self.restrictions.isLateMorph() and canRollback and len(itemLocDict) == 1:
item, locList = list(itemLocDict.items())[0]
if item.Type == 'Morph':
morphLocs = self.restrictions.lateMorphCheck(container, locList)
morphLocs = self.restrictions.lateMorphCheck(container, locList, self.random)
if morphLocs is not None:
itemLocDict[item] = morphLocs
else:
@@ -115,7 +115,7 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
assert len(locs) == 1 and locs[0].Name == item.Name
return ItemLocation(item, locs[0])
# late doors check for random door colors
if self.restrictions.isLateDoors() and random.random() < self.lateDoorsProb:
if self.restrictions.isLateDoors() and self.random.random() < self.lateDoorsProb:
self.processLateDoors(itemLocDict, ap, container)
self.progressionItemLocs = progressionItemLocs
self.ap = ap
@@ -145,14 +145,14 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
def chooseLocationProg(self, locs, item):
locs = self.getLocsSpreadProgression(locs)
random.shuffle(locs)
self.random.shuffle(locs)
ret = self.getChooseFunc(self.chooseLocRanges, self.chooseLocFuncs)(locs)
self.log.debug('chooseLocationProg. ret='+ret.Name)
return ret
# get choose function from a weighted dict
def getChooseFunc(self, rangeDict, funcDict):
v = chooseFromRange(rangeDict)
v = chooseFromRange(rangeDict, self.random)
return funcDict[v]
@@ -209,6 +209,6 @@ class ItemThenLocChoiceProgSpeed(ItemThenLocChoice):
for i in range(len(availableLocations)):
loc = availableLocations[i]
d = distances[i]
if d == maxDist or random.random() >= self.spreadProb:
if d == maxDist or self.random.random() >= self.spreadProb:
locs.append(loc)
return locs

View File

@@ -1,5 +1,5 @@
import copy, time, random
import copy, time
from ..utils import log
from ..logic.cache import RequestCache
from ..rando.RandoServices import RandoServices
@@ -15,11 +15,11 @@ from ..graph.graph_utils import GraphUtils
# item pool is not empty).
# entry point is generateItems
class Filler(object):
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity):
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity, *, random):
self.startAP = startAP
self.cache = RequestCache()
self.graph = graph
self.services = RandoServices(graph, restrictions, self.cache)
self.services = RandoServices(graph, restrictions, self.cache, random=random)
self.restrictions = restrictions
self.settings = restrictions.settings
self.endDate = endDate
@@ -108,9 +108,9 @@ class Filler(object):
# very simple front fill algorithm with no rollback and no "softlock checks" (== dessy algorithm)
class FrontFiller(Filler):
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity):
super(FrontFiller, self).__init__(startAP, graph, restrictions, emptyContainer, endDate)
self.choice = ItemThenLocChoice(restrictions)
def __init__(self, startAP, graph, restrictions, emptyContainer, endDate=infinity, *, random):
super(FrontFiller, self).__init__(startAP, graph, restrictions, emptyContainer, endDate, random=random)
self.choice = ItemThenLocChoice(restrictions, random)
self.stdStart = GraphUtils.isStandardStart(self.startAP)
def isEarlyGame(self):

View File

@@ -1,5 +1,5 @@
import random, copy
import copy
from ..utils import log
from ..graph.graph_utils import GraphUtils, vanillaTransitions, vanillaBossesTransitions, escapeSource, escapeTargets, graphAreas, getAccessPoint
from ..logic.logic import Logic
@@ -11,13 +11,14 @@ from collections import defaultdict
# creates graph and handles randomized escape
class GraphBuilder(object):
def __init__(self, graphSettings):
def __init__(self, graphSettings, random):
self.graphSettings = graphSettings
self.areaRando = graphSettings.areaRando
self.bossRando = graphSettings.bossRando
self.escapeRando = graphSettings.escapeRando
self.minimizerN = graphSettings.minimizerN
self.log = log.get('GraphBuilder')
self.random = random
# builds everything but escape transitions
def createGraph(self, maxDiff):
@@ -48,18 +49,18 @@ class GraphBuilder(object):
objForced = forcedAreas.intersection(escAreas)
escAreasList = sorted(list(escAreas))
while len(objForced) < n and len(escAreasList) > 0:
objForced.add(escAreasList.pop(random.randint(0, len(escAreasList)-1)))
objForced.add(escAreasList.pop(self.random.randint(0, len(escAreasList)-1)))
forcedAreas = forcedAreas.union(objForced)
transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN, sorted(list(forcedAreas)))
transitions = GraphUtils.createMinimizerTransitions(self.graphSettings.startAP, self.minimizerN, sorted(list(forcedAreas)), random=self.random)
else:
if not self.bossRando:
transitions += vanillaBossesTransitions
else:
transitions += GraphUtils.createBossesTransitions()
transitions += GraphUtils.createBossesTransitions(self.random)
if not self.areaRando:
transitions += vanillaTransitions
else:
transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando)
transitions += GraphUtils.createAreaTransitions(self.graphSettings.lightAreaRando, random=self.random)
ret = AccessGraph(Logic.accessPoints, transitions, self.graphSettings.dotFile)
Objectives.objDict[self.graphSettings.player].setGraph(ret, maxDiff)
return ret
@@ -100,7 +101,7 @@ class GraphBuilder(object):
self.escapeTimer(graph, paths, self.areaRando or escapeTrigger is not None)
self.log.debug("escapeGraph: ({}, {}) timer: {}".format(escapeSource, dst, graph.EscapeAttributes['Timer']))
# animals
GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst)
GraphUtils.escapeAnimalsTransitions(graph, possibleTargets, dst, self.random)
return True
def _getTargets(self, sm, graph, maxDiff):
@@ -110,7 +111,7 @@ class GraphBuilder(object):
if len(possibleTargets) == 0:
self.log.debug("Can't randomize escape, fallback to vanilla")
possibleTargets.append('Climb Bottom Left')
random.shuffle(possibleTargets)
self.random.shuffle(possibleTargets)
return possibleTargets
def getPossibleEscapeTargets(self, emptyContainer, graph, maxDiff):

View File

@@ -1,6 +1,6 @@
from ..utils.utils import randGaussBounds, getRangeDict, chooseFromRange
from ..utils import log
import logging, copy, random
import logging, copy
class Item:
__slots__ = ( 'Category', 'Class', 'Name', 'Code', 'Type', 'BeamBits', 'ItemBits', 'Id' )
@@ -335,7 +335,7 @@ class ItemManager:
itemCode = item.Code + modifier
return itemCode
def __init__(self, majorsSplit, qty, sm, nLocs, bossesItems, maxDiff):
def __init__(self, majorsSplit, qty, sm, nLocs, bossesItems, maxDiff, random):
self.qty = qty
self.sm = sm
self.majorsSplit = majorsSplit
@@ -344,6 +344,7 @@ class ItemManager:
self.maxDiff = maxDiff
self.majorClass = 'Chozo' if majorsSplit == 'Chozo' else 'Major'
self.itemPool = []
self.random = random
def newItemPool(self, addBosses=True):
self.itemPool = []
@@ -386,7 +387,7 @@ class ItemManager:
return ItemManager.Items[itemType].withClass(itemClass)
def createItemPool(self, exclude=None):
itemPoolGenerator = ItemPoolGenerator.factory(self.majorsSplit, self, self.qty, self.sm, exclude, self.nLocs, self.maxDiff)
itemPoolGenerator = ItemPoolGenerator.factory(self.majorsSplit, self, self.qty, self.sm, exclude, self.nLocs, self.maxDiff, self.random)
self.itemPool = itemPoolGenerator.getItemPool()
@staticmethod
@@ -402,20 +403,20 @@ class ItemPoolGenerator(object):
nbBosses = 9
@staticmethod
def factory(majorsSplit, itemManager, qty, sm, exclude, nLocs, maxDiff):
def factory(majorsSplit, itemManager, qty, sm, exclude, nLocs, maxDiff, random):
if majorsSplit == 'Chozo':
return ItemPoolGeneratorChozo(itemManager, qty, sm, maxDiff)
return ItemPoolGeneratorChozo(itemManager, qty, sm, maxDiff, random)
elif majorsSplit == 'Plando':
return ItemPoolGeneratorPlando(itemManager, qty, sm, exclude, nLocs, maxDiff)
return ItemPoolGeneratorPlando(itemManager, qty, sm, exclude, nLocs, maxDiff, random)
elif nLocs == ItemPoolGenerator.maxLocs:
if majorsSplit == "Scavenger":
return ItemPoolGeneratorScavenger(itemManager, qty, sm, maxDiff)
return ItemPoolGeneratorScavenger(itemManager, qty, sm, maxDiff, random)
else:
return ItemPoolGeneratorMajors(itemManager, qty, sm, maxDiff)
return ItemPoolGeneratorMajors(itemManager, qty, sm, maxDiff, random)
else:
return ItemPoolGeneratorMinimizer(itemManager, qty, sm, nLocs, maxDiff)
return ItemPoolGeneratorMinimizer(itemManager, qty, sm, nLocs, maxDiff, random)
def __init__(self, itemManager, qty, sm, maxDiff):
def __init__(self, itemManager, qty, sm, maxDiff, random):
self.itemManager = itemManager
self.qty = qty
self.sm = sm
@@ -423,12 +424,13 @@ class ItemPoolGenerator(object):
self.maxEnergy = 18 # 14E, 4R
self.maxDiff = maxDiff
self.log = log.get('ItemPool')
self.random = random
def isUltraSparseNoTanks(self):
# if low stuff botwoon is not known there is a hard energy req of one tank, even
# with both suits
lowStuffBotwoon = self.sm.knowsLowStuffBotwoon()
return random.random() < 0.5 and (lowStuffBotwoon.bool == True and lowStuffBotwoon.difficulty <= self.maxDiff)
return self.random.random() < 0.5 and (lowStuffBotwoon.bool == True and lowStuffBotwoon.difficulty <= self.maxDiff)
def calcMaxMinors(self):
pool = self.itemManager.getItemPool()
@@ -464,7 +466,7 @@ class ItemPoolGenerator(object):
rangeDict = getRangeDict(ammoQty)
self.log.debug("rangeDict: {}".format(rangeDict))
while len(self.itemManager.getItemPool()) < maxItems:
item = chooseFromRange(rangeDict)
item = chooseFromRange(rangeDict, self.random)
self.itemManager.addMinor(item)
else:
minorsTypes = ['Missile', 'Super', 'PowerBomb']
@@ -522,7 +524,7 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
# no etank nor reserve
self.itemManager.removeItem('ETank')
self.itemManager.addItem('NoEnergy', 'Chozo')
elif random.random() < 0.5:
elif self.random.random() < 0.5:
# replace only etank with reserve
self.itemManager.removeItem('ETank')
self.itemManager.addItem('Reserve', 'Chozo')
@@ -535,9 +537,9 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
# 4-6
# already 3E and 1R
alreadyInPool = 4
rest = randGaussBounds(2, 5)
rest = randGaussBounds(self.random, 2, 5)
if rest >= 1:
if random.random() < 0.5:
if self.random.random() < 0.5:
self.itemManager.addItem('Reserve', 'Minor')
else:
self.itemManager.addItem('ETank', 'Minor')
@@ -550,13 +552,13 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
# 8-12
# add up to 3 Reserves or ETanks (cannot add more than 3 reserves)
for i in range(3):
if random.random() < 0.5:
if self.random.random() < 0.5:
self.itemManager.addItem('Reserve', 'Minor')
else:
self.itemManager.addItem('ETank', 'Minor')
# 7 already in the pool (3 E, 1 R, + the previous 3)
alreadyInPool = 7
rest = 1 + randGaussBounds(4, 3.7)
rest = 1 + randGaussBounds(self.random, 4, 3.7)
for i in range(rest):
self.itemManager.addItem('ETank', 'Minor')
# fill the rest with NoEnergy
@@ -581,10 +583,10 @@ class ItemPoolGeneratorChozo(ItemPoolGenerator):
return self.itemManager.getItemPool()
class ItemPoolGeneratorMajors(ItemPoolGenerator):
def __init__(self, itemManager, qty, sm, maxDiff):
super(ItemPoolGeneratorMajors, self).__init__(itemManager, qty, sm, maxDiff)
self.sparseRest = 1 + randGaussBounds(2, 5)
self.mediumRest = 3 + randGaussBounds(4, 3.7)
def __init__(self, itemManager, qty, sm, maxDiff, random):
super(ItemPoolGeneratorMajors, self).__init__(itemManager, qty, sm, maxDiff, random)
self.sparseRest = 1 + randGaussBounds(self.random,2, 5)
self.mediumRest = 3 + randGaussBounds(self.random, 4, 3.7)
self.ultraSparseNoTanks = self.isUltraSparseNoTanks()
def addNoEnergy(self):
@@ -609,7 +611,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
# no energy at all
self.addNoEnergy()
else:
if random.random() < 0.5:
if self.random.random() < 0.5:
self.itemManager.addItem('ETank')
else:
self.itemManager.addItem('Reserve')
@@ -620,7 +622,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
elif energyQty == 'sparse':
# 4-6
if random.random() < 0.5:
if self.random.random() < 0.5:
self.itemManager.addItem('Reserve')
else:
self.itemManager.addItem('ETank')
@@ -639,7 +641,7 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
alreadyInPool = 2
n = getE(3)
for i in range(n):
if random.random() < 0.5:
if self.random.random() < 0.5:
self.itemManager.addItem('Reserve')
else:
self.itemManager.addItem('ETank')
@@ -676,15 +678,15 @@ class ItemPoolGeneratorMajors(ItemPoolGenerator):
return self.itemManager.getItemPool()
class ItemPoolGeneratorScavenger(ItemPoolGeneratorMajors):
def __init__(self, itemManager, qty, sm, maxDiff):
super(ItemPoolGeneratorScavenger, self).__init__(itemManager, qty, sm, maxDiff)
def __init__(self, itemManager, qty, sm, maxDiff, random):
super(ItemPoolGeneratorScavenger, self).__init__(itemManager, qty, sm, maxDiff, random)
def addNoEnergy(self):
self.itemManager.addItem('Nothing')
class ItemPoolGeneratorMinimizer(ItemPoolGeneratorMajors):
def __init__(self, itemManager, qty, sm, nLocs, maxDiff):
super(ItemPoolGeneratorMinimizer, self).__init__(itemManager, qty, sm, maxDiff)
def __init__(self, itemManager, qty, sm, nLocs, maxDiff, random):
super(ItemPoolGeneratorMinimizer, self).__init__(itemManager, qty, sm, maxDiff, random)
self.maxItems = nLocs
self.calcMaxAmmo()
nMajors = len([itemName for itemName,item in ItemManager.Items.items() if item.Class == 'Major' and item.Category != 'Energy'])
@@ -716,8 +718,8 @@ class ItemPoolGeneratorMinimizer(ItemPoolGeneratorMajors):
self.log.debug("maxEnergy: "+str(self.maxEnergy))
class ItemPoolGeneratorPlando(ItemPoolGenerator):
def __init__(self, itemManager, qty, sm, exclude, nLocs, maxDiff):
super(ItemPoolGeneratorPlando, self).__init__(itemManager, qty, sm, maxDiff)
def __init__(self, itemManager, qty, sm, exclude, nLocs, maxDiff, random):
super(ItemPoolGeneratorPlando, self).__init__(itemManager, qty, sm, maxDiff, random)
# in exclude dict:
# in alreadyPlacedItems:
# dict of 'itemType: count' of items already added in the plando.
@@ -805,7 +807,7 @@ class ItemPoolGeneratorPlando(ItemPoolGenerator):
if ammoQty:
rangeDict = getRangeDict(ammoQty)
while len(self.itemManager.getItemPool()) < maxItems and remain > 0:
item = chooseFromRange(rangeDict)
item = chooseFromRange(rangeDict, self.random)
self.itemManager.addMinor(item)
remain -= 1

View File

@@ -1,4 +1,4 @@
import sys, random, time
import sys, time
from ..utils import log
from ..logic.logic import Logic
@@ -14,7 +14,7 @@ from ..utils.doorsmanager import DoorsManager
# entry point for rando execution ("randomize" method)
class RandoExec(object):
def __init__(self, seedName, vcr, randoSettings, graphSettings, player):
def __init__(self, seedName, vcr, randoSettings, graphSettings, player, random):
self.errorMsg = ""
self.seedName = seedName
self.vcr = vcr
@@ -22,6 +22,7 @@ class RandoExec(object):
self.graphSettings = graphSettings
self.log = log.get('RandoExec')
self.player = player
self.random = random
# processes settings to :
# - create Restrictions and GraphBuilder objects
@@ -31,7 +32,7 @@ class RandoExec(object):
vcr = VCR(self.seedName, 'rando') if self.vcr == True else None
self.errorMsg = ""
split = self.randoSettings.restrictions['MajorMinor']
self.graphBuilder = GraphBuilder(self.graphSettings)
self.graphBuilder = GraphBuilder(self.graphSettings, self.random)
container = None
i = 0
attempts = 500 if self.graphSettings.areaRando or self.graphSettings.doorsColorsRando or split == 'Scavenger' else 1
@@ -43,10 +44,10 @@ class RandoExec(object):
while container is None and i < attempts and now <= endDate:
self.restrictions = Restrictions(self.randoSettings)
if self.graphSettings.doorsColorsRando == True:
DoorsManager.randomize(self.graphSettings.allowGreyDoors, self.player)
DoorsManager.randomize(self.graphSettings.allowGreyDoors, self.player, self.random)
self.areaGraph = self.graphBuilder.createGraph(self.randoSettings.maxDiff)
services = RandoServices(self.areaGraph, self.restrictions)
setup = RandoSetup(self.graphSettings, Logic.locations[:], services, self.player)
services = RandoServices(self.areaGraph, self.restrictions, random=self.random)
setup = RandoSetup(self.graphSettings, Logic.locations[:], services, self.player, self.random)
self.setup = setup
container = setup.createItemLocContainer(endDate, vcr)
if container is None:
@@ -78,7 +79,7 @@ class RandoExec(object):
n = nMaj
elif split == 'Chozo':
n = nChozo
GraphUtils.updateLocClassesStart(startAP.GraphArea, split, possibleMajLocs, preserveMajLocs, n)
GraphUtils.updateLocClassesStart(startAP.GraphArea, split, possibleMajLocs, preserveMajLocs, n, self.random)
def postProcessItemLocs(self, itemLocs, hide):
# hide some items like in dessy's
@@ -89,7 +90,7 @@ class RandoExec(object):
if (item.Category != "Nothing"
and loc.CanHidden == True
and loc.Visibility == 'Visible'):
if bool(random.getrandbits(1)) == True:
if bool(self.random.getrandbits(1)) == True:
loc.Visibility = 'Hidden'
# put nothing in unfilled locations
filledLocNames = [il.Location.Name for il in itemLocs]

View File

@@ -1,5 +1,4 @@
import copy, random, sys, logging, os
import copy, sys, logging, os
from enum import Enum, unique
from ..utils import log
from ..utils.parameters import infinity
@@ -19,12 +18,13 @@ class ComebackCheckType(Enum):
# collection of stateless services to be used mainly by fillers
class RandoServices(object):
def __init__(self, graph, restrictions, cache=None):
def __init__(self, graph, restrictions, cache=None, *, random):
self.restrictions = restrictions
self.settings = restrictions.settings
self.areaGraph = graph
self.cache = cache
self.log = log.get('RandoServices')
self.random = random
@staticmethod
def printProgress(s):
@@ -217,7 +217,7 @@ class RandoServices(object):
# choose a morph item location in that context
morphItemLoc = ItemLocation(
morph,
random.choice(morphLocs)
self.random.choice(morphLocs)
)
# acquire morph in new context and see if we can still open new locs
newAP = self.collect(ap, containerCpy, morphItemLoc)
@@ -232,7 +232,7 @@ class RandoServices(object):
if morphLocItem is None or len(itemLocDict) == 1:
# no morph, or it is the only possibility: nothing to do
return
morphLocs = self.restrictions.lateMorphCheck(container, itemLocDict[morphLocItem])
morphLocs = self.restrictions.lateMorphCheck(container, itemLocDict[morphLocItem], self.random)
if morphLocs is not None:
itemLocDict[morphLocItem] = morphLocs
else:
@@ -380,10 +380,10 @@ class RandoServices(object):
(itemLocDict, isProg) = self.getPossiblePlacements(ap, container, ComebackCheckType.NoCheck)
assert not isProg
items = list(itemLocDict.keys())
random.shuffle(items)
self.random.shuffle(items)
for item in items:
cont = copy.copy(container)
loc = random.choice(itemLocDict[item])
loc = self.random.choice(itemLocDict[item])
itemLoc1 = ItemLocation(item, loc)
self.log.debug("itemLoc1 attempt: "+getItemLocStr(itemLoc1))
newAP = self.collect(ap, cont, itemLoc1)
@@ -391,8 +391,8 @@ class RandoServices(object):
self.cache.reset()
(ild, isProg) = self.getPossiblePlacements(newAP, cont, ComebackCheckType.NoCheck)
if isProg:
item2 = random.choice(list(ild.keys()))
itemLoc2 = ItemLocation(item2, random.choice(ild[item2]))
item2 = self.random.choice(list(ild.keys()))
itemLoc2 = ItemLocation(item2, self.random.choice(ild[item2]))
self.log.debug("itemLoc2: "+getItemLocStr(itemLoc2))
return (itemLoc1, itemLoc2)
return None

View File

@@ -1,5 +1,4 @@
import sys, random
import sys
from collections import defaultdict
from ..rando.Items import ItemManager
from ..utils.utils import getRangeDict, chooseFromRange
@@ -32,11 +31,11 @@ class RandoSettings(object):
def isPlandoRando(self):
return self.PlandoOptions is not None
def getItemManager(self, smbm, nLocs, bossesItems):
def getItemManager(self, smbm, nLocs, bossesItems, random):
if not self.isPlandoRando():
return ItemManager(self.restrictions['MajorMinor'], self.qty, smbm, nLocs, bossesItems, self.maxDiff)
return ItemManager(self.restrictions['MajorMinor'], self.qty, smbm, nLocs, bossesItems, self.maxDiff, random)
else:
return ItemManager('Plando', self.qty, smbm, nLocs, bossesItems, self.maxDiff)
return ItemManager('Plando', self.qty, smbm, nLocs, bossesItems, self.maxDiff, random)
def getExcludeItems(self, locations):
if not self.isPlandoRando():
@@ -94,7 +93,7 @@ class ProgSpeedParameters(object):
self.restrictions = restrictions
self.nLocs = nLocs
def getVariableSpeed(self):
def getVariableSpeed(self, random):
ranges = getRangeDict({
'slowest':7,
'slow':20,
@@ -102,7 +101,7 @@ class ProgSpeedParameters(object):
'fast':27,
'fastest':11
})
return chooseFromRange(ranges)
return chooseFromRange(ranges, random)
def getMinorHelpProb(self, progSpeed):
if self.restrictions.split != 'Major':
@@ -134,7 +133,7 @@ class ProgSpeedParameters(object):
def isSlow(self, progSpeed):
return progSpeed == "slow" or (progSpeed == "slowest" and self.restrictions.split == "Chozo")
def getItemLimit(self, progSpeed):
def getItemLimit(self, progSpeed, random):
itemLimit = self.nLocs
if self.isSlow(progSpeed):
itemLimit = int(self.nLocs*0.209) # 21 for 105

View File

@@ -1,4 +1,4 @@
import copy, random
import copy
from ..utils import log
from ..utils.utils import randGaussBounds
@@ -16,8 +16,9 @@ from ..rom.rom_patches import RomPatches
# checks init conditions for the randomizer: processes super fun settings, graph, start location, special restrictions
# the entry point is createItemLocContainer
class RandoSetup(object):
def __init__(self, graphSettings, locations, services, player):
def __init__(self, graphSettings, locations, services, player, random):
self.sm = SMBoolManager(player, services.settings.maxDiff)
self.random = random
self.settings = services.settings
self.graphSettings = graphSettings
self.startAP = graphSettings.startAP
@@ -31,7 +32,7 @@ class RandoSetup(object):
# print("nLocs Setup: "+str(len(self.locations)))
# in minimizer we can have some missing boss locs
bossesItems = [loc.BossItemType for loc in self.locations if loc.isBoss()]
self.itemManager = self.settings.getItemManager(self.sm, len(self.locations), bossesItems)
self.itemManager = self.settings.getItemManager(self.sm, len(self.locations), bossesItems, random)
self.forbiddenItems = []
self.restrictedLocs = []
self.lastRestricted = []
@@ -165,7 +166,7 @@ class RandoSetup(object):
return True
self.log.debug("********* PRE RANDO START")
container = copy.copy(self.container)
filler = FrontFiller(self.startAP, self.areaGraph, self.restrictions, container)
filler = FrontFiller(self.startAP, self.areaGraph, self.restrictions, container, random=self.random)
condition = filler.createStepCountCondition(4)
(isStuck, itemLocations, progItems) = filler.generateItems(condition)
self.log.debug("********* PRE RANDO END")
@@ -345,9 +346,9 @@ class RandoSetup(object):
def getForbiddenItemsFromList(self, itemList):
self.log.debug('getForbiddenItemsFromList: ' + str(itemList))
remove = []
n = randGaussBounds(len(itemList))
n = randGaussBounds(self.random, len(itemList))
for i in range(n):
idx = random.randint(0, len(itemList) - 1)
idx = self.random.randint(0, len(itemList) - 1)
item = itemList.pop(idx)
if item is not None:
remove.append(item)

View File

@@ -1,4 +1,4 @@
import copy, random
import copy
from ..utils import log
from ..graph.graph_utils import getAccessPoint
from ..rando.ItemLocContainer import getLocListStr
@@ -112,7 +112,7 @@ class Restrictions(object):
return item.Class == "Minor"
# return True if we can keep morph as a possibility
def lateMorphCheck(self, container, possibleLocs):
def lateMorphCheck(self, container, possibleLocs, random):
# the closer we get to the limit the higher the chances of allowing morph
proba = random.randint(0, self.lateMorphLimit)
if self.split == 'Full':