open-toontown/toontown/building/DistributedBuildingAI.py

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
#