2019-11-02 17:27:54 -05:00
|
|
|
import math
|
|
|
|
from direct.showbase.DirectObject import DirectObject
|
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
|
|
from direct.fsm.FSM import FSM
|
|
|
|
from direct.task.Task import Task
|
|
|
|
from direct.interval.IntervalGlobal import Sequence, Parallel, LerpScaleInterval, LerpFunctionInterval, Func, Wait, LerpFunc, SoundInterval, ParallelEndTogether, LerpPosInterval, ActorInterval, LerpPosHprInterval, LerpHprInterval
|
|
|
|
from direct.directutil import Mopath
|
|
|
|
from direct.showbase.PythonUtil import bound as clamp
|
2022-12-16 18:40:57 -06:00
|
|
|
from panda3d.core import CollisionSphere, CollisionNode, CollisionTube, CollisionPolygon, Vec3, Point3
|
2019-11-02 17:27:54 -05:00
|
|
|
from toontown.suit import Suit
|
|
|
|
from toontown.suit import SuitDNA
|
|
|
|
from toontown.toonbase import ToontownGlobals
|
|
|
|
from toontown.battle import BattleProps
|
2019-12-30 00:07:56 -06:00
|
|
|
from .CogdoFlyingUtil import swapAvatarShadowPlacer
|
|
|
|
from . import CogdoUtil
|
|
|
|
from . import CogdoFlyingGameGlobals as Globals
|
2019-11-02 17:27:54 -05:00
|
|
|
|
2019-12-30 00:59:01 -06:00
|
|
|
class CogdoFlyingLegalEagle(FSM, DirectObject):
|
2019-11-02 17:27:54 -05:00
|
|
|
CollSphereName = 'CogdoFlyingLegalEagleSphere'
|
|
|
|
CollisionEventName = 'CogdoFlyingLegalEagleCollision'
|
|
|
|
InterestCollName = 'CogdoFlyingLegalEagleInterestCollision'
|
|
|
|
RequestAddTargetEventName = 'CogdoFlyingLegalEagleRequestTargetEvent'
|
|
|
|
RequestAddTargetAgainEventName = 'CogdoFlyingLegalEagleRequestTargetAgainEvent'
|
|
|
|
RequestRemoveTargetEventName = 'CogdoFlyingLegalEagleRemoveTargetEvent'
|
|
|
|
ForceRemoveTargetEventName = 'CogdoFlyingLegalEagleForceRemoveTargetEvent'
|
|
|
|
EnterLegalEagle = 'CogdoFlyingLegalEagleDamageToon'
|
|
|
|
ChargingToAttackEventName = 'LegalEagleChargingToAttack'
|
|
|
|
LockOnToonEventName = 'LegalEagleLockOnToon'
|
|
|
|
CooldownEventName = 'LegalEagleCooldown'
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('CogdoFlyingLegalEagle')
|
|
|
|
|
|
|
|
def __init__(self, nest, index, suitDnaName = 'le'):
|
|
|
|
FSM.__init__(self, 'CogdoFlyingLegalEagle')
|
|
|
|
self.defaultTransitions = {'Off': ['Roost'],
|
|
|
|
'Roost': ['TakeOff', 'Off'],
|
|
|
|
'TakeOff': ['LockOnToon', 'LandOnNest', 'Off'],
|
|
|
|
'LockOnToon': ['RetreatToNest', 'ChargeUpAttack', 'Off'],
|
|
|
|
'ChargeUpAttack': ['RetreatToNest', 'Attack', 'Off'],
|
|
|
|
'Attack': ['RetreatToSky', 'Off'],
|
|
|
|
'RetreatToSky': ['Cooldown', 'Off'],
|
|
|
|
'Cooldown': ['LockOnToon', 'LandOnNest', 'Off'],
|
|
|
|
'RetreatToNest': ['LandOnNest', 'Off'],
|
|
|
|
'LandOnNest': ['Roost', 'Off']}
|
|
|
|
self.index = index
|
|
|
|
self.nest = nest
|
|
|
|
self.target = None
|
|
|
|
self.isEagleInterested = False
|
|
|
|
self.collSphere = None
|
|
|
|
self.suit = Suit.Suit()
|
|
|
|
d = SuitDNA.SuitDNA()
|
|
|
|
d.newSuit(suitDnaName)
|
|
|
|
self.suit.setDNA(d)
|
|
|
|
self.suit.reparentTo(render)
|
|
|
|
swapAvatarShadowPlacer(self.suit, 'legalEagle-%sShadowPlacer' % index)
|
|
|
|
self.suit.setPos(self.nest.getPos(render))
|
|
|
|
self.suit.setHpr(-180, 0, 0)
|
|
|
|
self.suit.stash()
|
|
|
|
self.prop = None
|
|
|
|
self.attachPropeller()
|
|
|
|
head = self.suit.find('**/joint_head')
|
|
|
|
self.interestConeOrigin = self.nest.attachNewNode('fakeHeadNodePath')
|
|
|
|
self.interestConeOrigin.setPos(render, head.getPos(render) + Vec3(0, Globals.LegalEagle.InterestConeOffset, 0))
|
|
|
|
self.attackTargetPos = None
|
|
|
|
self.startOfRetreatToSkyPos = None
|
|
|
|
pathModel = CogdoUtil.loadFlyingModel('legalEaglePaths')
|
|
|
|
self.chargeUpMotionPath = Mopath.Mopath(name='chargeUpMotionPath-%i' % self.index)
|
|
|
|
self.chargeUpMotionPath.loadNodePath(pathModel.find('**/charge_path'))
|
|
|
|
self.retreatToSkyMotionPath = Mopath.Mopath(name='retreatToSkyMotionPath-%i' % self.index)
|
|
|
|
self.retreatToSkyMotionPath.loadNodePath(pathModel.find('**/retreat_path'))
|
|
|
|
audioMgr = base.cogdoGameAudioMgr
|
|
|
|
self._screamSfx = audioMgr.createSfx('legalEagleScream', self.suit)
|
|
|
|
self.initIntervals()
|
|
|
|
return
|
|
|
|
|
|
|
|
def attachPropeller(self):
|
|
|
|
if self.prop == None:
|
|
|
|
self.prop = BattleProps.globalPropPool.getProp('propeller')
|
|
|
|
head = self.suit.find('**/joint_head')
|
|
|
|
self.prop.reparentTo(head)
|
|
|
|
return
|
|
|
|
|
|
|
|
def detachPropeller(self):
|
|
|
|
if self.prop:
|
|
|
|
self.prop.cleanup()
|
|
|
|
self.prop.removeNode()
|
|
|
|
self.prop = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def _getAnimationIval(self, animName, startFrame = 0, endFrame = None, duration = 1):
|
|
|
|
if endFrame == None:
|
|
|
|
self.suit.getNumFrames(animName) - 1
|
|
|
|
frames = endFrame - startFrame
|
|
|
|
frameRate = self.suit.getFrameRate(animName)
|
|
|
|
newRate = frames / duration
|
|
|
|
playRate = newRate / frameRate
|
|
|
|
ival = Sequence(ActorInterval(self.suit, animName, playRate=playRate))
|
|
|
|
return ival
|
|
|
|
|
|
|
|
def initIntervals(self):
|
|
|
|
dur = Globals.LegalEagle.LiftOffTime
|
|
|
|
nestPos = self.nest.getPos(render)
|
|
|
|
airPos = nestPos + Vec3(0.0, 0.0, Globals.LegalEagle.LiftOffHeight)
|
|
|
|
self.takeOffSeq = Sequence(Parallel(Sequence(Wait(dur * 0.6), LerpPosInterval(self.suit, dur * 0.4, startPos=nestPos, pos=airPos, blendType='easeInOut'))), Wait(1.5), Func(self.request, 'next'), name='%s.takeOffSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
self.landOnNestPosLerp = LerpPosInterval(self.suit, 1.0, startPos=airPos, pos=nestPos, blendType='easeInOut')
|
|
|
|
self.landingSeq = Sequence(Func(self.updateLandOnNestPosLerp), Parallel(self.landOnNestPosLerp), Func(self.request, 'next'), name='%s.landingSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
dur = Globals.LegalEagle.ChargeUpTime
|
|
|
|
self.chargeUpPosLerp = LerpFunc(self.moveAlongChargeUpMopathFunc, fromData=0.0, toData=self.chargeUpMotionPath.getMaxT(), duration=dur, blendType='easeInOut')
|
|
|
|
self.chargeUpAttackSeq = Sequence(Func(self.updateChargeUpPosLerp), self.chargeUpPosLerp, Func(self.request, 'next'), name='%s.chargeUpAttackSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
dur = Globals.LegalEagle.RetreatToNestTime
|
|
|
|
self.retreatToNestPosLerp = LerpPosInterval(self.suit, dur, startPos=Vec3(0, 0, 0), pos=airPos, blendType='easeInOut')
|
|
|
|
self.retreatToNestSeq = Sequence(Func(self.updateRetreatToNestPosLerp), self.retreatToNestPosLerp, Func(self.request, 'next'), name='%s.retreatToNestSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
dur = Globals.LegalEagle.RetreatToSkyTime
|
|
|
|
self.retreatToSkyPosLerp = LerpFunc(self.moveAlongRetreatMopathFunc, fromData=0.0, toData=self.retreatToSkyMotionPath.getMaxT(), duration=dur, blendType='easeOut')
|
|
|
|
self.retreatToSkySeq = Sequence(Func(self.updateRetreatToSkyPosLerp), self.retreatToSkyPosLerp, Func(self.request, 'next'), name='%s.retreatToSkySeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
dur = Globals.LegalEagle.PreAttackTime
|
|
|
|
self.preAttackLerpXY = LerpFunc(self.updateAttackXY, fromData=0.0, toData=1.0, duration=dur)
|
|
|
|
self.preAttackLerpZ = LerpFunc(self.updateAttackZ, fromData=0.0, toData=1.0, duration=dur, blendType='easeOut')
|
|
|
|
dur = Globals.LegalEagle.PostAttackTime
|
|
|
|
self.postAttackPosLerp = LerpPosInterval(self.suit, dur, startPos=Vec3(0, 0, 0), pos=Vec3(0, 0, 0))
|
|
|
|
self.attackSeq = Sequence(Parallel(self.preAttackLerpXY, self.preAttackLerpZ), Func(self.updatePostAttackPosLerp), self.postAttackPosLerp, Func(self.request, 'next'), name='%s.attackSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
dur = Globals.LegalEagle.CooldownTime
|
|
|
|
self.cooldownSeq = Sequence(Wait(dur), Func(self.request, 'next'), name='%s.cooldownSeq-%i' % (self.__class__.__name__, self.index))
|
|
|
|
self.propTrack = Sequence(ActorInterval(self.prop, 'propeller', startFrame=0, endFrame=14))
|
|
|
|
self.hoverOverNestSeq = Sequence(ActorInterval(self.suit, 'landing', startFrame=10, endFrame=20, playRate=0.5), ActorInterval(self.suit, 'landing', startFrame=20, endFrame=10, playRate=0.5))
|
|
|
|
|
|
|
|
def initCollision(self):
|
|
|
|
self.collSphere = CollisionSphere(0, 0, 0, 0)
|
|
|
|
self.collSphere.setTangible(0)
|
|
|
|
self.collNode = CollisionNode('%s-%s' % (self.CollSphereName, self.index))
|
|
|
|
self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
|
|
|
|
self.collNode.addSolid(self.collSphere)
|
|
|
|
self.collNodePath = self.suit.attachNewNode(self.collNode)
|
|
|
|
self.collNodePath.hide()
|
|
|
|
self.accept('enter%s-%s' % (self.CollSphereName, self.index), self.handleEnterSphere)
|
|
|
|
self.setCollSphereToNest()
|
|
|
|
|
|
|
|
def getInterestConeLength(self):
|
|
|
|
return Globals.LegalEagle.InterestConeLength + Globals.LegalEagle.InterestConeOffset
|
|
|
|
|
|
|
|
def isToonInView(self, toon):
|
|
|
|
distanceThreshold = self.getInterestConeLength()
|
|
|
|
angleThreshold = Globals.LegalEagle.InterestConeAngle
|
|
|
|
toonPos = toon.getPos(render)
|
|
|
|
nestPos = self.nest.getPos(render)
|
|
|
|
distance = toon.getDistance(self.interestConeOrigin)
|
|
|
|
if distance > distanceThreshold:
|
|
|
|
return False
|
|
|
|
if toonPos[1] > nestPos[1]:
|
|
|
|
return False
|
|
|
|
a = toon.getPos(render) - self.interestConeOrigin.getPos(render)
|
|
|
|
a.normalize()
|
|
|
|
b = Vec3(0, -1, 0)
|
|
|
|
dotProduct = a.dot(b)
|
|
|
|
angle = math.degrees(math.acos(dotProduct))
|
|
|
|
if angle <= angleThreshold / 2.0:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def update(self, dt, localPlayer):
|
|
|
|
if Globals.Dev.NoLegalEagleAttacks:
|
|
|
|
return
|
|
|
|
inView = self.isToonInView(localPlayer.toon)
|
|
|
|
if inView and not self.isEagleInterested:
|
|
|
|
self.handleEnterInterest()
|
|
|
|
elif inView and self.isEagleInterested:
|
|
|
|
self.handleAgainInterest()
|
|
|
|
elif not inView and self.isEagleInterested:
|
|
|
|
self.handleExitInterest()
|
|
|
|
|
|
|
|
def updateLockOnTask(self):
|
|
|
|
dt = globalClock.getDt()
|
|
|
|
targetPos = self.target.getPos(render)
|
|
|
|
suitPos = self.suit.getPos(render)
|
|
|
|
nestPos = self.nest.getPos(render)
|
|
|
|
attackPos = Vec3(targetPos)
|
|
|
|
attackPos[1] = nestPos[1] + Globals.LegalEagle.LockOnDistanceFromNest
|
|
|
|
attackPos[2] += Globals.LegalEagle.VerticalOffset
|
|
|
|
if attackPos[2] < nestPos[2]:
|
|
|
|
attackPos[2] = nestPos[2]
|
|
|
|
attackChangeVec = (attackPos - suitPos) * Globals.LegalEagle.LockOnSpeed
|
|
|
|
self.suit.setPos(suitPos + attackChangeVec * dt)
|
|
|
|
return Task.cont
|
|
|
|
|
|
|
|
def updateAttackXY(self, value):
|
|
|
|
if Globals.LegalEagle.EagleAttackShouldXCorrect:
|
|
|
|
x = self.readyToAttackPos.getX() + (self.attackTargetPos.getX() - self.readyToAttackPos.getX()) * value
|
|
|
|
self.suit.setX(x)
|
|
|
|
y = self.readyToAttackPos.getY() + (self.attackTargetPos.getY() - self.readyToAttackPos.getY()) * value
|
|
|
|
self.suit.setY(y)
|
|
|
|
|
|
|
|
def updateAttackZ(self, value):
|
|
|
|
z = self.readyToAttackPos.getZ() + (self.attackTargetPos.getZ() - self.readyToAttackPos.getZ()) * value
|
|
|
|
self.suit.setZ(z)
|
|
|
|
|
|
|
|
def moveAlongChargeUpMopathFunc(self, value):
|
|
|
|
self.chargeUpMotionPath.goTo(self.suit, value)
|
|
|
|
self.suit.setPos(self.suit.getPos() + self.startOfChargeUpPos)
|
|
|
|
|
|
|
|
def moveAlongRetreatMopathFunc(self, value):
|
|
|
|
self.retreatToSkyMotionPath.goTo(self.suit, value)
|
|
|
|
self.suit.setPos(self.suit.getPos() + self.startOfRetreatToSkyPos)
|
|
|
|
|
|
|
|
def updateChargeUpPosLerp(self):
|
|
|
|
self.startOfChargeUpPos = self.suit.getPos(render)
|
|
|
|
|
|
|
|
def updateLandOnNestPosLerp(self):
|
|
|
|
self.landOnNestPosLerp.setStartPos(self.suit.getPos())
|
|
|
|
|
|
|
|
def updateRetreatToNestPosLerp(self):
|
|
|
|
self.retreatToNestPosLerp.setStartPos(self.suit.getPos())
|
|
|
|
|
|
|
|
def updateRetreatToSkyPosLerp(self):
|
|
|
|
self.startOfRetreatToSkyPos = self.suit.getPos(render)
|
|
|
|
|
|
|
|
def updatePostAttackPosLerp(self):
|
|
|
|
suitPos = self.suit.getPos(render)
|
|
|
|
finalPos = suitPos + Vec3(0, -Globals.LegalEagle.PostAttackLength, 0)
|
|
|
|
self.postAttackPosLerp.setStartPos(suitPos)
|
|
|
|
self.postAttackPosLerp.setEndPos(finalPos)
|
|
|
|
|
|
|
|
def handleEnterSphere(self, collEntry):
|
|
|
|
self.notify.debug('handleEnterSphere:%i' % self.index)
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.EnterLegalEagle, [self, collEntry])
|
|
|
|
|
|
|
|
def handleEnterInterest(self):
|
|
|
|
self.notify.debug('handleEnterInterestColl:%i' % self.index)
|
|
|
|
self.isEagleInterested = True
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.RequestAddTargetEventName, [self.index])
|
|
|
|
|
|
|
|
def handleAgainInterest(self):
|
|
|
|
self.isEagleInterested = True
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.RequestAddTargetAgainEventName, [self.index])
|
|
|
|
|
|
|
|
def handleExitInterest(self):
|
|
|
|
self.notify.debug('handleExitInterestSphere:%i' % self.index)
|
|
|
|
self.isEagleInterested = False
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.RequestRemoveTargetEventName, [self.index])
|
|
|
|
|
|
|
|
def hasTarget(self):
|
|
|
|
if self.target != None:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
return
|
|
|
|
|
|
|
|
def setTarget(self, toon, elapsedTime = 0.0):
|
|
|
|
self.notify.debug('Setting eagle %i to target: %s, elapsed time: %s' % (self.index, toon.getName(), elapsedTime))
|
|
|
|
self.target = toon
|
|
|
|
if self.state == 'Roost':
|
|
|
|
self.request('next', elapsedTime)
|
|
|
|
if self.state == 'ChargeUpAttack':
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [self.target.doId])
|
|
|
|
|
|
|
|
def clearTarget(self, elapsedTime = 0.0):
|
|
|
|
self.notify.debug('Clearing target from eagle %i, elapsed time: %s' % (self.index, elapsedTime))
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [self.target.doId])
|
|
|
|
self.target = None
|
|
|
|
if self.state in ['LockOnToon']:
|
|
|
|
self.request('next', elapsedTime)
|
|
|
|
return
|
|
|
|
|
|
|
|
def leaveCooldown(self, elapsedTime = 0.0):
|
|
|
|
if self.state in ['Cooldown']:
|
|
|
|
self.request('next', elapsedTime)
|
|
|
|
|
|
|
|
def shouldBeInFrame(self):
|
|
|
|
if self.state in ['TakeOff', 'LockOnToon', 'ChargeUpAttack']:
|
|
|
|
return True
|
|
|
|
elif self.state == 'Attack':
|
|
|
|
distance = self.suit.getDistance(self.target)
|
|
|
|
threshold = Globals.LegalEagle.EagleAndTargetDistCameraTrackThreshold
|
|
|
|
suitPos = self.suit.getPos(render)
|
|
|
|
targetPos = self.target.getPos(render)
|
|
|
|
if distance > threshold and suitPos[1] > targetPos[1]:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def getTarget(self):
|
|
|
|
return self.target
|
|
|
|
|
|
|
|
def onstage(self):
|
|
|
|
self.suit.unstash()
|
|
|
|
self.request('Roost')
|
|
|
|
|
|
|
|
def offstage(self):
|
|
|
|
self.suit.stash()
|
|
|
|
self.request('Off')
|
|
|
|
|
|
|
|
def gameStart(self, gameStartTime):
|
|
|
|
self.gameStartTime = gameStartTime
|
|
|
|
self.initCollision()
|
|
|
|
|
|
|
|
def gameEnd(self):
|
|
|
|
self.shutdownCollisions()
|
|
|
|
|
|
|
|
def shutdownCollisions(self):
|
|
|
|
self.ignoreAll()
|
|
|
|
if self.collSphere != None:
|
|
|
|
del self.collSphere
|
|
|
|
self.collSphere = None
|
|
|
|
if self.collNodePath != None:
|
|
|
|
self.collNodePath.removeNode()
|
|
|
|
del self.collNodePath
|
|
|
|
self.collNodePath = None
|
|
|
|
if self.collNode != None:
|
|
|
|
del self.collNode
|
|
|
|
self.collNode = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def destroy(self):
|
|
|
|
self.request('Off')
|
|
|
|
self.detachPropeller()
|
|
|
|
del self._screamSfx
|
|
|
|
self.suit.cleanup()
|
|
|
|
self.suit.removeNode()
|
|
|
|
self.suit.delete()
|
|
|
|
self.interestConeOrigin.removeNode()
|
|
|
|
del self.interestConeOrigin
|
|
|
|
self.nest = None
|
|
|
|
self.target = None
|
|
|
|
taskMgr.remove('updateLockOnTask-%i' % self.index)
|
|
|
|
taskMgr.remove('exitLockOnToon-%i' % self.index)
|
|
|
|
self.propTrack.clearToInitial()
|
|
|
|
del self.propTrack
|
|
|
|
del self.chargeUpMotionPath
|
|
|
|
del self.retreatToSkyMotionPath
|
|
|
|
self.takeOffSeq.clearToInitial()
|
|
|
|
del self.takeOffSeq
|
|
|
|
del self.landOnNestPosLerp
|
|
|
|
self.landingSeq.clearToInitial()
|
|
|
|
del self.landingSeq
|
|
|
|
del self.chargeUpPosLerp
|
|
|
|
self.chargeUpAttackSeq.clearToInitial()
|
|
|
|
del self.chargeUpAttackSeq
|
|
|
|
del self.retreatToNestPosLerp
|
|
|
|
self.retreatToNestSeq.clearToInitial()
|
|
|
|
del self.retreatToNestSeq
|
|
|
|
del self.retreatToSkyPosLerp
|
|
|
|
self.retreatToSkySeq.clearToInitial()
|
|
|
|
del self.retreatToSkySeq
|
|
|
|
del self.postAttackPosLerp
|
|
|
|
self.attackSeq.clearToInitial()
|
|
|
|
del self.attackSeq
|
|
|
|
self.cooldownSeq.clearToInitial()
|
|
|
|
del self.cooldownSeq
|
|
|
|
self.hoverOverNestSeq.clearToInitial()
|
|
|
|
del self.hoverOverNestSeq
|
|
|
|
del self.preAttackLerpXY
|
|
|
|
del self.preAttackLerpZ
|
|
|
|
return
|
|
|
|
|
|
|
|
def requestNext(self):
|
|
|
|
self.request('next')
|
|
|
|
|
|
|
|
def setCollSphereToNest(self):
|
|
|
|
if hasattr(self, 'collSphere') and self.collSphere is not None:
|
|
|
|
radius = Globals.LegalEagle.OnNestDamageSphereRadius
|
|
|
|
self.collSphere.setCenter(Point3(0.0, -Globals.Level.LaffPowerupNestOffset[1], self.suit.getHeight() / 2.0))
|
|
|
|
self.collSphere.setRadius(radius)
|
|
|
|
return
|
|
|
|
|
|
|
|
def setCollSphereToTargeting(self):
|
|
|
|
if hasattr(self, 'collSphere') and self.collSphere is not None:
|
|
|
|
radius = Globals.LegalEagle.DamageSphereRadius
|
|
|
|
self.collSphere.setCenter(Point3(0, 0, radius * 2))
|
|
|
|
self.collSphere.setRadius(radius)
|
|
|
|
return
|
|
|
|
|
|
|
|
def enterRoost(self):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState))
|
|
|
|
self.hoverOverNestSeq.loop()
|
|
|
|
self.propTrack.loop()
|
|
|
|
self.setCollSphereToNest()
|
|
|
|
|
|
|
|
def filterRoost(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
return 'TakeOff'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitRoost(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.hoverOverNestSeq.pause()
|
|
|
|
self.setCollSphereToTargeting()
|
|
|
|
|
|
|
|
def enterTakeOff(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.takeOffSeq.start(elapsedTime)
|
|
|
|
self.hoverOverNestSeq.loop()
|
|
|
|
|
|
|
|
def filterTakeOff(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
if self.hasTarget():
|
|
|
|
return 'LockOnToon'
|
|
|
|
else:
|
|
|
|
return 'LandOnNest'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitTakeOff(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.takeOffSeq.clearToInitial()
|
|
|
|
self.hoverOverNestSeq.pause()
|
|
|
|
|
|
|
|
def enterLockOnToon(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
taskName = 'updateLockOnTask-%i' % self.index
|
|
|
|
taskMgr.add(self.updateLockOnTask, taskName, 45, extraArgs=[])
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.LockOnToonEventName, [self.target.doId])
|
|
|
|
range = self.target.getDistance(self.interestConeOrigin) / self.getInterestConeLength()
|
|
|
|
range = clamp(range, 0.0, 1.0)
|
|
|
|
dur = Globals.LegalEagle.LockOnTime
|
|
|
|
if self.oldState == 'TakeOff':
|
|
|
|
dur *= range
|
|
|
|
else:
|
|
|
|
dur += Globals.LegalEagle.ExtraPostCooldownTime
|
|
|
|
taskName = 'exitLockOnToon-%i' % self.index
|
|
|
|
taskMgr.doMethodLater(dur, self.requestNext, taskName, extraArgs=[])
|
|
|
|
|
|
|
|
def filterLockOnToon(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
if self.hasTarget():
|
|
|
|
return 'ChargeUpAttack'
|
|
|
|
else:
|
|
|
|
return 'RetreatToNest'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitLockOnToon(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
taskMgr.remove('updateLockOnTask-%i' % self.index)
|
|
|
|
taskMgr.remove('exitLockOnToon-%i' % self.index)
|
|
|
|
|
|
|
|
def enterChargeUpAttack(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.chargeUpAttackSeq.start(elapsedTime)
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [self.target.doId])
|
|
|
|
|
|
|
|
def filterChargeUpAttack(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
if self.hasTarget():
|
|
|
|
return 'Attack'
|
|
|
|
else:
|
|
|
|
return 'RetreatToNest'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitChargeUpAttack(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.chargeUpAttackSeq.clearToInitial()
|
|
|
|
|
|
|
|
def enterAttack(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.attackTargetPos = self.target.getPos(render)
|
|
|
|
targetState = self.target.animFSM.getCurrentState().getName()
|
|
|
|
self._screamSfx.play()
|
|
|
|
if targetState == 'jumpAirborne':
|
|
|
|
self.attackTargetPos[2] += Globals.LegalEagle.VerticalOffset
|
|
|
|
else:
|
|
|
|
self.attackTargetPos[2] += Globals.LegalEagle.PlatformVerticalOffset
|
|
|
|
self.readyToAttackPos = self.suit.getPos(render)
|
|
|
|
self.attackSeq.start(elapsedTime)
|
|
|
|
|
|
|
|
def filterAttack(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
return 'RetreatToSky'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitAttack(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.attackSeq.clearToInitial()
|
|
|
|
taskMgr.remove('updateAttackPosTask-%i' % self.index)
|
|
|
|
|
|
|
|
def enterRetreatToSky(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.retreatToSkySeq.start(elapsedTime)
|
|
|
|
|
|
|
|
def filterRetreatToSky(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
return 'Cooldown'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitRetreatToSky(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.retreatToSkySeq.clearToInitial()
|
|
|
|
|
|
|
|
def enterCooldown(self):
|
|
|
|
if self.target != None:
|
|
|
|
messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [self.target.doId])
|
|
|
|
self.suit.stash()
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState))
|
|
|
|
return
|
|
|
|
|
|
|
|
def filterCooldown(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
if self.hasTarget():
|
|
|
|
return 'LockOnToon'
|
|
|
|
else:
|
|
|
|
return 'LandOnNest'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitCooldown(self):
|
|
|
|
self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
|
|
|
|
self.suit.unstash()
|
|
|
|
self.cooldownSeq.clearToInitial()
|
|
|
|
if self.newState != 'Off':
|
|
|
|
heightOffNest = Globals.LegalEagle.PostCooldownHeightOffNest
|
|
|
|
nestPos = self.nest.getPos(render)
|
|
|
|
if self.newState in ['LandOnNest']:
|
|
|
|
self.suit.setPos(nestPos + Vec3(0, 0, heightOffNest))
|
|
|
|
else:
|
|
|
|
targetPos = self.target.getPos(render)
|
|
|
|
attackPos = Vec3(targetPos)
|
|
|
|
attackPos[1] = nestPos[1]
|
|
|
|
attackPos[2] = nestPos[2] + heightOffNest
|
|
|
|
self.suit.setPos(attackPos)
|
|
|
|
|
|
|
|
def enterRetreatToNest(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.retreatToNestSeq.start(elapsedTime)
|
|
|
|
|
|
|
|
def filterRetreatToNest(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
return 'LandOnNest'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitRetreatToNest(self):
|
|
|
|
self.retreatToNestSeq.clearToInitial()
|
|
|
|
|
|
|
|
def enterLandOnNest(self, elapsedTime = 0.0):
|
|
|
|
self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState,
|
|
|
|
self.oldState,
|
|
|
|
self.newState,
|
|
|
|
elapsedTime))
|
|
|
|
self.landingSeq.start(elapsedTime)
|
|
|
|
|
|
|
|
def filterLandOnNest(self, request, args):
|
|
|
|
self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
|
|
|
|
if request == self.state:
|
|
|
|
return None
|
|
|
|
elif request == 'next':
|
|
|
|
if self.hasTarget():
|
|
|
|
return 'TakeOff'
|
|
|
|
else:
|
|
|
|
return 'Roost'
|
|
|
|
else:
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def exitLandOnNest(self):
|
|
|
|
self.landingSeq.clearToInitial()
|