955 lines
38 KiB
Python
955 lines
38 KiB
Python
""" DistributedBuildingAI module: contains the DistributedBuildingAI
|
|
class, the server side representation of a 'building'."""
|
|
|
|
|
|
from otp.ai.AIBaseGlobal import *
|
|
from direct.distributed.ClockDelta import *
|
|
|
|
import types
|
|
from direct.task.Task import Task
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed import DistributedObjectAI
|
|
from direct.fsm import State
|
|
from direct.fsm import ClassicFSM, State
|
|
from toontown.toonbase.ToontownGlobals import ToonHall
|
|
from . import DistributedToonInteriorAI
|
|
from . import DistributedToonHallInteriorAI
|
|
from . import DistributedSuitInteriorAI
|
|
from . import DistributedDoorAI
|
|
from . import DoorTypes
|
|
from . import DistributedElevatorExtAI
|
|
from . import DistributedKnockKnockDoorAI
|
|
from . import SuitPlannerInteriorAI
|
|
from . import SuitBuildingGlobals
|
|
from . import FADoorCodes
|
|
from toontown.hood import ZoneUtil
|
|
import random
|
|
import time
|
|
from toontown.cogdominium.DistributedCogdoInteriorAI import DistributedCogdoInteriorAI
|
|
from toontown.cogdominium.SuitPlannerCogdoInteriorAI import SuitPlannerCogdoInteriorAI
|
|
from toontown.cogdominium.CogdoLayout import CogdoLayout
|
|
from toontown.cogdominium.DistributedCogdoElevatorExtAI import DistributedCogdoElevatorExtAI
|
|
|
|
class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
|
|
"""
|
|
DistributedBuildingAI class: The server side representation of a
|
|
single building. This is the object that remember who 'owns' the
|
|
associated building (either the bad guys or the toons). The child
|
|
of this object, the DistributedBuilding object, is the client side
|
|
version and updates the display that client's display based on who
|
|
'owns' the building.
|
|
"""
|
|
|
|
if __debug__:
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBuildingAI')
|
|
|
|
FieldOfficeNumFloors = 1
|
|
|
|
def __init__(self, air, blockNumber, zoneId, trophyMgr):
|
|
"""blockNumber: the landmark building number (from the name)"""
|
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
|
self.block = blockNumber
|
|
assert(self.debugPrint("DistributedBuildingAI(%s, %s)" % ("the air", str(blockNumber))))
|
|
self.zoneId = zoneId
|
|
self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
|
|
self.trophyMgr = trophyMgr
|
|
self.victorResponses = None
|
|
self.fsm = ClassicFSM.ClassicFSM('DistributedBuildingAI',
|
|
[State.State('off',
|
|
self.enterOff,
|
|
self.exitOff,
|
|
['waitForVictors',
|
|
'becomingToon',
|
|
'toon',
|
|
'clearOutToonInterior',
|
|
'becomingSuit',
|
|
'suit',
|
|
'clearOutToonInteriorForCogdo',
|
|
'becomingCogdo',
|
|
'becomingCogdoFromCogdo',
|
|
'cogdo',
|
|
]),
|
|
State.State('waitForVictors',
|
|
self.enterWaitForVictors,
|
|
self.exitWaitForVictors,
|
|
['becomingToon',
|
|
]),
|
|
State.State('waitForVictorsFromCogdo',
|
|
self.enterWaitForVictorsFromCogdo,
|
|
self.exitWaitForVictorsFromCogdo,
|
|
['becomingToonFromCogdo',
|
|
'becomingCogdoFromCogdo'
|
|
]),
|
|
State.State('becomingToon',
|
|
self.enterBecomingToon,
|
|
self.exitBecomingToon,
|
|
['toon']),
|
|
State.State('becomingToonFromCogdo',
|
|
self.enterBecomingToonFromCogdo,
|
|
self.exitBecomingToonFromCogdo,
|
|
['toon']),
|
|
State.State('toon',
|
|
self.enterToon,
|
|
self.exitToon,
|
|
['clearOutToonInterior', 'clearOutToonInteriorForCogdo']),
|
|
State.State('clearOutToonInterior',
|
|
self.enterClearOutToonInterior,
|
|
self.exitClearOutToonInterior,
|
|
['becomingSuit']),
|
|
State.State('becomingSuit',
|
|
self.enterBecomingSuit,
|
|
self.exitBecomingSuit,
|
|
['suit']),
|
|
State.State('suit',
|
|
self.enterSuit,
|
|
self.exitSuit,
|
|
['waitForVictors',
|
|
'becomingToon', # debug only
|
|
]),
|
|
State.State('clearOutToonInteriorForCogdo',
|
|
self.enterClearOutToonInteriorForCogdo,
|
|
self.exitClearOutToonInteriorForCogdo,
|
|
['becomingCogdo']),
|
|
State.State('becomingCogdo',
|
|
self.enterBecomingCogdo,
|
|
self.exitBecomingCogdo,
|
|
['cogdo']),
|
|
State.State('becomingCogdoFromCogdo',
|
|
self.enterBecomingCogdoFromCogdo,
|
|
self.exitBecomingCogdoFromCogdo,
|
|
['cogdo']),
|
|
State.State('cogdo',
|
|
self.enterCogdo,
|
|
self.exitCogdo,
|
|
['waitForVictorsFromCogdo',
|
|
'becomingToonFromCogdo', # debug only
|
|
])],
|
|
# Initial State
|
|
'off',
|
|
# Final State
|
|
'off',
|
|
)
|
|
self.fsm.enterInitialState()
|
|
self.track='c'
|
|
self.difficulty=1
|
|
self.numFloors=0
|
|
self.savedBy=None
|
|
self.becameSuitTime=0
|
|
self.frontDoorPoint=None
|
|
self.suitPlannerExt=None
|
|
self.fSkipElevatorOpening = False
|
|
|
|
def cleanup(self):
|
|
if self.isDeleted():
|
|
return
|
|
|
|
self.fsm.requestFinalState()
|
|
|
|
if hasattr(self, "interior"):
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
|
|
if hasattr(self, "door"):
|
|
self.door.requestDelete()
|
|
del self.door
|
|
self.insideDoor.requestDelete()
|
|
del self.insideDoor
|
|
self.knockKnock.requestDelete()
|
|
del self.knockKnock
|
|
|
|
if hasattr(self, "elevator"):
|
|
self.elevator.requestDelete()
|
|
del self.elevator
|
|
|
|
self.requestDelete()
|
|
|
|
|
|
def delete( self ):
|
|
"""
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: clean up tasks that might still be running for this
|
|
// building
|
|
// Parameters:
|
|
// Changes:
|
|
////////////////////////////////////////////////////////////////////
|
|
"""
|
|
# make sure to remove any tasks we might have created
|
|
taskMgr.remove(self.taskName('suitbldg-time-out'))
|
|
|
|
# remove the doLater associated with the state transition of
|
|
# a suit building becoming a toon building
|
|
taskMgr.remove(self.taskName(str(self.block) + '_becomingToon-timer'))
|
|
|
|
# remove the doLater associated with the state transition of
|
|
# a toon building becoming a suit building
|
|
taskMgr.remove(self.taskName(str(self.block) + '_becomingSuit-timer'))
|
|
|
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
|
|
|
del self.fsm
|
|
|
|
def getPickleData(self):
|
|
assert(self.debugPrint("getPickleData()"))
|
|
pickleData={
|
|
'state': str(self.fsm.getCurrentState().getName()),
|
|
'block': str(self.block),
|
|
'track': str(self.track),
|
|
'difficulty': str(self.difficulty),
|
|
'numFloors': str(self.numFloors),
|
|
'savedBy': self.savedBy,
|
|
'becameSuitTime' : self.becameSuitTime,
|
|
}
|
|
return pickleData
|
|
|
|
def _getMinMaxFloors(self, difficulty):
|
|
return SuitBuildingGlobals.SuitBuildingInfo[difficulty][0]
|
|
|
|
def suitTakeOver(self, suitTrack, difficulty, buildingHeight):
|
|
"""Switch from toon to suit building
|
|
suitTrack: one of 'c', 'l', 'm', or 's'
|
|
difficulty: 0+
|
|
buildingHeight: 0..4, or None to choose based on the difficulty.
|
|
"""
|
|
if not self.isToonBlock():
|
|
return
|
|
assert(suitTrack in ['c', 'l', 'm', 's'])
|
|
|
|
# Remove the old saved by credit with the old number of floors
|
|
self.updateSavedBy(None)
|
|
|
|
difficulty = min(difficulty, len(SuitBuildingGlobals.SuitBuildingInfo) - 1)
|
|
minFloors, maxFloors = self._getMinMaxFloors(difficulty)
|
|
if buildingHeight == None:
|
|
# Pick a random floor number from the appropriate range.
|
|
numFloors = random.randint(minFloors, maxFloors)
|
|
else:
|
|
# The number of floors is specified.
|
|
numFloors = buildingHeight + 1
|
|
|
|
if (numFloors < minFloors or numFloors > maxFloors):
|
|
# Hmm, the number of floors is out of range for this
|
|
# suit. There must be an invasion in effect. In that
|
|
# case, go ahead and make a building of any height
|
|
# appropriate to the suit.
|
|
numFloors = random.randint(minFloors, maxFloors)
|
|
|
|
assert(self.debugPrint("suitTakeOver(%s, %s, %s)" % (suitTrack, difficulty, numFloors - 1)))
|
|
|
|
self.track=suitTrack
|
|
self.difficulty=difficulty
|
|
self.numFloors=numFloors
|
|
self.becameSuitTime = time.time()
|
|
self.fsm.request('clearOutToonInterior')
|
|
|
|
def cogdoTakeOver(self, suitTrack, difficulty, buildingHeight):
|
|
if not self.isToonBlock():
|
|
return
|
|
|
|
# Remove the old saved by credit with the old number of floors
|
|
self.updateSavedBy(None)
|
|
|
|
numFloors = self.FieldOfficeNumFloors
|
|
|
|
assert(self.debugPrint("cogdoTakeOver(%s, %s)" % (difficulty, numFloors - 1)))
|
|
|
|
self.track = suitTrack
|
|
self.difficulty=difficulty
|
|
self.numFloors=numFloors
|
|
self.becameSuitTime = time.time()
|
|
self.fsm.request('clearOutToonInteriorForCogdo')
|
|
|
|
def toonTakeOver(self):
|
|
"""Switch from suit to toon building
|
|
savedBy: a list of 1 to 4 avatar [name, style] lists."""
|
|
assert(self.debugPrint("toonTakeOver(savedBy=%s)"%(self.savedBy)))
|
|
isCogdo = 'cogdo' in self.fsm.getCurrentState().getName().lower()
|
|
takenOver = True
|
|
if isCogdo:
|
|
if self.buildingDefeated:
|
|
self.fsm.request('becomingToonFromCogdo')
|
|
else:
|
|
self.fsm.request('becomingCogdoFromCogdo')
|
|
takenOver = False
|
|
else:
|
|
self.fsm.request('becomingToon')
|
|
if takenOver and self.suitPlannerExt:
|
|
self.suitPlannerExt.recycleBuilding(isCogdo)
|
|
if hasattr(self, "interior"):
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
|
|
def getFrontDoorPoint(self):
|
|
"""get any associated path point for this building, useful for
|
|
suits to know where to go when exiting from a building"""
|
|
assert(self.debugPrint("getFrontDoorPoint()"))
|
|
return self.frontDoorPoint
|
|
|
|
def setFrontDoorPoint(self, point):
|
|
"""set the associated front door point with this building"""
|
|
assert(self.debugPrint("setFrontDoorPoint(%s)" % (str(point))))
|
|
self.frontDoorPoint = point
|
|
|
|
def getBlock(self):
|
|
assert(self.debugPrint("getBlock()"))
|
|
dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
|
|
return [self.block, interiorZoneId]
|
|
|
|
def getSuitData(self):
|
|
assert(self.debugPrint("getSuitData()"))
|
|
return [ord(self.track), self.difficulty, self.numFloors]
|
|
|
|
def getState(self):
|
|
assert(self.debugPrint("getState()"))
|
|
return [self.fsm.getCurrentState().getName(),
|
|
globalClockDelta.getRealNetworkTime()]
|
|
|
|
def setState(self, state, timestamp=0):
|
|
assert(self.notify.debug(str(self.block)+" setState(state="+str(state)+")"))
|
|
self.fsm.request(state)
|
|
|
|
def isSuitBuilding(self):
|
|
"""return true if that block is a suit building"""
|
|
assert(self.debugPrint("isSuitBlock()"))
|
|
state=self.fsm.getCurrentState().getName()
|
|
return state=='suit' or state=='becomingSuit' or \
|
|
state=='clearOutToonInterior'
|
|
|
|
def isCogdo(self):
|
|
"""return true if that block is a cogdo"""
|
|
assert(self.debugPrint("isSuitBlock()"))
|
|
state=self.fsm.getCurrentState().getName()
|
|
return state=='cogdo' or state=='becomingCogdo' or \
|
|
state=='becomingCogdoFromCogdo' or state=='clearOutToonInteriorForCogdo'
|
|
|
|
def isSuitBlock(self):
|
|
"""return true if that block is a suit block/building/cogdo"""
|
|
assert(self.debugPrint("isSuitBlock()"))
|
|
state=self.fsm.getCurrentState().getName()
|
|
return self.isSuitBuilding() or self.isCogdo()
|
|
|
|
def isEstablishedSuitBlock(self):
|
|
"""return true if that block is a fully established suit building"""
|
|
assert(self.debugPrint("isEstablishedSuitBlock()"))
|
|
state=self.fsm.getCurrentState().getName()
|
|
return state=='suit'
|
|
|
|
def isToonBlock(self):
|
|
"""return true if that block is a toon block/building"""
|
|
assert(self.debugPrint("isToonBlock()"))
|
|
state=self.fsm.getCurrentState().getName()
|
|
return state in ('toon', 'becomingToon', 'becomingToonFromCogdo', )
|
|
|
|
def getExteriorAndInteriorZoneId(self):
|
|
assert(self.notify.debug(str(self.block)+" getInteriorZoneId()"))
|
|
blockNumber = self.block
|
|
assert(blockNumber<100) # this may cause trouble for the interiorZoneId,
|
|
# it may bump into the next higher zone range.
|
|
dnaStore = self.air.dnaStoreMap[self.canonicalZoneId]
|
|
zoneId = dnaStore.getZoneFromBlockNumber(blockNumber)
|
|
zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
|
|
interiorZoneId = (zoneId - zoneId % 100) + 500 + blockNumber
|
|
assert(self.notify.debug(str(self.block)+" getInteriorZoneId() returning"
|
|
+str(interiorZoneId)))
|
|
return zoneId, interiorZoneId
|
|
|
|
def d_setState(self, state):
|
|
assert(self.notify.debug(str(self.block)+" d_setState(state="+str(state)+")"))
|
|
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
|
|
|
|
def b_setVictorList(self, victorList):
|
|
self.setVictorList(victorList)
|
|
self.d_setVictorList(victorList)
|
|
return
|
|
|
|
def d_setVictorList(self, victorList):
|
|
self.sendUpdate("setVictorList", [victorList])
|
|
return
|
|
|
|
def setVictorList(self, victorList):
|
|
self.victorList = victorList
|
|
return
|
|
|
|
def findVictorIndex(self, avId):
|
|
for i in range(len(self.victorList)):
|
|
if self.victorList[i] == avId:
|
|
return i
|
|
return None
|
|
|
|
def recordVictorResponse(self, avId):
|
|
index = self.findVictorIndex(avId)
|
|
if index == None:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedBuildingAI.setVictorReady from toon not in %s.' % (self.victorList))
|
|
return
|
|
|
|
assert(self.victorResponses[index] == 0 or self.victorResponses[index] == avId)
|
|
self.victorResponses[index] = avId
|
|
|
|
def allVictorsResponded(self):
|
|
if self.victorResponses == self.victorList:
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
def setVictorReady(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if self.victorResponses == None:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedBuildingAI.setVictorReady in state %s.' % (self.fsm.getCurrentState().getName()))
|
|
return
|
|
|
|
# Don't tell us about this avatar exiting any more.
|
|
event = self.air.getAvatarExitEvent(avId)
|
|
self.ignore(event)
|
|
|
|
if self.allVictorsResponded():
|
|
return
|
|
|
|
assert(self.notify.debug("victor %d is ready for bldg %d" % (avId, self.doId)))
|
|
self.recordVictorResponse(avId)
|
|
|
|
if self.allVictorsResponded():
|
|
self.toonTakeOver()
|
|
|
|
def setVictorExited(self, avId):
|
|
print("victor %d exited unexpectedly for bldg %d" % (avId, self.doId))
|
|
self.recordVictorResponse(avId)
|
|
if self.allVictorsResponded():
|
|
self.toonTakeOver()
|
|
|
|
def victorsTimedOutTask(self, task):
|
|
if self.allVictorsResponded():
|
|
return
|
|
if hasattr(self, 'interior'):
|
|
self.notify.info('victorsTimedOutTask: ejecting players by deleting interior.')
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
task.delayTime = 15.0
|
|
return task.again
|
|
self.notify.info('victorsTimedOutTask: suspicious players remaining, advancing state.')
|
|
for i in range(len(self.victorList)):
|
|
if self.victorList[i] and self.victorResponses[i] == 0:
|
|
self.air.writeServerEvent('suspicious', self.victorList[i], 'DistributedBuildingAI toon client refused to leave building.')
|
|
self.recordVictorResponse(self.victorList[i])
|
|
event = self.air.getAvatarExitEvent(self.victorList[i])
|
|
self.ignore(event)
|
|
|
|
self.toonTakeOver()
|
|
return Task.done
|
|
|
|
##### off state #####
|
|
|
|
def enterOff(self):
|
|
assert(self.debugPrint("enterOff()"))
|
|
|
|
def exitOff(self):
|
|
assert(self.debugPrint("exitOff()"))
|
|
|
|
##### waitForVictors state #####
|
|
|
|
def getToon(self, toonId):
|
|
if (toonId in self.air.doId2do):
|
|
return self.air.doId2do[toonId]
|
|
else:
|
|
self.notify.warning('getToon() - toon: %d not in repository!' \
|
|
% toonId)
|
|
return None
|
|
|
|
def updateSavedBy(self, savedBy):
|
|
# Clear the old savedBy from the trophy manager
|
|
if self.savedBy:
|
|
for avId, name, dna in self.savedBy:
|
|
# Don't change building take over score when the toon is in the welcome valley.
|
|
if not ZoneUtil.isWelcomeValley(self.zoneId):
|
|
self.trophyMgr.removeTrophy(avId, self.numFloors)
|
|
# Update the new saved by list
|
|
self.savedBy = savedBy
|
|
if self.savedBy:
|
|
for avId, name, dna in self.savedBy:
|
|
# Don't change building take over score when the toon is in the welcome valley.
|
|
if not ZoneUtil.isWelcomeValley(self.zoneId):
|
|
self.trophyMgr.addTrophy(avId, name, self.numFloors)
|
|
|
|
def enterWaitForVictors(self, victorList, savedBy):
|
|
assert(len(victorList) == 4)
|
|
|
|
# Grab the list of active toons to pass in for each toon
|
|
# (this is used by the quest system)
|
|
activeToons = []
|
|
for t in victorList:
|
|
toon = None
|
|
if (t):
|
|
toon = self.getToon(t)
|
|
if (toon != None):
|
|
activeToons.append(toon)
|
|
# Tell the quest manager that these toons defeated this building
|
|
for t in victorList:
|
|
toon = None
|
|
if t:
|
|
toon = self.getToon(t)
|
|
self.air.writeServerEvent(
|
|
'buildingDefeated', t, "%s|%s|%s|%s" % (self.track, self.numFloors, self.zoneId, victorList))
|
|
|
|
if toon != None:
|
|
self.air.questManager.toonKilledBuilding(
|
|
toon, self.track, self.difficulty,
|
|
self.numFloors, self.zoneId, activeToons)
|
|
|
|
# Convert the list to all ints. 0 means no one is there.
|
|
# Also, if a toon has disconnected, remove him from the list.
|
|
for i in range(0, 4):
|
|
victor = victorList[i]
|
|
if victor == None or victor not in self.air.doId2do:
|
|
victorList[i] = 0
|
|
|
|
else:
|
|
# Handle unexpected exit messages for everyone else.
|
|
event = self.air.getAvatarExitEvent(victor)
|
|
self.accept(event, self.setVictorExited, extraArgs=[victor])
|
|
|
|
# Save the list and also tell it to all the clients.
|
|
self.b_setVictorList(victorList)
|
|
self.updateSavedBy(savedBy)
|
|
# List of victor responses
|
|
self.victorResponses = [0, 0, 0, 0]
|
|
# Tell the client to go into waitForVictors state
|
|
self.d_setState("waitForVictors")
|
|
return
|
|
|
|
def exitWaitForVictors(self):
|
|
# Stop waiting for unexpected exits.
|
|
self.victorResponses = None
|
|
for victor in self.victorList:
|
|
event = simbase.air.getAvatarExitEvent(victor)
|
|
self.ignore(event)
|
|
return
|
|
|
|
def enterWaitForVictorsFromCogdo(self, victorList, savedBy):
|
|
assert(len(victorList) == 4)
|
|
|
|
# Grab the list of active toons to pass in for each toon
|
|
# (this is used by the quest system)
|
|
activeToons = []
|
|
for t in victorList:
|
|
toon = None
|
|
if (t):
|
|
toon = self.getToon(t)
|
|
if (toon != None):
|
|
activeToons.append(toon)
|
|
# Tell the quest manager that these toons defeated this building
|
|
self.buildingDefeated = len(savedBy) > 0
|
|
if self.buildingDefeated:
|
|
for t in victorList:
|
|
toon = None
|
|
if t:
|
|
toon = self.getToon(t)
|
|
self.air.writeServerEvent(
|
|
'buildingDefeated', t, "%s|%s|%s|%s" % (self.track, self.numFloors, self.zoneId, victorList))
|
|
|
|
if toon != None:
|
|
self.air.questManager.toonKilledCogdo(
|
|
toon, self.difficulty,
|
|
self.numFloors, self.zoneId, activeToons)
|
|
|
|
# Convert the list to all ints. 0 means no one is there.
|
|
# Also, if a toon has disconnected, remove him from the list.
|
|
for i in range(0, 4):
|
|
victor = victorList[i]
|
|
if victor == None or victor not in self.air.doId2do:
|
|
victorList[i] = 0
|
|
|
|
else:
|
|
# Handle unexpected exit messages for everyone else.
|
|
event = self.air.getAvatarExitEvent(victor)
|
|
self.accept(event, self.setVictorExited, extraArgs=[victor])
|
|
|
|
# Save the list and also tell it to all the clients.
|
|
self.b_setVictorList(victorList)
|
|
self.updateSavedBy(savedBy)
|
|
# List of victor responses
|
|
self.victorResponses = [0, 0, 0, 0]
|
|
taskMgr.doMethodLater(30, self.victorsTimedOutTask, self.taskName(str(self.block) + '_waitForVictors-timer'))
|
|
# Tell the client to go into waitForVictors state
|
|
self.d_setState("waitForVictorsFromCogdo")
|
|
return
|
|
|
|
def exitWaitForVictorsFromCogdo(self):
|
|
taskMgr.remove(self.taskName(str(self.block) + '_waitForVictors-timer'))
|
|
# Stop waiting for unexpected exits.
|
|
self.victorResponses = None
|
|
for victor in self.victorList:
|
|
event = simbase.air.getAvatarExitEvent(victor)
|
|
self.ignore(event)
|
|
return
|
|
|
|
##### becomingToon state #####
|
|
|
|
def enterBecomingToon(self):
|
|
assert(self.debugPrint("enterBecomingToon()"))
|
|
self.d_setState('becomingToon')
|
|
name = self.taskName(str(self.block)+'_becomingToon-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
|
|
self.becomingToonTask,
|
|
name)
|
|
|
|
def exitBecomingToon(self):
|
|
assert(self.debugPrint("exitBecomingToon()"))
|
|
name = self.taskName(str(self.block)+'_becomingToon-timer')
|
|
taskMgr.remove(name)
|
|
|
|
##### becomingToonFromCogdo state #####
|
|
|
|
def enterBecomingToonFromCogdo(self):
|
|
assert(self.debugPrint("enterBecomingToonFromCogdo()"))
|
|
self.d_setState('becomingToonFromCogdo')
|
|
name = self.taskName(str(self.block)+'_becomingToonFromCogdo-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
|
|
self.becomingToonTask,
|
|
name)
|
|
|
|
def exitBecomingToonFromCogdo(self):
|
|
assert(self.debugPrint("exitBecomingToonFromCogdo()"))
|
|
name = self.taskName(str(self.block)+'_becomingToonFromCogdo-timer')
|
|
taskMgr.remove(name)
|
|
|
|
##### toon state #####
|
|
|
|
def becomingToonTask(self, task):
|
|
assert(self.debugPrint("becomingToonTask()"))
|
|
self.fsm.request("toon")
|
|
|
|
# Save the building state whenever we convert a building to
|
|
# toonness.
|
|
self.suitPlannerExt.buildingMgr.save()
|
|
|
|
return Task.done
|
|
|
|
def enterToon(self):
|
|
assert(self.debugPrint("enterToon()"))
|
|
self.d_setState('toon')
|
|
# Create the DistributedDoor:
|
|
exteriorZoneId, interiorZoneId=self.getExteriorAndInteriorZoneId()
|
|
# Toon interior:
|
|
if simbase.config.GetBool("want-new-toonhall",1) and \
|
|
ZoneUtil.getCanonicalZoneId(interiorZoneId)== ToonHall:
|
|
self.interior=DistributedToonHallInteriorAI.DistributedToonHallInteriorAI(
|
|
self.block, self.air, interiorZoneId, self)
|
|
else:
|
|
self.interior=DistributedToonInteriorAI.DistributedToonInteriorAI(
|
|
self.block, self.air, interiorZoneId, self)
|
|
self.interior.generateWithRequired(interiorZoneId)
|
|
|
|
# Outside door:
|
|
door=self.createExteriorDoor()
|
|
# Inside of the same door (different zone, and different distributed object):
|
|
insideDoor=DistributedDoorAI.DistributedDoorAI(self.air, self.block,
|
|
DoorTypes.INT_STANDARD)
|
|
# Tell them about each other:
|
|
door.setOtherDoor(insideDoor)
|
|
insideDoor.setOtherDoor(door)
|
|
door.zoneId=exteriorZoneId
|
|
insideDoor.zoneId=interiorZoneId
|
|
# Now that they both now about each other, generate them:
|
|
door.generateWithRequired(exteriorZoneId)
|
|
insideDoor.generateWithRequired(interiorZoneId)
|
|
# keep track of them:
|
|
self.door=door
|
|
self.insideDoor=insideDoor
|
|
self.becameSuitTime = 0
|
|
|
|
self.knockKnock=DistributedKnockKnockDoorAI.DistributedKnockKnockDoorAI(
|
|
self.air, self.block)
|
|
self.knockKnock.generateWithRequired(exteriorZoneId)
|
|
|
|
self.air.writeServerEvent(
|
|
'building-toon', self.doId,
|
|
"%s|%s" % (self.zoneId, self.block))
|
|
|
|
def createExteriorDoor(self):
|
|
"""Return the DistributedDoor for the exterior, with correct door type set"""
|
|
# Created so animated buildings can over ride this function
|
|
result = DistributedDoorAI.DistributedDoorAI(self.air, self.block,
|
|
DoorTypes.EXT_STANDARD)
|
|
return result
|
|
|
|
def exitToon(self):
|
|
assert(self.debugPrint("exitToon()"))
|
|
self.door.setDoorLock(FADoorCodes.BUILDING_TAKEOVER)
|
|
# The door doesn't get unlocked, because
|
|
# it will be distroyed and recreated.
|
|
|
|
##### clearOutToonInterior state #####
|
|
|
|
def enterClearOutToonInterior(self):
|
|
assert(self.debugPrint("enterClearOutToonInterior()"))
|
|
self.d_setState('clearOutToonInterior')
|
|
if hasattr(self, "interior"):
|
|
self.interior.setState("beingTakenOver")
|
|
name = self.taskName(str(self.block)+'_clearOutToonInterior-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
|
|
self.clearOutToonInteriorTask,
|
|
name)
|
|
|
|
def exitClearOutToonInterior(self):
|
|
assert(self.debugPrint("exitClearOutToonInterior()"))
|
|
name = self.taskName(str(self.block)+'_clearOutToonInterior-timer')
|
|
taskMgr.remove(name)
|
|
|
|
##### becomingSuit state #####
|
|
|
|
def clearOutToonInteriorTask(self, task):
|
|
assert(self.debugPrint("clearOutToonInteriorTask()"))
|
|
self.fsm.request("becomingSuit")
|
|
return Task.done
|
|
|
|
def enterBecomingSuit(self):
|
|
assert(self.debugPrint("enterBecomingSuit()"))
|
|
|
|
# We have to send this message before we send the distributed
|
|
# update to becomingSuit state, because the clients depend on
|
|
# knowing what kind of suit building we're becoming.
|
|
self.sendUpdate('setSuitData',
|
|
[ord(self.track), self.difficulty, self.numFloors])
|
|
|
|
self.d_setState('becomingSuit')
|
|
name = self.taskName(str(self.block)+'_becomingSuit-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
|
|
self.becomingSuitTask,
|
|
name)
|
|
|
|
def exitBecomingSuit(self):
|
|
assert(self.debugPrint("exitBecomingSuit()"))
|
|
name = self.taskName(str(self.block)+'_becomingSuit-timer')
|
|
taskMgr.remove(name)
|
|
# Clean up the toon distributed objects:
|
|
if hasattr(self, "interior"):
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
self.door.requestDelete()
|
|
del self.door
|
|
self.insideDoor.requestDelete()
|
|
del self.insideDoor
|
|
self.knockKnock.requestDelete()
|
|
del self.knockKnock
|
|
|
|
##### suit state #####
|
|
|
|
def becomingSuitTask(self, task):
|
|
assert(self.debugPrint("becomingSuitTask()"))
|
|
self.fsm.request("suit")
|
|
|
|
# Save the building state whenever we convert a building to
|
|
# suitness.
|
|
self.suitPlannerExt.buildingMgr.save()
|
|
|
|
return Task.done
|
|
|
|
def enterSuit(self):
|
|
assert(self.debugPrint("enterSuit()"))
|
|
|
|
# We have to send this message again, even though we've
|
|
# already sent it in becomingSuit, because we might have come
|
|
# to this state directly on startup.
|
|
self.sendUpdate('setSuitData',
|
|
[ord(self.track), self.difficulty, self.numFloors])
|
|
|
|
# Create the suit planner for the interior
|
|
zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
|
|
self.planner = SuitPlannerInteriorAI.SuitPlannerInteriorAI(
|
|
self.numFloors, self.difficulty, self.track, interiorZoneId)
|
|
|
|
self.d_setState('suit')
|
|
# Create the DistributedDoor:
|
|
exteriorZoneId, interiorZoneId=self.getExteriorAndInteriorZoneId()
|
|
#todo: ...create the elevator.
|
|
self.elevator = DistributedElevatorExtAI.DistributedElevatorExtAI(
|
|
self.air,
|
|
self)
|
|
self.elevator.generateWithRequired(exteriorZoneId)
|
|
|
|
self.air.writeServerEvent(
|
|
'building-cog', self.doId,
|
|
"%s|%s|%s|%s" % (self.zoneId, self.block, self.track, self.numFloors))
|
|
|
|
def exitSuit(self):
|
|
assert(self.debugPrint("exitSuit()"))
|
|
del self.planner
|
|
# Clean up the suit distributed objects:
|
|
if hasattr(self, "elevator"):
|
|
self.elevator.requestDelete()
|
|
del self.elevator
|
|
|
|
##### clearOutToonInteriorForCogdo state #####
|
|
|
|
def enterClearOutToonInteriorForCogdo(self):
|
|
assert(self.debugPrint("enterClearOutToonInteriorForCogdo()"))
|
|
self.d_setState('clearOutToonInteriorForCogdo')
|
|
if hasattr(self, "interior"):
|
|
self.interior.setState("beingTakenOver")
|
|
name = self.taskName(str(self.block)+'_clearOutToonInteriorForCogdo-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
|
|
self.clearOutToonInteriorForCogdoTask,
|
|
name)
|
|
|
|
def exitClearOutToonInteriorForCogdo(self):
|
|
assert(self.debugPrint("exitClearOutToonInteriorForCogdo()"))
|
|
name = self.taskName(str(self.block)+'_clearOutToonInteriorForCogdo-timer')
|
|
taskMgr.remove(name)
|
|
|
|
##### becomingCogdo state #####
|
|
|
|
def clearOutToonInteriorForCogdoTask(self, task):
|
|
assert(self.debugPrint("clearOutToonInteriorForCogdoTask()"))
|
|
self.fsm.request("becomingCogdo")
|
|
return Task.done
|
|
|
|
def enterBecomingCogdo(self):
|
|
assert(self.debugPrint("enterBecomingCogdo()"))
|
|
|
|
# We have to send this message before we send the distributed
|
|
# update to becomingCogdo state, because the clients depend on
|
|
# knowing what kind of cogdo building we're becoming.
|
|
self.sendUpdate('setSuitData',
|
|
[ord(self.track), self.difficulty, self.numFloors])
|
|
|
|
self.d_setState('becomingCogdo')
|
|
name = self.taskName(str(self.block)+'_becomingCogdo-timer')
|
|
taskMgr.doMethodLater(
|
|
SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
|
|
self.becomingCogdoTask,
|
|
name)
|
|
|
|
def exitBecomingCogdo(self):
|
|
assert(self.debugPrint("exitBecomingCogdo()"))
|
|
name = self.taskName(str(self.block)+'_becomingCogdo-timer')
|
|
taskMgr.remove(name)
|
|
# Clean up the toon distributed objects:
|
|
if hasattr(self, "interior"):
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
self.door.requestDelete()
|
|
del self.door
|
|
self.insideDoor.requestDelete()
|
|
del self.insideDoor
|
|
self.knockKnock.requestDelete()
|
|
del self.knockKnock
|
|
|
|
##### becomingCogdoFromCogdo state #####
|
|
|
|
def enterBecomingCogdoFromCogdo(self):
|
|
self.d_setState('becomingCogdoFromCogdo')
|
|
name = self.taskName(str(self.block) + '_becomingCogdoFromCogdo-timer')
|
|
taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_RUN_TIME, self.becomingCogdoTask, name)
|
|
|
|
def exitBecomingCogdoFromCogdo(self):
|
|
self.fSkipElevatorOpening = True
|
|
name = self.taskName(str(self.block) + '_becomingCogdoFromCogdo-timer')
|
|
taskMgr.remove(name)
|
|
|
|
##### cogdo state #####
|
|
|
|
def becomingCogdoTask(self, task):
|
|
assert(self.debugPrint("becomingCogdoTask()"))
|
|
self.fsm.request("cogdo")
|
|
|
|
# Save the building state whenever we convert a building to
|
|
# cogdoness.
|
|
self.suitPlannerExt.buildingMgr.save()
|
|
|
|
return Task.done
|
|
|
|
def enterCogdo(self):
|
|
assert(self.debugPrint("enterCogdo()"))
|
|
|
|
# We have to send this message again, even though we've
|
|
# already sent it in becomingCogdo, because we might have come
|
|
# to this state directly on startup.
|
|
self.sendUpdate('setSuitData',
|
|
[ord(self.track), self.difficulty, self.numFloors])
|
|
|
|
# Create the suit planner for the interior
|
|
zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
|
|
self._cogdoLayout = CogdoLayout(self.numFloors)
|
|
self.planner = SuitPlannerCogdoInteriorAI(
|
|
self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
|
|
|
|
self.d_setState('cogdo')
|
|
# Create the DistributedDoor:
|
|
exteriorZoneId, interiorZoneId=self.getExteriorAndInteriorZoneId()
|
|
#todo: ...create the elevator.
|
|
self.elevator = DistributedCogdoElevatorExtAI(self.air, self, fSkipOpening=self.fSkipElevatorOpening)
|
|
self.fSkipElevatorOpening = False
|
|
self.elevator.generateWithRequired(exteriorZoneId)
|
|
|
|
self.air.writeServerEvent(
|
|
'building-cogdo', self.doId,
|
|
"%s|%s|%s" % (self.zoneId, self.block, self.numFloors))
|
|
|
|
def exitCogdo(self):
|
|
assert(self.debugPrint("exitCogdo()"))
|
|
del self.planner
|
|
# Clean up the cogdo distributed objects:
|
|
if hasattr(self, "elevator"):
|
|
self.elevator.requestDelete()
|
|
del self.elevator
|
|
|
|
def setSuitPlannerExt( self, planner ):
|
|
"""
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: let the building know which suit planner contains
|
|
// its building manager
|
|
// Parameters: planner, the governing suit planner for this bldg
|
|
// Changes:
|
|
////////////////////////////////////////////////////////////////////
|
|
"""
|
|
self.suitPlannerExt = planner
|
|
|
|
def _createSuitInterior(self):
|
|
return DistributedSuitInteriorAI.DistributedSuitInteriorAI(self.air, self.elevator)
|
|
|
|
def _createCogdoInterior(self):
|
|
return DistributedCogdoInteriorAI(self.air, self.elevator)
|
|
|
|
def createSuitInterior(self):
|
|
# Create a building interior in the new (interior) zone
|
|
self.interior = self._createSuitInterior()
|
|
dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
|
|
self.interior.fsm.request('WaitForAllToonsInside')
|
|
self.interior.generateWithRequired(interiorZoneId)
|
|
|
|
def createCogdoInterior(self):
|
|
# Create a building interior in the new (interior) zone
|
|
self.interior = self._createCogdoInterior()
|
|
dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
|
|
self.interior.fsm.request('WaitForAllToonsInside')
|
|
self.interior.generateWithRequired(interiorZoneId)
|
|
|
|
def deleteSuitInterior(self):
|
|
if hasattr(self, "interior"):
|
|
self.interior.requestDelete()
|
|
del self.interior
|
|
if hasattr(self, "elevator"):
|
|
# -1 means the lobby.
|
|
self.elevator.d_setFloor(-1)
|
|
self.elevator.open()
|
|
|
|
def deleteCogdoInterior(self):
|
|
self.deleteSuitInterior()
|
|
|
|
if __debug__:
|
|
def debugPrint(self, message):
|
|
"""for debugging"""
|
|
return self.notify.debug(
|
|
str(self.__dict__.get('block', '?'))+' '+message)
|
|
|
|
# history
|
|
#
|
|
# 10May01 jlbutler added frontDoorPoint to the building so a suit or
|
|
# the suit planner can get from a building to a suit
|
|
# path point which is in front of the building
|
|
#
|
|
|