Poodletooth-iLand/toontown/suit/DistributedSuitAI.py

370 lines
14 KiB
Python

from otp.ai.AIBaseGlobal import *
from panda3d.core import *
from direct.distributed.ClockDelta import *
from otp.avatar import DistributedAvatarAI
import SuitTimings
from direct.task import Task
import SuitPlannerBase
import SuitBase
import SuitDialog
import SuitDNA
from libpandadna import *
from direct.directnotify import DirectNotifyGlobal
from toontown.battle import SuitBattleGlobals
from toontown.building import FADoorCodes
import DistributedSuitBaseAI
from toontown.hood import ZoneUtil
from toontown.toon import NPCToons
import random
class DistributedSuitAI(DistributedSuitBaseAI.DistributedSuitBaseAI):
SUIT_BUILDINGS = simbase.config.GetBool('want-suit-buildings', 1)
DEBUG_SUIT_POSITIONS = simbase.config.GetBool('debug-suit-positions', 0)
UPDATE_TIMESTAMP_INTERVAL = 180.0
myId = 0
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSuitAI')
def __init__(self, air, suitPlanner):
DistributedSuitBaseAI.DistributedSuitBaseAI.__init__(self, air, suitPlanner)
self.bldgTrack = None
self.branchId = None
if suitPlanner:
self.branchId = suitPlanner.zoneId
self.pathEndpointStart = 0
self.pathEndpointEnd = 0
self.minPathLen = 0
self.maxPathLen = 0
self.pathPositionIndex = 0
self.pathPositionTimestamp = 0.0
self.pathState = 0
self.currentLeg = 0
self.legType = SuitLeg.TOff
self.flyInSuit = 0
self.buildingSuit = 0
self.attemptingTakeover = 0
self.buildingDestination = None
self.buildingDestinationIsCogdo = False
def delete(self):
del self.bldgTrack
del self.branchId
del self.buildingDestination
del self.buildingDestinationIsCogdo
DistributedSuitBaseAI.DistributedSuitBaseAI.delete(self)
def stopTasks(self):
taskMgr.remove(self.taskName('flyAwayNow'))
taskMgr.remove(self.taskName('danceNowFlyAwayLater'))
taskMgr.remove(self.taskName('move'))
def pointInMyPath(self, point, elapsedTime):
if self.pathState != 1:
return 0
then = globalClock.getFrameTime() + elapsedTime
elapsed = then - self.pathStartTime
if not self.sp:
pass
return self.legList.isPointInRange(point, elapsed - self.sp.PATH_COLLISION_BUFFER, elapsed + self.sp.PATH_COLLISION_BUFFER)
def requestBattle(self, x, y, z, h, p, r):
toonId = self.air.getAvatarIdFromSender()
if self.air.doId2do.get(toonId) == None:
return
if self.pathState == 3:
pass
elif self.pathState != 1:
if self.notify.getDebug():
self.notify.debug('requestBattle() - suit %s not on path' % self.getDoId())
if self.pathState == 2 or self.pathState == 4:
self.b_setBrushOff(SuitDialog.getBrushOffIndex(self.getStyleName()))
self.d_denyBattle(toonId)
return
elif self.legType != SuitLeg.TWalk:
if self.notify.getDebug():
self.notify.debug('requestBattle() - suit %s not in Bellicose' % self.getDoId())
self.b_setBrushOff(SuitDialog.getBrushOffIndex(self.getStyleName()))
self.d_denyBattle(toonId)
return
self.confrontPos = Point3(x, y, z)
self.confrontHpr = Vec3(h, p, r)
if self.sp.requestBattle(self.zoneId, self, toonId):
if self.notify.getDebug():
self.notify.debug('Suit %s requesting battle in zone %s' % (self.getDoId(), self.zoneId))
else:
if self.notify.getDebug():
self.notify.debug('requestBattle from suit %s - denied by battle manager' % self.getDoId())
self.b_setBrushOff(SuitDialog.getBrushOffIndex(self.getStyleName()))
self.d_denyBattle(toonId)
return
def getConfrontPosHpr(self):
return (self.confrontPos, self.confrontHpr)
def flyAwayNow(self):
self.b_setPathState(2)
self.stopPathNow()
name = self.taskName('flyAwayNow')
taskMgr.remove(name)
taskMgr.doMethodLater(SuitTimings.toSky, self.finishFlyAwayNow, name)
def danceNowFlyAwayLater(self):
self.b_setPathState(4)
self.stopPathNow()
name = self.taskName('danceNowFlyAwayLater')
taskMgr.remove(name)
taskMgr.doMethodLater(SuitTimings.victoryDance + SuitTimings.toSky, self.finishFlyAwayNow, name)
def finishFlyAwayNow(self, task):
self.notify.debug('Suit %s finishFlyAwayNow' % self.doId)
self.requestRemoval()
return Task.done
def d_setSPDoId(self, doId):
self.sendUpdate('setSPDoId', [doId])
def getSPDoId(self):
if self.sp:
return self.sp.getDoId()
else:
return 0
def releaseControl(self):
self.b_setPathState(0)
def b_setPathEndpoints(self, start, end, minPathLen, maxPathLen):
self.setPathEndpoints(start, end, minPathLen, maxPathLen)
self.d_setPathEndpoints(start, end, minPathLen, maxPathLen)
def d_setPathEndpoints(self, start, end, minPathLen, maxPathLen):
self.sendUpdate('setPathEndpoints', [start,
end,
minPathLen,
maxPathLen])
def setPathEndpoints(self, start, end, minPathLen, maxPathLen):
self.pathEndpointStart = start
self.pathEndpointEnd = end
self.minPathLen = minPathLen
self.maxPathLen = maxPathLen
def getPathEndpoints(self):
return (self.pathEndpointStart,
self.pathEndpointEnd,
self.minPathLen,
self.maxPathLen)
def b_setPathPosition(self, index, timestamp):
self.setPathPosition(index, timestamp)
self.d_setPathPosition(index, timestamp)
def d_setPathPosition(self, index, timestamp):
self.notify.debug('Suit %s reaches point %s at time %0.2f' % (self.getDoId(), index, timestamp))
self.sendUpdate('setPathPosition', [index, globalClockDelta.localToNetworkTime(timestamp)])
def setPathPosition(self, index, timestamp):
self.pathPositionIndex = index
self.pathPositionTimestamp = timestamp
def getPathPosition(self):
return (self.pathPositionIndex, globalClockDelta.localToNetworkTime(self.pathPositionTimestamp))
def b_setPathState(self, state):
self.setPathState(state)
self.d_setPathState(state)
def d_setPathState(self, state):
self.sendUpdate('setPathState', [state])
def setPathState(self, state):
if self.pathState != state:
self.pathState = state
if state == 0:
self.stopPathNow()
elif state == 1:
self.moveToNextLeg(None)
elif state == 2:
self.stopPathNow()
elif state == 3:
pass
elif state == 4:
self.stopPathNow()
else:
self.notify.error('Invalid state: ' + str(state))
return
def getPathState(self):
return self.pathState
def d_debugSuitPosition(self, elapsed, currentLeg, x, y, timestamp):
timestamp = globalClockDelta.localToNetworkTime(timestamp)
self.sendUpdate('debugSuitPosition', [elapsed,
currentLeg,
x,
y,
timestamp])
def initializePath(self):
self.makeLegList()
if self.notify.getDebug():
self.notify.debug('Leg list:')
print self.legList
idx1 = self.startPoint.getIndex()
idx2 = self.endPoint.getIndex()
self.pathStartTime = globalClock.getFrameTime()
self.setPathEndpoints(idx1, idx2, self.minPathLen, self.maxPathLen)
self.setPathPosition(0, self.pathStartTime)
self.pathState = 1
self.currentLeg = 0
self.zoneId = self.legList.getZoneId(0)
self.legType = self.legList.getType(0)
if self.notify.getDebug():
self.notify.debug('creating suit in zone %s' % self.zoneId)
def resync(self):
self.b_setPathPosition(self.currentLeg, self.pathStartTime + self.legList.getStartTime(self.currentLeg))
def moveToNextLeg(self, task):
now = globalClock.getFrameTime()
elapsed = now - self.pathStartTime
nextLeg = self.legList.getLegIndexAtTime(elapsed, self.currentLeg)
numLegs = self.legList.getNumLegs()
if self.currentLeg != nextLeg:
if nextLeg >= numLegs:
self.flyAwayNow()
return Task.done
self.currentLeg = nextLeg
self.__beginLegType(self.legList.getType(nextLeg))
zoneId = self.legList.getZoneId(nextLeg)
if zoneId:
self.__enterZone(zoneId)
self.notify.debug('Suit %s reached leg %s of %s in zone %s.' % (self.getDoId(),
nextLeg,
numLegs - 1,
self.zoneId))
if self.DEBUG_SUIT_POSITIONS:
leg = self.legList.getLeg(nextLeg)
pos = leg.getPosAtTime(elapsed - leg.getStartTime())
self.d_debugSuitPosition(elapsed, nextLeg, pos[0], pos[1], now)
if now - self.pathPositionTimestamp > self.UPDATE_TIMESTAMP_INTERVAL:
self.resync()
if self.pathState != 1:
return Task.done
nextLeg += 1
while nextLeg + 1 < numLegs and self.legList.getZoneId(nextLeg) == ZoneUtil.getCanonicalZoneId(self.zoneId) and self.legList.getType(nextLeg) == self.legType:
nextLeg += 1
if nextLeg < numLegs:
nextTime = self.legList.getStartTime(nextLeg)
delay = nextTime - elapsed
taskMgr.remove(self.taskName('move'))
taskMgr.doMethodLater(delay, self.moveToNextLeg, self.taskName('move'))
else:
if simbase.config.GetBool('want-cogbuildings', True):
self.startTakeOver()
self.requestRemoval()
return Task.done
def stopPathNow(self):
taskMgr.remove(self.taskName('move'))
def __enterZone(self, zoneId):
if zoneId != self.zoneId:
self.sp.zoneChange(self, self.zoneId, zoneId)
# Originally, we would call self.air.sendSetZoneMsg(). I think the
# following is a worthy replacement, however:
self.b_setLocation(simbase.air.districtId, zoneId)
self.zoneId = zoneId
if self.pathState == 1:
self.sp.checkForBattle(zoneId, self)
def __beginLegType(self, legType):
self.legType = legType
if legType == SuitLeg.TWalkFromStreet:
self.checkBuildingState()
elif legType == SuitLeg.TToToonBuilding:
self.openToonDoor()
elif legType == SuitLeg.TToSuitBuilding:
self.openSuitDoor()
elif legType == SuitLeg.TToCogHQ:
self.openCogHQDoor(1)
elif legType == SuitLeg.TFromCogHQ:
self.openCogHQDoor(0)
def resume(self):
self.notify.debug('Suit %s resume' % self.doId)
if self.currHP <= 0:
self.notify.debug('Suit %s dead after resume' % self.doId)
self.requestRemoval()
else:
self.danceNowFlyAwayLater()
def prepareToJoinBattle(self):
self.b_setPathState(0)
def interruptMove(self):
SuitBase.SuitBase.interruptMove(self)
def checkBuildingState(self):
blockNumber = self.buildingDestination
if blockNumber == None:
return
building = self.sp.buildingMgr.getBuilding(blockNumber)
if self.attemptingTakeover:
if not building.isToonBlock():
self.flyAwayNow()
return
if not hasattr(building, 'door'):
self.flyAwayNow()
return
building.door.setDoorLock(FADoorCodes.SUIT_APPROACHING)
elif not building.isSuitBlock():
self.flyAwayNow()
return
def openToonDoor(self):
blockNumber = self.buildingDestination
building = self.sp.buildingMgr.getBuilding(blockNumber)
if not building.isToonBlock():
self.flyAwayNow()
return
if not hasattr(building, 'door'):
self.flyAwayNow()
return
building.door.requestSuitEnter(self.getDoId())
def openSuitDoor(self):
blockNumber = self.buildingDestination
building = self.sp.buildingMgr.getBuilding(blockNumber)
if not building.isSuitBlock():
self.flyAwayNow()
return
def openCogHQDoor(self, enter):
blockNumber = self.legList.getBlockNumber(self.currentLeg)
try:
door = self.sp.cogHQDoors[blockNumber]
except:
self.notify.error('No CogHQ door %s in zone %s' % (blockNumber, self.sp.zoneId))
return
if enter:
door.requestSuitEnter(self.getDoId())
else:
door.requestSuitExit(self.getDoId())
def startTakeOver(self):
if not self.SUIT_BUILDINGS:
return
blockNumber = self.buildingDestination
if self.sp.buildingMgr is None:
return
if not self.sp.buildingMgr.isSuitBlock(blockNumber):
self.notify.debug('Suit %s taking over building %s in %s' % (self.getDoId(), blockNumber, self.zoneId))
difficulty = self.getActualLevel() - 1
dept = SuitDNA.getSuitDept(self.dna.name)
if self.buildingDestinationIsCogdo:
self.sp.cogdoTakeOver(blockNumber, difficulty, self.buildingHeight, dept)
else:
self.sp.suitTakeOver(blockNumber, dept, difficulty, self.buildingHeight)