oldschool-toontown/toontown/suit/DistributedSuitPlannerAI.py

1182 lines
55 KiB
Python

from panda3d.toontown import *
from otp.ai.AIBaseGlobal import *
from direct.distributed import DistributedObjectAI
from . import SuitPlannerBase, DistributedSuitAI
from toontown.battle import BattleManagerAI
from direct.task import Task
from direct.directnotify import DirectNotifyGlobal
from . import SuitDNA
from toontown.battle import SuitBattleGlobals
from . import SuitTimings
from toontown.toon import NPCToons
from toontown.building import HQBuildingAI
from toontown.hood import ZoneUtil
from toontown.building import SuitBuildingGlobals
from toontown.building.DistributedBuildingAI import DistributedBuildingAI
from toontown.toonbase import ToontownBattleGlobals
from toontown.toonbase import ToontownGlobals
import math, time, random
class DistributedSuitPlannerAI(DistributedObjectAI.DistributedObjectAI, SuitPlannerBase.SuitPlannerBase):
CogdoPopFactor = config.GetFloat('cogdo-pop-factor', 1.5)
CogdoRatio = min(1.0, max(0.0, config.GetFloat('cogdo-ratio', 0.5)))
MinimumOfOne = config.GetBool('minimum-of-one-building', 0)
SuitHoodInfo = [
[
2100, 5, 15, 0, 5, 20, 3, (1, 5, 10, 40, 60, 80), (25, 25, 25, 25), (1, 2, 3), []], [2200, 3, 10, 0, 5, 15, 3, (1, 5, 10, 40, 60, 80), (10, 70, 10, 10), (1, 2, 3), []], [2300, 3, 10, 0, 5, 15, 3, (1, 5, 10, 40, 60, 80), (10, 10, 40, 40), (1, 2, 3), []], [1100, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (90, 10, 0, 0), (2, 3, 4), []], [1200, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (0, 0, 90, 10), (3, 4, 5, 6), []], [1300, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (40, 40, 10, 10), (3, 4, 5, 6), []], [3100, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (90, 10, 0, 0), (5, 6, 7), []], [3200, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (10, 20, 30, 40), (5, 6, 7), []], [3300, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (5, 85, 5, 5), (7, 8, 9), []], [4100, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (0, 0, 50, 50), (2, 3, 4), []], [4200, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (0, 0, 90, 10), (3, 4, 5, 6), []], [4300, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (50, 50, 0, 0), (3, 4, 5, 6), []], [5100, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (0, 20, 10, 70), (2, 3, 4), []], [5200, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (10, 70, 0, 20), (3, 4, 5, 6), []], [5300, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (5, 5, 5, 85), (3, 4, 5, 6), []], [9100, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (25, 25, 25, 25), (6, 7, 8, 9), []], [9200, 1, 5, 0, 99, 100, 4, (1, 5, 10, 40, 60, 80), (5, 5, 85, 5), (6, 7, 8, 9), []], [11000, 3, 15, 0, 0, 0, 4, (1, 5, 10, 40, 60, 80), (0, 0, 0, 100), (4, 5, 6), []], [11200, 10, 20, 0, 0, 0, 4, (1, 5, 10, 40, 60, 80), (0, 0, 0, 100), (4, 5, 6), []], [12000, 10, 20, 0, 0, 0, 4, (1, 5, 10, 40, 60, 80), (0, 0, 100, 0), (7, 8, 9), []], [13000, 10, 20, 0, 0, 0, 4, (1, 5, 10, 40, 60, 80), (0, 100, 0, 0), (8, 9, 10), []]]
SUIT_HOOD_INFO_ZONE = 0
SUIT_HOOD_INFO_MIN = 1
SUIT_HOOD_INFO_MAX = 2
SUIT_HOOD_INFO_BMIN = 3
SUIT_HOOD_INFO_BMAX = 4
SUIT_HOOD_INFO_BWEIGHT = 5
SUIT_HOOD_INFO_SMAX = 6
SUIT_HOOD_INFO_JCHANCE = 7
SUIT_HOOD_INFO_TRACK = 8
SUIT_HOOD_INFO_LVL = 9
SUIT_HOOD_INFO_HEIGHTS = 10
MAX_SUIT_TYPES = 6
POP_UPKEEP_DELAY = 10
POP_ADJUST_DELAY = 300
PATH_COLLISION_BUFFER = 5
TOTAL_MAX_SUITS = 50
MIN_PATH_LEN = 40
MAX_PATH_LEN = 300
MIN_TAKEOVER_PATH_LEN = 2
SUITS_ENTER_BUILDINGS = 1
SUIT_BUILDING_NUM_SUITS = 1.5
SUIT_BUILDING_TIMEOUT = [
None, None, None, None, None, None, 72, 60, 48, 36, 24, 12, 6, 3, 1, 0.5]
TOTAL_SUIT_BUILDING_PCT = 18 * CogdoPopFactor
BUILDING_HEIGHT_DISTRIBUTION = [
14, 18, 25, 23, 20]
TOTAL_BWEIGHT = 0
TOTAL_BWEIGHT_PER_TRACK = [
0, 0, 0, 0]
TOTAL_BWEIGHT_PER_HEIGHT = [
0, 0, 0, 0, 0]
for currHoodInfo in SuitHoodInfo:
weight = currHoodInfo[SUIT_HOOD_INFO_BWEIGHT]
tracks = currHoodInfo[SUIT_HOOD_INFO_TRACK]
levels = currHoodInfo[SUIT_HOOD_INFO_LVL]
heights = [
0, 0, 0, 0, 0]
for level in levels:
minFloors, maxFloors = SuitBuildingGlobals.SuitBuildingInfo[level - 1][0]
for i in range(minFloors - 1, maxFloors):
heights[i] += 1
currHoodInfo[SUIT_HOOD_INFO_HEIGHTS] = heights
TOTAL_BWEIGHT += weight
TOTAL_BWEIGHT_PER_TRACK[0] += weight * tracks[0]
TOTAL_BWEIGHT_PER_TRACK[1] += weight * tracks[1]
TOTAL_BWEIGHT_PER_TRACK[2] += weight * tracks[2]
TOTAL_BWEIGHT_PER_TRACK[3] += weight * tracks[3]
TOTAL_BWEIGHT_PER_HEIGHT[0] += weight * heights[0]
TOTAL_BWEIGHT_PER_HEIGHT[1] += weight * heights[1]
TOTAL_BWEIGHT_PER_HEIGHT[2] += weight * heights[2]
TOTAL_BWEIGHT_PER_HEIGHT[3] += weight * heights[3]
TOTAL_BWEIGHT_PER_HEIGHT[4] += weight * heights[4]
defaultSuitName = simbase.config.GetString('suit-type', 'random')
if defaultSuitName == 'random':
defaultSuitName = None
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSuitPlannerAI')
def __init__(self, air, zoneId):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
SuitPlannerBase.SuitPlannerBase.__init__(self)
self.air = air
self.zoneId = zoneId
self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
if simbase.air.wantCogdominiums:
if not hasattr(self.__class__, 'CogdoPopAdjusted'):
self.__class__.CogdoPopAdjusted = True
for index in range(len(self.SuitHoodInfo)):
hoodInfo = self.SuitHoodInfo[index]
hoodInfo[self.SUIT_HOOD_INFO_BMIN] = int(0.5 + self.CogdoPopFactor * hoodInfo[self.SUIT_HOOD_INFO_BMIN])
hoodInfo[self.SUIT_HOOD_INFO_BMAX] = int(0.5 + self.CogdoPopFactor * hoodInfo[self.SUIT_HOOD_INFO_BMAX])
self.hoodInfoIdx = -1
for index in range(len(self.SuitHoodInfo)):
currHoodInfo = self.SuitHoodInfo[index]
if currHoodInfo[self.SUIT_HOOD_INFO_ZONE] == self.canonicalZoneId:
self.hoodInfoIdx = index
self.currDesired = None
self.baseNumSuits = (self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_MIN] + self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_MAX]) // 2
self.targetNumCogdos = 0
if simbase.air.wantCogdominiums:
self.targetNumCogdos = int(0.5 + self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_BMIN] * self.CogdoRatio)
if self.MinimumOfOne:
self.targetNumCogdos = max(self.targetNumCogdos, 1)
self.targetNumSuitBuildings = self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_BMIN]
self.targetNumSuitBuildings -= self.targetNumCogdos
if self.MinimumOfOne:
self.targetNumSuitBuildings = max(self.targetNumSuitBuildings, 1)
if ZoneUtil.isWelcomeValley(self.zoneId):
self.targetNumCogdos = 0
self.targetNumSuitBuildings = 0
self.pendingBuildingTracks = []
self.pendingBuildingHeights = []
self.pendingCogdoHeights = []
self.suitList = []
self.numFlyInSuits = 0
self.numBuildingSuits = 0
self.numAttemptingTakeover = 0
self.numAttemptingCogdoTakeover = 0
self.zoneInfo = {}
self.zoneIdToPointMap = None
self.cogHQDoors = []
self.battleList = []
self.battleMgr = BattleManagerAI.BattleManagerAI(self.air)
self.setupDNA()
if self.notify.getDebug():
self.notify.debug('Creating a building manager AI in zone' + str(self.zoneId))
self.buildingMgr = self.air.buildingManagers.get(self.zoneId)
if self.buildingMgr:
blocks, hqBlocks, gagshopBlocks, petshopBlocks, kartshopBlocks, animBldgBlocks = self.buildingMgr.getDNABlockLists()
for currBlock in blocks:
bldg = self.buildingMgr.getBuilding(currBlock)
bldg.setSuitPlannerExt(self)
for currBlock in animBldgBlocks:
bldg = self.buildingMgr.getBuilding(currBlock)
bldg.setSuitPlannerExt(self)
self.dnaStore.resetBlockNumbers()
self.initBuildingsAndPoints()
numSuits = simbase.config.GetInt('suit-count', -1)
if numSuits >= 0:
self.currDesired = numSuits
suitHood = simbase.config.GetInt('suits-only-in-hood', -1)
if suitHood >= 0:
if self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_ZONE] != suitHood:
self.currDesired = 0
self.suitCountAdjust = 0
return
def cleanup(self):
taskMgr.remove(self.taskName('sptUpkeepPopulation'))
taskMgr.remove(self.taskName('sptAdjustPopulation'))
for suit in self.suitList:
suit.stopTasks()
if suit.isGenerated():
self.zoneChange(suit, suit.zoneId)
suit.requestDelete()
self.suitList = []
self.numFlyInSuits = 0
self.numBuildingSuits = 0
self.numAttemptingTakeover = 0
self.numAttemptingCogdoTakeover = 0
def delete(self):
self.cleanup()
DistributedObjectAI.DistributedObjectAI.delete(self)
def initBuildingsAndPoints(self):
if not self.buildingMgr:
return
if self.notify.getDebug():
self.notify.debug('Initializing building points')
self.buildingFrontDoors = {}
self.buildingSideDoors = {}
for p in self.frontdoorPointList:
blockNumber = p.getLandmarkBuildingIndex()
if p.getPointType() < 0:
self.notify.warning('No landmark building for (%s) in zone %d' % (repr(p), self.zoneId))
elif blockNumber in self.buildingFrontDoors:
self.notify.warning('Multiple front doors for building %d in zone %d' % (blockNumber, self.zoneId))
else:
self.buildingFrontDoors[blockNumber] = p
for p in self.sidedoorPointList:
blockNumber = p.getLandmarkBuildingIndex()
if p.getPointType() < 0:
self.notify.warning('No landmark building for (%s) in zone %d' % (repr(p), self.zoneId))
elif blockNumber in self.buildingSideDoors:
self.buildingSideDoors[blockNumber].append(p)
else:
self.buildingSideDoors[blockNumber] = [
p]
for bldg in self.buildingMgr.getBuildings():
if isinstance(bldg, HQBuildingAI.HQBuildingAI):
continue
blockNumber = bldg.getBlock()[0]
if blockNumber not in self.buildingFrontDoors:
self.notify.warning('No front door for building %d in zone %d' % (blockNumber, self.zoneId))
if blockNumber not in self.buildingSideDoors:
self.notify.warning('No side door for building %d in zone %d' % (blockNumber, self.zoneId))
def countNumSuitsPerTrack(self, count):
for suit in self.suitList:
if suit.track in count:
count[suit.track] += 1
else:
count[suit.track] = 1
def countNumBuildingsPerTrack(self, count):
if self.buildingMgr:
for building in self.buildingMgr.getBuildings():
if building.isSuitBuilding():
if building.track in count:
count[building.track] += 1
else:
count[building.track] = 1
def countNumBuildingsPerHeight(self, count):
if self.buildingMgr:
for building in self.buildingMgr.getBuildings():
if building.isSuitBuilding():
height = building.numFloors - 1
if height in count:
count[height] += 1
else:
count[height] = 1
def formatNumSuitsPerTrack(self, count):
result = ' '
for track, num in list(count.items()):
result += ' %s:%d' % (track, num)
return result[2:]
def calcDesiredNumFlyInSuits(self):
if self.currDesired != None:
return 0
return self.baseNumSuits + self.suitCountAdjust
def calcDesiredNumBuildingSuits(self):
if self.currDesired != None:
return self.currDesired
if not self.buildingMgr:
return 0
suitBuildings = self.buildingMgr.getEstablishedSuitBlocks()
return int(len(suitBuildings) * self.SUIT_BUILDING_NUM_SUITS)
def getZoneIdToPointMap(self):
if self.zoneIdToPointMap != None:
return self.zoneIdToPointMap
self.zoneIdToPointMap = {}
for point in self.streetPointList:
points = self.dnaStore.getAdjacentPoints(point)
i = points.getNumPoints() - 1
while i >= 0:
pi = points.getPointIndex(i)
p = self.pointIndexes[pi]
i -= 1
zoneName = self.dnaStore.getSuitEdgeZone(point.getIndex(), p.getIndex())
zoneId = int(self.extractGroupName(zoneName))
if zoneId in self.zoneIdToPointMap:
self.zoneIdToPointMap[zoneId].append(point)
else:
self.zoneIdToPointMap[zoneId] = [
point]
return self.zoneIdToPointMap
def getStreetPointsForBuilding(self, blockNumber):
pointList = []
if blockNumber in self.buildingSideDoors:
for doorPoint in self.buildingSideDoors[blockNumber]:
points = self.dnaStore.getAdjacentPoints(doorPoint)
i = points.getNumPoints() - 1
while i >= 0:
pi = points.getPointIndex(i)
point = self.pointIndexes[pi]
if point.getPointType() == DNASuitPoint.STREETPOINT:
pointList.append(point)
i -= 1
if blockNumber in self.buildingFrontDoors:
doorPoint = self.buildingFrontDoors[blockNumber]
points = self.dnaStore.getAdjacentPoints(doorPoint)
i = points.getNumPoints() - 1
while i >= 0:
pi = points.getPointIndex(i)
pointList.append(self.pointIndexes[pi])
i -= 1
return pointList
def createNewSuit(self, blockNumbers, streetPoints, toonBlockTakeover=None, cogdoTakeover=None, minPathLen=None, maxPathLen=None, buildingHeight=None, suitLevel=None, suitType=None, suitTrack=None, suitName=None, skelecog=None, revives=None):
startPoint = None
blockNumber = None
if self.notify.getDebug():
self.notify.debug('Choosing origin from %d+%d possibles.' % (len(streetPoints), len(blockNumbers)))
while startPoint == None and len(blockNumbers) > 0:
bn = random.choice(blockNumbers)
blockNumbers.remove(bn)
if bn in self.buildingSideDoors:
for doorPoint in self.buildingSideDoors[bn]:
points = self.dnaStore.getAdjacentPoints(doorPoint)
i = points.getNumPoints() - 1
while blockNumber == None and i >= 0:
pi = points.getPointIndex(i)
p = self.pointIndexes[pi]
i -= 1
startTime = SuitTimings.fromSuitBuilding
startTime += self.dnaStore.getSuitEdgeTravelTime(doorPoint.getIndex(), pi, self.suitWalkSpeed)
if not self.pointCollision(p, doorPoint, startTime):
startTime = SuitTimings.fromSuitBuilding
startPoint = doorPoint
blockNumber = bn
while startPoint == None and len(streetPoints) > 0:
p = random.choice(streetPoints)
streetPoints.remove(p)
if not self.pointCollision(p, None, SuitTimings.fromSky):
startPoint = p
startTime = SuitTimings.fromSky
if startPoint == None:
return
newSuit = DistributedSuitAI.DistributedSuitAI(simbase.air, self)
newSuit.startPoint = startPoint
if blockNumber != None:
newSuit.buildingSuit = 1
if suitTrack == None:
suitTrack = self.buildingMgr.getBuildingTrack(blockNumber)
else:
newSuit.flyInSuit = 1
newSuit.attemptingTakeover = self.newSuitShouldAttemptTakeover()
if newSuit.attemptingTakeover:
cogdosNeeded = self.countNumNeededCogdos()
bldgsNeeded = self.countNumNeededBuildings()
cogdosAvailable = cogdosNeeded - self.numAttemptingCogdoTakeover
bldgsAvailable = bldgsNeeded - (self.numAttemptingTakeover - self.numAttemptingCogdoTakeover)
totalAvailable = cogdosAvailable + bldgsAvailable
if cogdoTakeover is None:
cogdoTakeover = False
if simbase.air.wantCogdominiums:
if totalAvailable > 0:
r = random.randrange(totalAvailable)
if r < cogdosAvailable:
cogdoTakeover = True
newSuit.takeoverIsCogdo = cogdoTakeover
if newSuit.takeoverIsCogdo:
pendingTracks = [
's']
pendingHeights = self.pendingCogdoHeights
else:
pendingTracks = self.pendingBuildingTracks
pendingHeights = self.pendingBuildingHeights
if suitTrack == None and len(pendingTracks) > 0:
suitTrack = pendingTracks[0]
del pendingTracks[0]
pendingTracks.append(suitTrack)
if buildingHeight == None and len(pendingHeights) > 0:
buildingHeight = pendingHeights[0]
del pendingHeights[0]
pendingHeights.append(buildingHeight)
else:
if cogdoTakeover and suitTrack == None:
suitTrack = random.choice(['s'])
if suitName == None:
if not cogdoTakeover:
suitName, skelecog = self.air.suitInvasionManager.getInvadingCog()
if suitName == None:
suitName = self.defaultSuitName
if suitType == None and suitName != None:
suitType = SuitDNA.getSuitType(suitName)
suitTrack = SuitDNA.getSuitDept(suitName)
if suitLevel == None and buildingHeight != None:
if not cogdoTakeover:
suitLevel = self.chooseSuitLevel(self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_LVL], buildingHeight)
else:
suitLevel = self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_LVL][-1] + 1
suitLevel, suitType, suitTrack = self.pickLevelTypeAndTrack(suitLevel, suitType, suitTrack)
newSuit.setupSuitDNA(suitLevel, suitType, suitTrack)
newSuit.buildingHeight = buildingHeight
gotDestination = self.chooseDestination(newSuit, startTime, toonBlockTakeover=toonBlockTakeover, cogdoTakeover=cogdoTakeover, minPathLen=minPathLen, maxPathLen=maxPathLen)
if not gotDestination:
self.notify.debug("Couldn't get a destination in %d!" % self.zoneId)
newSuit.doNotDeallocateChannel = None
newSuit.delete()
return
newSuit.initializePath()
self.zoneChange(newSuit, None, newSuit.zoneId)
if skelecog:
newSuit.setSkelecog(skelecog)
if revives:
newSuit.setSkeleRevives(revives)
newSuit.generateWithRequired(newSuit.zoneId)
newSuit.moveToNextLeg(None)
self.suitList.append(newSuit)
if newSuit.flyInSuit:
self.numFlyInSuits += 1
if newSuit.buildingSuit:
self.numBuildingSuits += 1
if newSuit.attemptingTakeover:
self.numAttemptingTakeover += 1
if newSuit.takeoverIsCogdo:
self.numAttemptingCogdoTakeover += 1
return newSuit
def countNumNeededBuildings(self):
if not self.buildingMgr:
return 0
numSuitBuildings = len(self.buildingMgr.getSuitBlocks()) - len(self.buildingMgr.getCogdoBlocks())
numNeeded = self.targetNumSuitBuildings - numSuitBuildings
return numNeeded
def countNumNeededCogdos(self):
if not self.buildingMgr:
return 0
numCogdos = len(self.buildingMgr.getCogdoBlocks())
numNeeded = self.targetNumCogdos - numCogdos
return numNeeded
def newSuitShouldAttemptTakeover(self):
if not self.SUITS_ENTER_BUILDINGS:
return 0
numNeeded = self.countNumNeededBuildings()
if simbase.air.wantCogdominiums:
numNeeded += self.countNumNeededCogdos()
if self.numAttemptingTakeover >= numNeeded:
self.pendingBuildingTracks = []
return 0
self.notify.debug('DSP %d is planning a takeover attempt in zone %d' % (self.getDoId(), self.zoneId))
return 1
def chooseDestination(self, suit, startTime, toonBlockTakeover=None, cogdoTakeover=None, minPathLen=None, maxPathLen=None):
possibles = []
backup = []
if cogdoTakeover is None:
cogdoTakeover = False
if toonBlockTakeover != None:
suit.attemptingTakeover = 1
blockNumber = toonBlockTakeover
if blockNumber in self.buildingFrontDoors:
possibles.append((blockNumber, self.buildingFrontDoors[blockNumber]))
elif suit.attemptingTakeover:
for blockNumber in self.buildingMgr.getToonBlocks():
building = self.buildingMgr.getBuilding(blockNumber)
extZoneId, intZoneId = building.getExteriorAndInteriorZoneId()
if not NPCToons.isZoneProtected(intZoneId):
if blockNumber in self.buildingFrontDoors:
possibles.append((blockNumber, self.buildingFrontDoors[blockNumber]))
else:
if self.buildingMgr:
for blockNumber in self.buildingMgr.getSuitBlocks():
track = self.buildingMgr.getBuildingTrack(blockNumber)
if track == suit.track and blockNumber in self.buildingSideDoors:
for doorPoint in self.buildingSideDoors[blockNumber]:
possibles.append((blockNumber, doorPoint))
backup = []
for p in self.streetPointList:
backup.append((None, p))
if self.notify.getDebug():
self.notify.debug('Choosing destination point from %d+%d possibles.' % (len(possibles), len(backup)))
if len(possibles) == 0:
possibles = backup
backup = []
if minPathLen == None:
if suit.attemptingTakeover:
minPathLen = self.MIN_TAKEOVER_PATH_LEN
else:
minPathLen = self.MIN_PATH_LEN
if maxPathLen == None:
maxPathLen = self.MAX_PATH_LEN
retryCount = 0
while len(possibles) > 0 and retryCount < 50:
p = random.choice(possibles)
possibles.remove(p)
if len(possibles) == 0:
possibles = backup
backup = []
path = self.genPath(suit.startPoint, p[1], minPathLen, maxPathLen)
if path and not self.pathCollision(path, startTime):
suit.endPoint = p[1]
suit.minPathLen = minPathLen
suit.maxPathLen = maxPathLen
suit.buildingDestination = p[0]
suit.buildingDestinationIsCogdo = cogdoTakeover
suit.setPath(path)
return 1
retryCount += 1
return 0
def pathCollision(self, path, elapsedTime):
pathLength = path.getNumPoints()
i = 0
pi = path.getPointIndex(i)
point = self.pointIndexes[pi]
adjacentPoint = self.pointIndexes[path.getPointIndex(i + 1)]
while point.getPointType() == DNASuitPoint.FRONTDOORPOINT or point.getPointType() == DNASuitPoint.SIDEDOORPOINT:
i += 1
lastPi = pi
pi = path.getPointIndex(i)
adjacentPoint = point
point = self.pointIndexes[pi]
elapsedTime += self.dnaStore.getSuitEdgeTravelTime(lastPi, pi, self.suitWalkSpeed)
result = self.pointCollision(point, adjacentPoint, elapsedTime)
return result
def pointCollision(self, point, adjacentPoint, elapsedTime):
for suit in self.suitList:
if suit.pointInMyPath(point, elapsedTime):
return 1
if adjacentPoint != None:
return self.battleCollision(point, adjacentPoint)
else:
points = self.dnaStore.getAdjacentPoints(point)
i = points.getNumPoints() - 1
while i >= 0:
pi = points.getPointIndex(i)
p = self.pointIndexes[pi]
i -= 1
if self.battleCollision(point, p):
return 1
return 0
def battleCollision(self, point, adjacentPoint):
zoneName = self.dnaStore.getSuitEdgeZone(point.getIndex(), adjacentPoint.getIndex())
zoneId = int(self.extractGroupName(zoneName))
return self.battleMgr.cellHasBattle(zoneId)
def removeSuit(self, suit):
self.zoneChange(suit, suit.zoneId)
if self.suitList.count(suit) > 0:
self.suitList.remove(suit)
if suit.flyInSuit:
self.numFlyInSuits -= 1
if suit.buildingSuit:
self.numBuildingSuits -= 1
if suit.attemptingTakeover:
self.numAttemptingTakeover -= 1
if suit.takeoverIsCogdo:
self.numAttemptingCogdoTakeover -= 1
suit.requestDelete()
def countTakeovers(self):
count = 0
for suit in self.suitList:
if suit.attemptingTakeover:
count += 1
return count
def countCogdoTakeovers(self):
count = 0
for suit in self.suitList:
if suit.attemptingTakeover and suit.takeoverIsCogdo:
count += 1
return count
def __waitForNextUpkeep(self):
t = random.random() * 2.0 + self.POP_UPKEEP_DELAY
taskMgr.doMethodLater(t, self.upkeepSuitPopulation, self.taskName('sptUpkeepPopulation'))
def __waitForNextAdjust(self):
t = random.random() * 10.0 + self.POP_ADJUST_DELAY
taskMgr.doMethodLater(t, self.adjustSuitPopulation, self.taskName('sptAdjustPopulation'))
def upkeepSuitPopulation(self, task):
targetFlyInNum = self.calcDesiredNumFlyInSuits()
targetFlyInNum = min(targetFlyInNum, self.TOTAL_MAX_SUITS - self.numBuildingSuits)
streetPoints = self.streetPointList[:]
flyInDeficit = (targetFlyInNum - self.numFlyInSuits + 3) // 4
while flyInDeficit > 0:
if not self.createNewSuit([], streetPoints):
break
flyInDeficit -= 1
if self.buildingMgr:
suitBuildings = self.buildingMgr.getEstablishedSuitBlocks()
else:
suitBuildings = []
if self.currDesired != None:
targetBuildingNum = max(0, self.currDesired - self.numFlyInSuits)
else:
targetBuildingNum = int(len(suitBuildings) * self.SUIT_BUILDING_NUM_SUITS)
targetBuildingNum += flyInDeficit
targetBuildingNum = min(targetBuildingNum, self.TOTAL_MAX_SUITS - self.numFlyInSuits)
buildingDeficit = (targetBuildingNum - self.numBuildingSuits + 3) // 4
while buildingDeficit > 0:
if not self.createNewSuit(suitBuildings, streetPoints):
break
buildingDeficit -= 1
if self.notify.getDebug() and self.currDesired == None:
self.notify.debug('zone %d has %d of %d fly-in and %d of %d building suits.' % (self.zoneId, self.numFlyInSuits, targetFlyInNum, self.numBuildingSuits, targetBuildingNum))
if buildingDeficit != 0:
self.notify.debug('remaining deficit is %d.' % buildingDeficit)
if self.buildingMgr:
suitBuildings = self.buildingMgr.getEstablishedSuitBlocks()
timeoutIndex = min(len(suitBuildings), len(self.SUIT_BUILDING_TIMEOUT) - 1)
timeout = self.SUIT_BUILDING_TIMEOUT[timeoutIndex]
if timeout != None:
timeout *= 3600.0
oldest = None
oldestAge = 0
now = time.time()
for b in suitBuildings:
building = self.buildingMgr.getBuilding(b)
if hasattr(building, 'elevator'):
if building.elevator.fsm.getCurrentState().getName() == 'waitEmpty':
age = now - building.becameSuitTime
if age > oldestAge:
oldest = building
oldestAge = age
if oldestAge > timeout:
self.notify.info('Street %d has %d buildings; reclaiming %0.2f-hour-old building.' % (self.zoneId, len(suitBuildings), oldestAge / 3600.0))
oldest.b_setVictorList([0, 0, 0, 0])
oldest.updateSavedBy(None)
oldest.toonTakeOver()
self.__waitForNextUpkeep()
return Task.done
def adjustSuitPopulation(self, task):
hoodInfo = self.SuitHoodInfo[self.hoodInfoIdx]
if hoodInfo[self.SUIT_HOOD_INFO_MAX] == 0:
self.__waitForNextAdjust()
return Task.done
min = hoodInfo[self.SUIT_HOOD_INFO_MIN]
max = hoodInfo[self.SUIT_HOOD_INFO_MAX]
adjustment = random.choice((-2, -1, -1, 0, 0, 0, 1, 1, 2))
self.suitCountAdjust += adjustment
desiredNum = self.calcDesiredNumFlyInSuits()
if desiredNum < min:
self.suitCountAdjust = min - self.baseNumSuits
else:
if desiredNum > max:
self.suitCountAdjust = max - self.baseNumSuits
self.__waitForNextAdjust()
return Task.done
def suitTakeOver(self, blockNumber, suitTrack, difficulty, buildingHeight):
if self.pendingBuildingTracks.count(suitTrack) > 0:
self.pendingBuildingTracks.remove(suitTrack)
if self.pendingBuildingHeights.count(buildingHeight) > 0:
self.pendingBuildingHeights.remove(buildingHeight)
building = self.buildingMgr.getBuilding(blockNumber)
building.suitTakeOver(suitTrack, difficulty, buildingHeight)
def cogdoTakeOver(self, blockNumber, suitTrack, difficulty, buildingHeight):
if self.pendingCogdoHeights.count(buildingHeight) > 0:
self.pendingCogdoHeights.remove(buildingHeight)
building = self.buildingMgr.getBuilding(blockNumber)
building.cogdoTakeOver(suitTrack, difficulty, buildingHeight)
def recycleBuilding(self, isCogdo):
bmin = self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_BMIN]
current = len(self.buildingMgr.getSuitBlocks())
target = self.targetNumSuitBuildings + self.targetNumCogdos
if target > bmin and current <= target:
if isCogdo:
if self.targetNumCogdos > choice(self.MinimumOfOne, 1, 0):
self.targetNumCogdos -= 1
self.assignCogdos(1)
elif self.targetNumSuitBuildings > choice(self.MinimumOfOne, 1, 0):
self.targetNumSuitBuildings -= 1
self.assignSuitBuildings(1)
def assignInitialSuitBuildings(self):
totalBuildings = 0
targetSuitBuildings = 0
actualSuitBuildings = 0
targetCogdos = 0
actualCogdos = 0
for sp in list(self.air.suitPlanners.values()):
totalBuildings += len(sp.frontdoorPointList)
targetSuitBuildings += sp.targetNumSuitBuildings
targetCogdos += sp.targetNumCogdos
if sp.buildingMgr:
numCogdoBlocks = len(sp.buildingMgr.getCogdoBlocks())
actualSuitBuildings += len(sp.buildingMgr.getSuitBlocks()) - numCogdoBlocks
actualCogdos += numCogdoBlocks
wantedSuitBuildings = int(totalBuildings * self.TOTAL_SUIT_BUILDING_PCT / 100)
if simbase.air.wantCogdominiums:
wantedCogdos = int(wantedSuitBuildings * self.CogdoRatio)
wantedSuitBuildings -= wantedCogdos
else:
wantedCogdos = 0
self.notify.debug('Want %d out of %d total suit buildings; we currently have %d assigned, %d actual.' % (wantedSuitBuildings, totalBuildings, targetSuitBuildings, actualSuitBuildings))
if actualSuitBuildings > 0:
numReassigned = 0
for sp in list(self.air.suitPlanners.values()):
if sp.buildingMgr:
numBuildings = len(sp.buildingMgr.getSuitBlocks()) - len(sp.buildingMgr.getCogdoBlocks())
else:
numBuildings = 0
if numBuildings > sp.targetNumSuitBuildings:
more = numBuildings - sp.targetNumSuitBuildings
sp.targetNumSuitBuildings += more
targetSuitBuildings += more
numReassigned += more
if numReassigned > 0:
self.notify.debug('Assigned %d buildings where suit buildings already existed.' % numReassigned)
if simbase.air.wantCogdominiums:
if actualCogdos > 0:
numReassigned = 0
for sp in list(self.air.suitPlanners.values()):
if sp.buildingMgr:
numCogdos = len(sp.buildingMgr.getCogdoBlocks())
else:
numCogdos = 0
if numCogdos > sp.targetNumCogdos:
more = numCogdos - sp.targetNumCogdos
sp.targetNumCogdos += more
targetCogdos += more
numReassigned += more
if numReassigned > 0:
self.notify.debug('Assigned %d cogdos where cogdos already existed.' % numReassigned)
if wantedSuitBuildings > targetSuitBuildings:
additionalBuildings = wantedSuitBuildings - targetSuitBuildings
self.assignSuitBuildings(additionalBuildings)
else:
if wantedSuitBuildings < targetSuitBuildings:
extraBuildings = targetSuitBuildings - wantedSuitBuildings
self.unassignSuitBuildings(extraBuildings)
if simbase.air.wantCogdominiums:
if wantedCogdos > targetCogdos:
additionalCogdos = wantedCogdos - targetCogdos
self.assignCogdos(additionalCogdos)
elif wantedCogdos < targetCogdos:
extraCogdos = targetCogdos - wantedCogdos
self.unassignCogdos(extraCogdos)
def assignSuitBuildings(self, numToAssign):
hoodInfo = self.SuitHoodInfo[:]
totalWeight = self.TOTAL_BWEIGHT
totalWeightPerTrack = self.TOTAL_BWEIGHT_PER_TRACK[:]
totalWeightPerHeight = self.TOTAL_BWEIGHT_PER_HEIGHT[:]
numPerTrack = {'c': 0, 'l': 0, 'm': 0, 's': 0}
for sp in list(self.air.suitPlanners.values()):
sp.countNumBuildingsPerTrack(numPerTrack)
numPerTrack['c'] += sp.pendingBuildingTracks.count('c')
numPerTrack['l'] += sp.pendingBuildingTracks.count('l')
numPerTrack['m'] += sp.pendingBuildingTracks.count('m')
numPerTrack['s'] += sp.pendingBuildingTracks.count('s')
numPerHeight = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
for sp in list(self.air.suitPlanners.values()):
sp.countNumBuildingsPerHeight(numPerHeight)
numPerHeight[0] += sp.pendingBuildingHeights.count(0)
numPerHeight[1] += sp.pendingBuildingHeights.count(1)
numPerHeight[2] += sp.pendingBuildingHeights.count(2)
numPerHeight[3] += sp.pendingBuildingHeights.count(3)
numPerHeight[4] += sp.pendingBuildingHeights.count(4)
while numToAssign > 0:
smallestCount = None
smallestTracks = []
for trackIndex in range(4):
if totalWeightPerTrack[trackIndex]:
track = SuitDNA.suitDepts[trackIndex]
count = numPerTrack[track]
if smallestCount == None or count < smallestCount:
smallestTracks = [
track]
smallestCount = count
elif count == smallestCount:
smallestTracks.append(track)
if not smallestTracks:
self.notify.info('No more room for buildings, with %s still to assign.' % numToAssign)
return
buildingTrack = random.choice(smallestTracks)
buildingTrackIndex = SuitDNA.suitDepts.index(buildingTrack)
smallestCount = None
smallestHeights = []
for height in range(5):
if totalWeightPerHeight[height]:
count = float(numPerHeight[height]) / float(self.BUILDING_HEIGHT_DISTRIBUTION[height])
if smallestCount == None or count < smallestCount:
smallestHeights = [
height]
smallestCount = count
elif count == smallestCount:
smallestHeights.append(height)
if not smallestHeights:
self.notify.info('No more room for buildings, with %s still to assign.' % numToAssign)
return
buildingHeight = random.choice(smallestHeights)
self.notify.info('Existing buildings are (%s, %s), choosing from (%s, %s), chose %s, %s.' % (self.formatNumSuitsPerTrack(numPerTrack), self.formatNumSuitsPerTrack(numPerHeight), smallestTracks, smallestHeights, buildingTrack, buildingHeight))
repeat = 1
while repeat and buildingTrack != None and buildingHeight != None:
if len(hoodInfo) == 0:
self.notify.warning('No more streets can have suit buildings, with %d buildings unassigned!' % numToAssign)
return
repeat = 0
currHoodInfo = self.chooseStreetWithPreference(hoodInfo, buildingTrackIndex, buildingHeight)
zoneId = currHoodInfo[self.SUIT_HOOD_INFO_ZONE]
if zoneId in self.air.suitPlanners:
sp = self.air.suitPlanners[zoneId]
numCogdos = sp.targetNumCogdos
numBldgs = sp.targetNumSuitBuildings
numTotalBuildings = len(sp.frontdoorPointList)
else:
numCogdos = 0
numBldgs = 0
numTotalBuildings = 0
if numCogdos + numBldgs >= currHoodInfo[self.SUIT_HOOD_INFO_BMAX] or numCogdos + numBldgs >= numTotalBuildings:
self.notify.info('Zone %d has enough buildings.' % zoneId)
hoodInfo.remove(currHoodInfo)
weight = currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
tracks = currHoodInfo[self.SUIT_HOOD_INFO_TRACK]
heights = currHoodInfo[self.SUIT_HOOD_INFO_HEIGHTS]
totalWeight -= weight
totalWeightPerTrack[0] -= weight * tracks[0]
totalWeightPerTrack[1] -= weight * tracks[1]
totalWeightPerTrack[2] -= weight * tracks[2]
totalWeightPerTrack[3] -= weight * tracks[3]
totalWeightPerHeight[0] -= weight * heights[0]
totalWeightPerHeight[1] -= weight * heights[1]
totalWeightPerHeight[2] -= weight * heights[2]
totalWeightPerHeight[3] -= weight * heights[3]
totalWeightPerHeight[4] -= weight * heights[4]
if totalWeightPerTrack[buildingTrackIndex] <= 0:
buildingTrack = None
if totalWeightPerHeight[buildingHeight] <= 0:
buildingHeight = None
repeat = 1
if buildingTrack != None and buildingHeight != None:
sp.targetNumSuitBuildings += 1
sp.pendingBuildingTracks.append(buildingTrack)
sp.pendingBuildingHeights.append(buildingHeight)
self.notify.info('Assigning building to zone %d, pending tracks = %s, pending heights = %s' % (zoneId, sp.pendingBuildingTracks, sp.pendingBuildingHeights))
numPerTrack[buildingTrack] += 1
numPerHeight[buildingHeight] += 1
numToAssign -= 1
return
def unassignSuitBuildings(self, numToAssign):
hoodInfo = self.SuitHoodInfo[:]
totalWeight = self.TOTAL_BWEIGHT
while numToAssign > 0:
repeat = 1
while repeat:
if len(hoodInfo) == 0:
self.notify.warning('No more streets can remove suit buildings, with %d buildings too many!' % numToAssign)
return
repeat = 0
currHoodInfo = self.chooseStreetNoPreference(hoodInfo, totalWeight)
zoneId = currHoodInfo[self.SUIT_HOOD_INFO_ZONE]
if zoneId in self.air.suitPlanners:
sp = self.air.suitPlanners[zoneId]
numCogdos = sp.targetNumCogdos
numBldgs = sp.targetNumSuitBuildings
numTotalBuildings = len(sp.frontdoorPointList)
else:
numCogdos = 0
numBldgs = 0
numTotalBuildings = 0
overallStrapped = numCogdos + numBldgs <= currHoodInfo[self.SUIT_HOOD_INFO_BMIN]
bldgStrapped = numBldgs <= choice(self.MinimumOfOne, 1, 0)
if overallStrapped or bldgStrapped:
self.notify.info("Zone %d can't remove any more buildings." % zoneId)
hoodInfo.remove(currHoodInfo)
totalWeight -= currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
repeat = 1
self.notify.info('Unassigning building from zone %d.' % zoneId)
sp.targetNumSuitBuildings -= 1
numToAssign -= 1
def assignCogdos(self, numToAssign):
hoodInfo = self.SuitHoodInfo[:]
totalWeight = self.TOTAL_BWEIGHT
while numToAssign > 0:
while 1:
if len(hoodInfo) == 0:
self.notify.warning('No more streets can have cogdos, with %d cogdos unassigned!' % numToAssign)
return
currHoodInfo = self.chooseStreetNoPreference(hoodInfo, totalWeight)
zoneId = currHoodInfo[self.SUIT_HOOD_INFO_ZONE]
if zoneId in self.air.suitPlanners:
sp = self.air.suitPlanners[zoneId]
numCogdos = sp.targetNumCogdos
numBldgs = sp.targetNumSuitBuildings
numTotalBuildings = len(sp.frontdoorPointList)
else:
numCogdos = 0
numBldgs = 0
numTotalBuildings = 0
if numCogdos + numBldgs >= currHoodInfo[self.SUIT_HOOD_INFO_BMAX] or numCogdos + numBldgs >= numTotalBuildings:
self.notify.info('Zone %d has enough cogdos.' % zoneId)
hoodInfo.remove(currHoodInfo)
weight = currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
totalWeight -= weight
continue
break
sp.targetNumCogdos += 1
sp.pendingCogdoHeights.append(DistributedBuildingAI.FieldOfficeNumFloors)
self.notify.info('Assigning cogdo to zone %d' % zoneId)
numToAssign -= 1
def unassignCogdos(self, numToAssign):
hoodInfo = self.SuitHoodInfo[:]
totalWeight = self.TOTAL_BWEIGHT
while numToAssign > 0:
while 1:
currHoodInfo = self.chooseStreetNoPreference(hoodInfo, totalWeight)
zoneId = currHoodInfo[self.SUIT_HOOD_INFO_ZONE]
if zoneId in self.air.suitPlanners:
sp = self.air.suitPlanners[zoneId]
numCogdos = sp.targetNumCogdos
numBldgs = sp.targetNumSuitBuildings
numTotalBuildings = len(sp.frontdoorPointList)
else:
numCogdos = 0
numBldgs = 0
numTotalBuildings = 0
overallStrapped = numCogdos + numBldgs <= currHoodInfo[self.SUIT_HOOD_INFO_BMIN]
cogdoStrapped = numCogdos <= choice(self.MinimumOfOne, 1, 0)
if overallStrapped or cogdoStrapped:
self.notify.info("Zone %s can't remove any more cogdos." % zoneId)
hoodInfo.remove(currHoodInfo)
totalWeight -= currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
continue
break
self.notify.info('Unassigning cogdo from zone %s.' % zoneId)
sp.targetNumCogdos -= 1
numToAssign -= 1
def chooseStreetNoPreference(self, hoodInfo, totalWeight):
c = random.random() * totalWeight
t = 0
for currHoodInfo in hoodInfo:
weight = currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
t += weight
if c < t:
return currHoodInfo
self.notify.warning('Weighted random choice failed! Total is %s, chose %s' % (t, c))
return random.choice(hoodInfo)
def chooseStreetWithPreference(self, hoodInfo, buildingTrackIndex, buildingHeight):
dist = []
for currHoodInfo in hoodInfo:
weight = currHoodInfo[self.SUIT_HOOD_INFO_BWEIGHT]
thisValue = weight * currHoodInfo[self.SUIT_HOOD_INFO_TRACK][buildingTrackIndex] * currHoodInfo[self.SUIT_HOOD_INFO_HEIGHTS][buildingHeight]
dist.append(thisValue)
totalWeight = sum(dist)
c = random.random() * totalWeight
t = 0
for i in range(len(hoodInfo)):
t += dist[i]
if c < t:
return hoodInfo[i]
self.notify.warning('Weighted random choice failed! Total is %s, chose %s' % (t, c))
return random.choice(hoodInfo)
def chooseSuitLevel(self, possibleLevels, buildingHeight):
choices = []
for level in possibleLevels:
minFloors, maxFloors = SuitBuildingGlobals.SuitBuildingInfo[level - 1][0]
if buildingHeight >= minFloors - 1 and buildingHeight <= maxFloors - 1:
choices.append(level)
return random.choice(choices)
def initTasks(self):
self.__waitForNextUpkeep()
self.__waitForNextAdjust()
def resyncSuits(self):
for suit in self.suitList:
suit.resync()
def flySuits(self):
for suit in self.suitList:
if suit.pathState == 1:
suit.flyAwayNow()
def requestBattle(self, zoneId, suit, toonId):
self.notify.debug('requestBattle() - zone: %d suit: %d toon: %d' % (zoneId, suit.doId, toonId))
canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
if canonicalZoneId not in self.battlePosDict:
return 0
toon = self.air.doId2do.get(toonId)
if toon.getBattleId() > 0:
self.notify.warning('We tried to request a battle when the toon was already in battle')
return 0
if toon:
if hasattr(toon, 'doId'):
print((
'Setting toonID ', toonId))
toon.b_setBattleId(toonId)
pos = self.battlePosDict[canonicalZoneId]
interactivePropTrackBonus = -1
if simbase.config.GetBool('props-buff-battles', True) and canonicalZoneId in self.cellToGagBonusDict:
tentativeBonusTrack = self.cellToGagBonusDict[canonicalZoneId]
trackToHolidayDict = {ToontownBattleGlobals.SQUIRT_TRACK: ToontownGlobals.HYDRANTS_BUFF_BATTLES, ToontownBattleGlobals.THROW_TRACK: ToontownGlobals.MAILBOXES_BUFF_BATTLES, ToontownBattleGlobals.HEAL_TRACK: ToontownGlobals.TRASHCANS_BUFF_BATTLES}
if tentativeBonusTrack in trackToHolidayDict:
holidayId = trackToHolidayDict[tentativeBonusTrack]
if simbase.air.holidayManager.isHolidayRunning(holidayId) and simbase.air.holidayManager.getCurPhase(holidayId) >= 1:
interactivePropTrackBonus = tentativeBonusTrack
self.battleMgr.newBattle(zoneId, zoneId, pos, suit, toonId, self.__battleFinished, self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_SMAX], interactivePropTrackBonus)
for currOther in self.zoneInfo[zoneId]:
self.notify.debug('Found suit %d in this new battle zone %d' % (currOther.getDoId(), zoneId))
if currOther != suit:
if currOther.pathState == 1 and currOther.legType == SuitLeg.TWalk:
self.checkForBattle(zoneId, currOther)
return 1
def __battleFinished(self, zoneId):
self.notify.debug('DistSuitPlannerAI: battle in zone ' + str(zoneId) + ' finished')
currBattleIdx = 0
while currBattleIdx < len(self.battleList):
currBattle = self.battleList[currBattleIdx]
if currBattle[0] == zoneId:
self.notify.debug('DistSuitPlannerAI: battle removed')
self.battleList.remove(currBattle)
else:
currBattleIdx = currBattleIdx + 1
return None
def __suitCanJoinBattle(self, zoneId):
battle = self.battleMgr.getBattle(zoneId)
if len(battle.suits) >= 4:
return 0
if battle:
if simbase.config.GetBool('suits-always-join', 0):
return 1
jChanceList = self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_JCHANCE]
ratioIdx = len(battle.toons) - battle.numSuitsEver + 2
if ratioIdx >= 0:
if ratioIdx < len(jChanceList):
if random.randint(0, 99) < jChanceList[ratioIdx]:
return 1
else:
self.notify.warning('__suitCanJoinBattle idx out of range!')
return 1
return 0
def checkForBattle(self, zoneId, suit):
if self.battleMgr.cellHasBattle(zoneId):
if self.__suitCanJoinBattle(zoneId) and self.battleMgr.requestBattleAddSuit(zoneId, suit):
pass
else:
suit.flyAwayNow()
return 1
else:
return 0
def postBattleResumeCheck(self, suit):
self.notify.debug('DistSuitPlannerAI:postBattleResumeCheck: suit ' + str(suit.getDoId()) + ' is leaving battle')
battleIndex = 0
for currBattle in self.battleList:
if suit.zoneId == currBattle[0]:
self.notify.debug(' battle found' + str(suit.zoneId))
for currPath in currBattle[1]:
for currPathPtSuit in range(suit.currWpt, suit.myPath.getNumPoints()):
ptIdx = suit.myPath.getPointIndex(currPathPtSuit)
if self.notify.getDebug():
self.notify.debug(' comparing' + str(ptIdx) + 'with' + str(currPath))
if currPath == ptIdx:
if self.notify.getDebug():
self.notify.debug(' match found, telling' + 'suit to fly')
return 0
else:
battleIndex = battleIndex + 1
pointList = []
for currPathPtSuit in range(suit.currWpt, suit.myPath.getNumPoints()):
ptIdx = suit.myPath.getPointIndex(currPathPtSuit)
if self.notify.getDebug():
self.notify.debug(' appending point with index of' + str(ptIdx))
pointList.append(ptIdx)
self.battleList.append([suit.zoneId, pointList])
return 1
def zoneChange(self, suit, oldZone, newZone=None):
if oldZone in self.zoneInfo and suit in self.zoneInfo[oldZone]:
self.zoneInfo[oldZone].remove(suit)
if newZone != None:
if newZone not in self.zoneInfo:
self.zoneInfo[newZone] = []
self.zoneInfo[newZone].append(suit)
return
def d_setZoneId(self, zoneId):
self.sendUpdate('setZoneId', [self.getZoneId()])
def getZoneId(self):
return self.zoneId
def suitListQuery(self):
suitIndexList = []
for suit in self.suitList:
suitIndexList.append(SuitDNA.suitHeadTypes.index(suit.dna.name))
self.sendUpdateToAvatarId(self.air.getAvatarIdFromSender(), 'suitListResponse', [suitIndexList])
def buildingListQuery(self):
buildingDict = {}
self.countNumBuildingsPerTrack(buildingDict)
buildingList = [0, 0, 0, 0]
for dept in SuitDNA.suitDepts:
if dept in buildingDict:
buildingList[SuitDNA.suitDepts.index(dept)] = buildingDict[dept]
self.sendUpdateToAvatarId(self.air.getAvatarIdFromSender(), 'buildingListResponse', [buildingList])
def pickLevelTypeAndTrack(self, level=None, type=None, track=None):
if level == None:
level = random.choice(self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_LVL])
if type == None:
typeChoices = list(range(max(level - 4, 1), min(level, self.MAX_SUIT_TYPES) + 1))
type = random.choice(typeChoices)
else:
level = min(max(level, type), type + 4)
if track == None:
track = SuitDNA.suitDepts[SuitBattleGlobals.pickFromFreqList(self.SuitHoodInfo[self.hoodInfoIdx][self.SUIT_HOOD_INFO_TRACK])]
self.notify.debug('pickLevelTypeAndTrack: %d %d %s' % (level, type, track))
return (
level, type, track)
@classmethod
def dump(cls):
s = ''
totalBldgs = 0
totalCogdos = 0
targetTotalBldgs = 0
targetTotalCogdos = 0
for index in range(len(cls.SuitHoodInfo)):
currHoodInfo = cls.SuitHoodInfo[index]
zoneId, min, max, bmin, bmax, bweight, smax, jchance, track, lvl, heights = currHoodInfo
sp = simbase.air.suitPlanners[zoneId]
targetCogdos = sp.targetNumCogdos
targetBldgs = sp.targetNumSuitBuildings
bm = simbase.air.buildingManagers.get(zoneId)
if bm:
numCogdos = len(bm.getCogdoBlocks())
numBldgs = len(bm.getSuitBlocks()) - numCogdos
s += ' %s: %2s/%2s buildings, %2s/%2s cogdos\n' % (zoneId, numBldgs, targetBldgs, numCogdos, targetCogdos)
totalBldgs += numBldgs
totalCogdos += numCogdos
targetTotalBldgs += targetBldgs
targetTotalCogdos += targetCogdos
header = '%s\n' % (cls.__name__,)
header += ' %s/%s buildings, %s/%s cogdos\n' % (totalBldgs, targetTotalBldgs, totalCogdos, targetTotalCogdos)
s = header + s
print(s)