mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-28 14:12:52 -06:00
954 lines
40 KiB
Python
Executable file
954 lines
40 KiB
Python
Executable file
import math
|
|
from pandac.PandaModules import *
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.interval.IntervalGlobal import *
|
|
from direct.task.Task import Task
|
|
from panda3d.core import PythonTask
|
|
from toontown.toontowngui import TTDialog
|
|
from toontown.toonbase.ToonBaseGlobal import *
|
|
from toontown.toonbase import ToontownGlobals
|
|
from toontown.toonbase import TTLocalizer
|
|
from toontown.effects import Splash, DustCloud, Wake
|
|
from toontown.minigame import Trajectory
|
|
from toontown.minigame import CannonGameGlobals
|
|
from toontown.parties import PartyGlobals
|
|
from toontown.parties.PartyGlobals import ActivityIds
|
|
from toontown.parties.PartyGlobals import ActivityTypes
|
|
from toontown.parties.PartyGlobals import FireworksStartedEvent
|
|
from toontown.parties.PartyGlobals import FireworksFinishedEvent
|
|
from toontown.parties.PartyGlobals import PartyCannonCollisions
|
|
from toontown.parties.DistributedPartyActivity import DistributedPartyActivity
|
|
from toontown.parties.CannonGui import CannonGui
|
|
from toontown.parties.PartyUtils import toRadians, toDegrees
|
|
CANNON_ROTATION_VEL = 15.0
|
|
CANNON_ANGLE_VEL = 15.0
|
|
GROUND_PLANE_MIN = -15
|
|
SHADOW_Z_OFFSET = 0.5
|
|
INITIAL_VELOCITY = 90.0
|
|
WHISTLE_SPEED = INITIAL_VELOCITY * 0.35
|
|
|
|
class DistributedPartyCannonActivity(DistributedPartyActivity):
|
|
# I never go anywhere without my party cannon!
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCannonActivity')
|
|
HIT_GROUND = 0
|
|
HIT_TOWER = 1
|
|
HIT_WATER = 2
|
|
REACTIVATE_CLOUD_TASK = 'PartyActivity_ReactivateLastCloud'
|
|
RULES_DONE_EVENT = 'DistributedPartyCannonActivity_RULES_DONE_EVENT'
|
|
LOCAL_TOON_LANDED_EVENT = 'DistributedPartyCannonActivity_LOCAL_TOON_LANDED_EVENT'
|
|
NetDivisor = 100
|
|
TimeFactor = 0.75
|
|
BroadcastPeriod = 0.2
|
|
|
|
def __init__(self, cr):
|
|
DistributedPartyActivity.__init__(self, cr, ActivityIds.PartyCannon, ActivityTypes.Continuous, wantRewardGui=True)
|
|
self.gui = None
|
|
self.firingCannon = None
|
|
self.shadowNode = None
|
|
self.partyDoId = None
|
|
self.splash = None
|
|
self.dustCloud = None
|
|
self.lastWakeTime = 0
|
|
self.localFlyingDropShadow = None
|
|
self.localFlyingToon = None
|
|
self.localFlyingToonId = 0
|
|
self._lastBroadcastTime = -self.BroadcastPeriod
|
|
self._dirtyNewVel = None
|
|
self.hitBumper = 0
|
|
self.hitCloud = 0
|
|
self.lastPos = Vec3(0, 0, 0)
|
|
self.lastVel = Vec3(0, 0, 0)
|
|
self.vel = Vec3(0, 0, 0)
|
|
self.landingPos = Vec3(0, 0, 0)
|
|
self.t = 0
|
|
self.lastT = 0
|
|
self.deltaT = 0
|
|
self._lastCloudHit = None
|
|
self.cameraPos = Vec3(0, -15.0, -25.0)
|
|
self.cameraSpeed = 5.0
|
|
self.camNode = None
|
|
self.flyingToonOffsetRotation = 0
|
|
self.flyingToonOffsetAngle = 0
|
|
self.flyingToonOffsetX = 0
|
|
self.flyingToonOffsetY = 0
|
|
self.flyingToonCloudsHit = 0
|
|
self.initialFlyVel = 0
|
|
self._localPlayedBefore = False
|
|
self.hitTrack = None
|
|
self.cTrav = None
|
|
self.flyColNode = None
|
|
self.flyColNodePath = None
|
|
self._flyingCollisionTaskName = None
|
|
return
|
|
|
|
def generateInit(self):
|
|
DistributedPartyActivity.generateInit(self)
|
|
self.taskNameFireCannon = self.taskName('fireCannon')
|
|
self.taskNameShoot = self.taskName('shootTask')
|
|
self.taskNameFly = self.taskName('flyTask')
|
|
self.gui = CannonGui()
|
|
|
|
def load(self):
|
|
self.notify.debug('load')
|
|
DistributedPartyActivity.load(self)
|
|
base.cr.playGame.hood.loader.loadClouds()
|
|
base.cr.playGame.hood.loader.setCloudSwitch(1)
|
|
self.shadow = loader.loadModel('phase_3/models/props/drop_shadow')
|
|
self.shadowNode = hidden.attachNewNode('dropShadow')
|
|
self.shadow.copyTo(self.shadowNode)
|
|
self.shadowNode.setColor(0, 0, 0, 0.5)
|
|
self.shadowNode.setBin('fixed', 0, 1)
|
|
self.splash = Splash.Splash(render)
|
|
self.dustCloud = DustCloud.DustCloud(render)
|
|
self.dustCloud.setBillboardPointEye()
|
|
self.sndHitGround = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg')
|
|
self.sndHitWater = base.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg')
|
|
self.sndHitHouse = base.loadSfx('phase_5/audio/sfx/AA_drop_sandbag.ogg')
|
|
self.sndBounce1 = base.loadSfx('phase_13/audio/sfx/bounce1.ogg')
|
|
self.sndBounce2 = base.loadSfx('phase_13/audio/sfx/bounce2.ogg')
|
|
self.sndBounce3 = base.loadSfx('phase_13/audio/sfx/bounce3.ogg')
|
|
self.onstage()
|
|
self.sign.reparentTo(hidden)
|
|
self.sign.setPos(-6.0, 10.0, 0.0)
|
|
self.accept(FireworksStartedEvent, self.__handleFireworksStarted)
|
|
self.accept(FireworksFinishedEvent, self.__handleFireworksFinished)
|
|
|
|
def generate(self):
|
|
DistributedPartyActivity.generate(self)
|
|
self._doneCannons = False
|
|
self._avId2trajectoryInfo = {}
|
|
self._remoteToonFlyTaskName = 'remoteToonFlyTask-%s' % self.doId
|
|
taskMgr.add(self._remoteToonFlyTask, self._remoteToonFlyTaskName, priority=45)
|
|
self.d_cloudsColorRequest()
|
|
|
|
def unload(self):
|
|
self.notify.debug('unload')
|
|
DistributedPartyActivity.unload(self)
|
|
if self.shadowNode is not None:
|
|
self.shadowNode.removeNode()
|
|
del self.shadowNode
|
|
if self.splash is not None:
|
|
self.splash.destroy()
|
|
del self.splash
|
|
if self.dustCloud is not None:
|
|
self.dustCloud.destroy()
|
|
del self.dustCloud
|
|
del self.sndHitHouse
|
|
del self.sndHitGround
|
|
del self.sndHitWater
|
|
del self.sndBounce1
|
|
del self.sndBounce2
|
|
del self.sndBounce3
|
|
if self.localFlyingToon:
|
|
self.__resetToon(self.localFlyingToon)
|
|
self.localFlyingToon.loop('neutral')
|
|
self.localFlyingToon.setPlayRate(1.0, 'run')
|
|
self.localFlyingToon = None
|
|
self.ignoreAll()
|
|
return
|
|
|
|
def onstage(self):
|
|
self.notify.debug('onstage')
|
|
self.splash.reparentTo(render)
|
|
self.dustCloud.reparentTo(render)
|
|
|
|
def offstage(self):
|
|
self.notify.debug('offstage')
|
|
if self.splash is not None:
|
|
self.splash.reparentTo(hidden)
|
|
self.splash.stop()
|
|
if self.dustCloud is not None:
|
|
self.dustCloud.reparentTo(hidden)
|
|
self.dustCloud.stop()
|
|
return
|
|
|
|
def disable(self):
|
|
taskMgr.remove(self._remoteToonFlyTaskName)
|
|
if self._flyingCollisionTaskName:
|
|
taskMgr.remove(self._flyingCollisionTaskName)
|
|
taskMgr.remove(self.taskNameFireCannon)
|
|
taskMgr.remove(self.taskNameShoot)
|
|
taskMgr.remove(self.taskNameFly)
|
|
taskMgr.remove(DistributedPartyCannonActivity.REACTIVATE_CLOUD_TASK)
|
|
self.ignoreAll()
|
|
if self.localFlyingToonId:
|
|
self.__stopCollisionHandler(self.localFlyingToon)
|
|
self.__stopLocalFlyTask(self.localFlyingToonId)
|
|
self.setMovie(PartyGlobals.CANNON_MOVIE_CLEAR, self.localFlyingToonId)
|
|
if self.hitTrack is not None:
|
|
self.hitTrack.finish()
|
|
del self.hitTrack
|
|
self.hitTrack = None
|
|
DistributedPartyActivity.disable(self)
|
|
return
|
|
|
|
def delete(self):
|
|
self.offstage()
|
|
DistributedPartyActivity.delete(self)
|
|
|
|
def setMovie(self, mode, toonId):
|
|
self.notify.debug('%s setMovie(%s, %s)' % (self.doId, toonId, mode))
|
|
if toonId != base.localAvatar.doId:
|
|
return
|
|
if mode == PartyGlobals.CANNON_MOVIE_CLEAR:
|
|
self.landToon(toonId)
|
|
elif mode == PartyGlobals.CANNON_MOVIE_LANDED:
|
|
self.landToon(toonId)
|
|
elif mode == PartyGlobals.CANNON_MOVIE_FORCE_EXIT:
|
|
self.landToon(toonId)
|
|
|
|
def __handleAvatarGone(self):
|
|
self.setMovie(PartyGlobals.CANNON_MOVIE_CLEAR, 0)
|
|
|
|
def handleToonDisabled(self, toonId):
|
|
self.notify.warning('handleToonDisabled no implementation yet')
|
|
|
|
def handleToonJoined(self, toonId):
|
|
self.notify.warning('handleToonJoined no implementation yet')
|
|
|
|
def isLocalToon(self, av):
|
|
return base.localAvatar == av
|
|
|
|
def isLocalToonId(self, toonId):
|
|
return base.localAvatar.doId == toonId
|
|
|
|
def getTitle(self):
|
|
return TTLocalizer.PartyCannonActivityTitle
|
|
|
|
def getInstructions(self):
|
|
return TTLocalizer.PartyCannonActivityInstructions
|
|
|
|
def hasPlayedBefore(self):
|
|
return self._localPlayedBefore
|
|
|
|
def displayRules(self):
|
|
self.startRules()
|
|
|
|
def handleRulesDone(self):
|
|
self.finishRules()
|
|
self._localPlayedBefore = True
|
|
messenger.send(DistributedPartyCannonActivity.RULES_DONE_EVENT)
|
|
|
|
def setCannonWillFire(self, cannonId, zRot, angle):
|
|
self.notify.debug('setCannonWillFire: %d %d %d' % (cannonId, zRot, angle))
|
|
cannon = base.cr.doId2do.get(cannonId)
|
|
if cannon is None:
|
|
self.notify.warning("Cannon has not been created, but we got this message. Don't show firing.")
|
|
return
|
|
if not cannon.getToonInside():
|
|
self.notify.warning("setCannonWillFire, but no toon insde. Don't show firing")
|
|
return
|
|
if self.isLocalToon(cannon.getToonInside()):
|
|
self.localFlyingToon = base.localAvatar
|
|
self.localFlyingToonId = base.localAvatar.doId
|
|
self.localFiringCannon = cannon
|
|
self.flyingToonCloudsHit = 0
|
|
cannon.updateModel(zRot, angle)
|
|
toonId = cannon.getToonInside().doId
|
|
task = PythonTask(self.__fireCannonTask)
|
|
task.toonId = toonId
|
|
task.cannon = cannon
|
|
taskMgr.add(task, self.taskNameFireCannon)
|
|
self.toonIds.append(toonId)
|
|
return
|
|
|
|
def __fireCannonTask(self, task):
|
|
launchTime = 0.0
|
|
toonId = task.toonId
|
|
cannon = task.cannon
|
|
toon = cannon.getToonInside()
|
|
self.notify.debug(str(self.doId) + ' FIRING CANNON FOR TOON ' + str(toonId))
|
|
if not cannon.isToonInside():
|
|
return Task.done
|
|
if self.isLocalToonId(toonId):
|
|
self.inWater = 0
|
|
startPos, startHpr, startVel, trajectory = self.__calcFlightResults(cannon, toonId, launchTime)
|
|
|
|
self.notify.debug('start position: ' + str(startPos))
|
|
self.notify.debug('start velocity: ' + str(startVel))
|
|
self.notify.debug('time of launch: ' + str(launchTime))
|
|
cannon.removeToonReadyToFire()
|
|
shootTask = PythonTask(self.__shootTask, self.taskNameShoot)
|
|
shootTask.info = {'toonId': toonId,
|
|
'cannon': cannon}
|
|
if self.isLocalToonId(toonId):
|
|
self.flyingToonOffsetRotation = 0
|
|
self.flyingToonOffsetAngle = 0
|
|
self.flyingToonOffsetX = 0
|
|
self.flyingToonOffsetY = 0
|
|
self.hitCloud = 0
|
|
self.initialFlyVel = INITIAL_VELOCITY
|
|
self.camNode = NodePath(self.uniqueName('flyingCamera'))
|
|
self.camNode.setScale(0.5)
|
|
self.camNode.setPos(self.localFlyingToon.getPos())
|
|
self.camNode.setHpr(self.localFlyingToon.getHpr())
|
|
self.camNode.reparentTo(render)
|
|
self.lastStartVel = startVel
|
|
place = base.cr.playGame.getPlace()
|
|
place.fsm.request('activity')
|
|
toon.dropShadow.hide()
|
|
self.localFlyingDropShadow = self.shadowNode.copyTo(hidden)
|
|
vel = startVel
|
|
toon.lookAt(toon.getPos() + Vec3(vel[0], vel[1], vel[2]))
|
|
toon.setP(localAvatar, -90)
|
|
hpr = toon.getHpr()
|
|
toon.d_setPosHpr(startPos[0], startPos[1], startPos[2], hpr[0], hpr[1], hpr[2])
|
|
self.localFlyingToon.wrtReparentTo(render)
|
|
info = {}
|
|
info['toonId'] = toonId
|
|
info['trajectory'] = trajectory
|
|
info['launchTime'] = launchTime
|
|
info['toon'] = self.localFlyingToon
|
|
info['hRot'] = cannon.getRotation()
|
|
camera.wrtReparentTo(self.localFlyingToon)
|
|
flyTask = PythonTask(self.__localFlyTask, self.taskNameFly)
|
|
flyTask.info = info
|
|
seqTask = Task.sequence(shootTask, flyTask)
|
|
self.__startCollisionHandler()
|
|
self.notify.debug('Disable standard local toon controls.')
|
|
base.localAvatar.disableAvatarControls()
|
|
frameTime = globalClock.getFrameTime()
|
|
netLaunchTime = globalClockDelta.localToNetworkTime(launchTime + frameTime, bits=31)
|
|
self.sendUpdate('setToonTrajectoryAi', [netLaunchTime,
|
|
startPos[0],
|
|
startPos[1],
|
|
startPos[2],
|
|
startHpr[0],
|
|
startHpr[1],
|
|
startHpr[2],
|
|
startVel[0],
|
|
startVel[1],
|
|
startVel[2]])
|
|
else:
|
|
seqTask = shootTask
|
|
taskMgr.add(seqTask, self.taskName('flyingToon') + '-' + str(toonId))
|
|
toon.startSmooth()
|
|
return Task.done
|
|
|
|
def setToonTrajectory(self, avId, launchTime, x, y, z, h, p, r, vx, vy, vz):
|
|
if avId == localAvatar.doId:
|
|
return
|
|
startPos = Vec3(x, y, z)
|
|
startHpr = Vec3(h, p, r)
|
|
startVel = Vec3(vx, vy, vz)
|
|
startT = globalClockDelta.networkToLocalTime(launchTime, bits=31) + 0.2
|
|
trajectory = Trajectory.Trajectory(0.0, startPos, startVel)
|
|
self._avId2trajectoryInfo[avId] = ScratchPad(startPos=startPos, startHpr=startHpr, startVel=startVel, startT=startT, trajectory=trajectory)
|
|
|
|
def _remoteToonFlyTask(self, task = None):
|
|
ids2del = []
|
|
frameTime = globalClock.getFrameTime()
|
|
for avId, trajInfo in self._avId2trajectoryInfo.iteritems():
|
|
trajectory = trajInfo.trajectory
|
|
startTime = trajInfo.startT
|
|
groundTime = trajectory.calcTimeOfImpactOnPlane(0.0) / self.TimeFactor + startTime
|
|
now = frameTime
|
|
if now < startTime:
|
|
now = startTime
|
|
if now > groundTime:
|
|
now = groundTime
|
|
t = max(0.0, now - startTime)
|
|
t *= self.TimeFactor
|
|
toon = self.cr.getDo(avId)
|
|
if toon is None:
|
|
ids2del.append(avId)
|
|
else:
|
|
toon.setFluidPos(trajectory.getPos(t))
|
|
vel = trajectory.getVel(t)
|
|
toon.lookAt(toon.getPos() + Vec3(vel[0], vel[1], vel[2]))
|
|
toon.setP(toon, -90)
|
|
|
|
for avId in ids2del:
|
|
del self._avId2trajectoryInfo[avId]
|
|
|
|
return Task.cont
|
|
|
|
def __calcFlightResults(self, cannon, toonId, launchTime):
|
|
def quantizeVec(vec, divisor):
|
|
quantize = lambda value, divisor: float(int(value * int(divisor))) / int(divisor)
|
|
vec[0] = quantize(vec[0], divisor)
|
|
vec[1] = quantize(vec[1], divisor)
|
|
vec[2] = quantize(vec[2], divisor)
|
|
|
|
startPos = cannon.getToonFirePos()
|
|
startHpr = cannon.getToonFireHpr()
|
|
startVel = cannon.getToonFireVel()
|
|
quantizeVec(startPos, self.NetDivisor)
|
|
quantizeVec(startHpr, self.NetDivisor)
|
|
quantizeVec(startVel, self.NetDivisor)
|
|
trajectory = Trajectory.Trajectory(launchTime, startPos, startVel)
|
|
self.trajectory = trajectory
|
|
return startPos, startHpr, startVel, trajectory
|
|
|
|
def __shootTask(self, task):
|
|
task.info['cannon'].fire()
|
|
toonId = task.info['toonId']
|
|
toon = base.cr.doId2do.get(toonId)
|
|
if toon:
|
|
toon.loop('swim')
|
|
else:
|
|
self.notify.debug('__shootTask avoided a crash, toon %d not found' % toonId)
|
|
if self.isLocalToonId(task.info['toonId']):
|
|
self.localFlyingDropShadow.reparentTo(render)
|
|
self.gui.enableAimKeys()
|
|
return Task.done
|
|
|
|
def d_setLanded(self, toonId):
|
|
printStack()
|
|
self.notify.debug('d_setLanded %s' % toonId)
|
|
if self.isLocalToonId(toonId):
|
|
if self.cr:
|
|
self.sendUpdate('setLanded', [toonId])
|
|
else:
|
|
self.notify.debug('we avoided crash 2')
|
|
|
|
def setLanded(self, toonId):
|
|
if toonId in self._avId2trajectoryInfo:
|
|
del self._avId2trajectoryInfo[toonId]
|
|
|
|
def landToon(self, toonId):
|
|
self.notify.debug('%s landToon' % self.doId)
|
|
toon = base.cr.doId2do.get(toonId)
|
|
if toon is not None:
|
|
toon.resetLOD()
|
|
if toon == base.localAvatar:
|
|
self.__stopCollisionHandler(base.localAvatar)
|
|
toon.wrtReparentTo(render)
|
|
self.__setToonUpright(toon)
|
|
toon.setPlayRate(1.0, 'run')
|
|
toon.startSmooth()
|
|
toon.setScale(1.0)
|
|
self.ignore(toon.uniqueName('disable'))
|
|
self.__cleanupFlyingToonData(toon)
|
|
toon.dropShadow.show()
|
|
place = base.cr.playGame.getPlace()
|
|
if place is not None:
|
|
if not hasattr(place, 'fsm'):
|
|
return
|
|
if toon is not None and toon == base.localAvatar:
|
|
self.__localDisplayLandedResults()
|
|
return
|
|
|
|
def __localDisplayLandedResults(self):
|
|
if self.flyingToonCloudsHit > 0:
|
|
self._doneCannons = True
|
|
else:
|
|
self.__localToonDoneLanding()
|
|
|
|
def handleRewardDone(self):
|
|
DistributedPartyActivity.handleRewardDone(self)
|
|
if self._doneCannons:
|
|
self.__localToonDoneLanding()
|
|
|
|
def __localToonDoneLanding(self):
|
|
base.cr.playGame.getPlace().fsm.request('walk')
|
|
self.notify.debug('__localToonDoneLanding')
|
|
base.localAvatar.collisionsOn()
|
|
base.localAvatar.startPosHprBroadcast()
|
|
base.localAvatar.enableAvatarControls()
|
|
messenger.send(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT)
|
|
|
|
def __setToonUpright(self, toon, pos = None):
|
|
if toon:
|
|
if self.inWater:
|
|
toon.setP(0)
|
|
toon.setR(0)
|
|
return
|
|
if not pos:
|
|
pos = toon.getPos(render)
|
|
toon.setPos(render, pos)
|
|
toon.loop('neutral')
|
|
if self.localFiringCannon and hasattr(self.localFiringCannon, 'cannonNode'):
|
|
if self.localFiringCannon.cannonNode:
|
|
toon.lookAt(self.localFiringCannon.cannonNode)
|
|
else:
|
|
self.notify.debug('we avoided crash 1.')
|
|
toon.setP(0)
|
|
toon.setR(0)
|
|
toon.setScale(1, 1, 1)
|
|
|
|
def __resetToonToCannon(self, avatar):
|
|
self.notify.debug('__resetToonToCannon')
|
|
if not avatar and self.localFlyingToonId:
|
|
avatar = base.cr.doId2do.get(self.localFlyingToonId, None)
|
|
if avatar:
|
|
self.__resetToon(avatar)
|
|
return
|
|
|
|
def __resetToon(self, avatar, pos = None):
|
|
self.notify.debug('__resetToon')
|
|
if avatar:
|
|
self.__stopCollisionHandler(avatar)
|
|
self.__setToonUpright(avatar, pos)
|
|
if self.isLocalToonId(avatar.doId):
|
|
self.notify.debug('toon setting position to %s' % pos)
|
|
if pos:
|
|
base.localAvatar.setPos(pos)
|
|
camera.reparentTo(avatar)
|
|
self.d_setLanded(avatar.doId)
|
|
|
|
def __updateFlightVelocity(self, trajectory):
|
|
hpr = LRotationf(self.flyingToonOffsetRotation, 0, 0)
|
|
newVel = hpr.xform(self.lastStartVel)
|
|
hpr = LRotationf(0, self.flyingToonOffsetAngle, 0)
|
|
zVel = hpr.xform(self.lastStartVel).getZ()
|
|
if zVel < newVel.getZ():
|
|
newVel.setZ(zVel)
|
|
trajectory.setStartVel(newVel)
|
|
now = globalClock.getFrameTime()
|
|
if now - self._lastBroadcastTime >= self.BroadcastPeriod:
|
|
self._dirtyNewVel = newVel
|
|
if self._dirtyNewVel:
|
|
self.sendUpdate('updateToonTrajectoryStartVelAi', [self._dirtyNewVel[0], self._dirtyNewVel[1], self._dirtyNewVel[2]])
|
|
self._lastBroadcastTime = now
|
|
self._dirtyNewVel = None
|
|
return
|
|
|
|
def updateToonTrajectoryStartVel(self, avId, vx, vy, vz):
|
|
if avId == localAvatar.doId:
|
|
return
|
|
if avId in self._avId2trajectoryInfo:
|
|
self._avId2trajectoryInfo[avId].trajectory.setStartVel(Vec3(vx, vy, vz))
|
|
|
|
def __isFlightKeyPressed(self):
|
|
return self.gui.leftPressed or self.gui.rightPressed or self.gui.upPressed or self.gui.downPressed
|
|
|
|
def __moveFlyingToon(self, toon):
|
|
toonP = toon.getP(render)
|
|
isToonFlyingHorizontal = toonP > -150 and toonP < -30
|
|
OFFSET = 0.25
|
|
rotVel = 0
|
|
if self.gui.leftPressed:
|
|
if isToonFlyingHorizontal:
|
|
rotVel += CANNON_ROTATION_VEL
|
|
else:
|
|
self.flyingToonOffsetX -= OFFSET
|
|
if self.gui.rightPressed:
|
|
if isToonFlyingHorizontal:
|
|
rotVel -= CANNON_ROTATION_VEL
|
|
else:
|
|
self.flyingToonOffsetX += OFFSET
|
|
self.flyingToonOffsetRotation += rotVel * globalClock.getDt()
|
|
angVel = 0
|
|
if self.gui.upPressed:
|
|
if not isToonFlyingHorizontal:
|
|
self.flyingToonOffsetY -= OFFSET
|
|
if self.gui.downPressed:
|
|
if isToonFlyingHorizontal:
|
|
angVel += CANNON_ANGLE_VEL
|
|
else:
|
|
self.flyingToonOffsetY += OFFSET
|
|
self.flyingToonOffsetAngle += angVel * globalClock.getDt()
|
|
|
|
def __stopLocalFlyTask(self, toonId):
|
|
taskMgr.remove(self.taskName('flyingToon') + '-' + str(toonId))
|
|
self.gui.disableAimKeys()
|
|
|
|
def __localFlyTask(self, task):
|
|
toon = task.info['toon']
|
|
if toon.isEmpty():
|
|
self.__resetToonToCannon(self.localFlyingToon)
|
|
return Task.done
|
|
curTime = task.time + task.info['launchTime']
|
|
t = curTime
|
|
t *= self.TimeFactor
|
|
self.lastT = self.t
|
|
self.t = t
|
|
deltaT = self.t - self.lastT
|
|
self.deltaT = deltaT
|
|
if self.hitBumper:
|
|
pos = self.lastPos + self.lastVel * deltaT
|
|
vel = self.lastVel
|
|
self.lastVel += Vec3(0, 0, -32.0) * deltaT
|
|
self.lastPos = pos
|
|
toon.setFluidPos(pos)
|
|
lastR = toon.getR()
|
|
toon.setR(lastR - deltaT * self.angularVel * 2.0)
|
|
cameraView = 0
|
|
else:
|
|
if not self.hitCloud and self.__isFlightKeyPressed():
|
|
self.__moveFlyingToon(toon)
|
|
self.__updateFlightVelocity(task.info['trajectory'])
|
|
if self.hitCloud == 1:
|
|
vel = task.info['trajectory'].getVel(t)
|
|
startPos = toon.getPos(render)
|
|
task.info['trajectory'].setStartTime(t)
|
|
task.info['trajectory'].setStartPos(startPos)
|
|
task.info['trajectory'].setStartVel(self.lastVel)
|
|
toon.lookAt(toon.getPos() + vel)
|
|
toon.setH(-toon.getH())
|
|
now = globalClock.getFrameTime()
|
|
netLaunchTime = globalClockDelta.localToNetworkTime(now, bits=31)
|
|
hpr = toon.getHpr()
|
|
self.sendUpdate('setToonTrajectoryAi', [netLaunchTime,
|
|
startPos[0],
|
|
startPos[1],
|
|
startPos[2],
|
|
hpr[0],
|
|
hpr[1],
|
|
hpr[2],
|
|
self.lastVel[0],
|
|
self.lastVel[1],
|
|
self.lastVel[2]])
|
|
self._lastBroadcastTime = now
|
|
self._dirtyNewVel = None
|
|
self.flyingToonOffsetRotation = 0
|
|
self.flyingToonOffsetAngle = 0
|
|
self.flyingToonOffsetX = 0
|
|
self.flyingToonOffsetY = 0
|
|
self.hitCloud = 2
|
|
pos = task.info['trajectory'].getPos(t)
|
|
toon.setFluidPos(pos)
|
|
toon.setFluidPos(toon, self.flyingToonOffsetX, self.flyingToonOffsetY, 0)
|
|
vel = task.info['trajectory'].getVel(t)
|
|
toon.lookAt(toon.getPos() + Vec3(vel[0], vel[1], vel[2]))
|
|
toon.setP(toon.getP() - 90)
|
|
cameraView = 2
|
|
if self.hitCloud == 2:
|
|
self.lastStartVel = vel
|
|
self.hitCloud = 0
|
|
shadowPos = toon.getPos()
|
|
shadowPos.setZ(SHADOW_Z_OFFSET)
|
|
self.localFlyingDropShadow.setPos(shadowPos)
|
|
if pos.getZ() < -20 or pos.getZ() > 1000:
|
|
self.notify.debug('stopping fly task toon.getZ()=%.2f' % pos.getZ())
|
|
self.__resetToonToCannon(self.localFlyingToon)
|
|
return Task.done
|
|
self.__setFlyingCameraView(task.info['toon'], cameraView, deltaT)
|
|
return Task.cont
|
|
|
|
def __setFlyingCameraView(self, toon, view, deltaT):
|
|
if toon != base.localAvatar:
|
|
return
|
|
lookAt = toon.getPos(render)
|
|
hpr = toon.getHpr(render)
|
|
if view == 0:
|
|
camera.wrtReparentTo(render)
|
|
camera.lookAt(lookAt)
|
|
elif view == 1:
|
|
camera.reparentTo(render)
|
|
camera.setPos(render, 100, 100, 35.25)
|
|
camera.lookAt(render, lookAt)
|
|
elif view == 2:
|
|
if camera.getParent() != self.camNode:
|
|
camera.wrtReparentTo(self.camNode)
|
|
camera.setPos(self.cameraPos)
|
|
camera.lookAt(toon)
|
|
self.camNode.setPos(toon.getPos(render))
|
|
camHpr = self.camNode.getHpr(toon)
|
|
vec = -Point3(0, 0, 0) - camHpr
|
|
relativeSpeed = math.pow(vec.length() / 60.0, 2) + 0.1
|
|
newHpr = camHpr + vec * deltaT * self.cameraSpeed * relativeSpeed
|
|
self.camNode.setHpr(toon, newHpr)
|
|
camera.lookAt(self.camNode)
|
|
camera.setR(render, 0)
|
|
|
|
def __cleanupFlyingToonData(self, toon):
|
|
self.notify.debug('__cleanupFlyingToonData')
|
|
if toon:
|
|
toon.dropShadow.show()
|
|
self.toonIds.remove(toon.doId)
|
|
if self.isLocalToon(toon):
|
|
if self.localFlyingDropShadow != None:
|
|
self.localFlyingDropShadow.removeNode()
|
|
self.localFlyingDropShadow = None
|
|
self.hitBumper = 0
|
|
self.angularVel = 0
|
|
self.vel = Vec3(0, 0, 0)
|
|
self.lastVel = Vec3(0, 0, 0)
|
|
self.lastPos = Vec3(0, 0, 0)
|
|
self.landingPos = Vec3(0, 0, 0)
|
|
self.t = 0
|
|
self.lastT = 0
|
|
self.deltaT = 0
|
|
self.lastWakeTime = 0
|
|
self.localFlyingToon = None
|
|
self.localFlyingToonId = 0
|
|
self.localFiringCannon = None
|
|
if hasattr(self, 'camNode') and self.camNode:
|
|
self.camNode.removeNode()
|
|
self.camNode = None
|
|
return
|
|
|
|
def __startCollisionHandler(self):
|
|
self.flyColSphere = CollisionSphere(0, 0, self.localFlyingToon.getHeight() / 2.0, 1.0)
|
|
self.flyColNode = CollisionNode(self.uniqueName('flySphere'))
|
|
self.flyColNode.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.FloorBitmask)
|
|
self.flyColNode.addSolid(self.flyColSphere)
|
|
self.flyColNodePath = self.localFlyingToon.attachNewNode(self.flyColNode)
|
|
self.flyColNodePath.setColor(1, 0, 0, 1)
|
|
self._activeCollisions = set()
|
|
self.handler = CollisionHandlerQueue()
|
|
self._flyingCollisionTaskName = 'checkFlyingToonCollision-%s' % self.doId
|
|
taskMgr.add(self._checkFlyingToonCollision, self._flyingCollisionTaskName)
|
|
base.cTrav.addCollider(self.flyColNodePath, self.handler)
|
|
|
|
def __stopCollisionHandler(self, avatar):
|
|
self.notify.debug('%s __stopCollisionHandler' % self.doId)
|
|
if self._flyingCollisionTaskName:
|
|
taskMgr.remove(self._flyingCollisionTaskName)
|
|
self._flyingCollisionTaskName = None
|
|
self._activeCollisions = set()
|
|
if avatar:
|
|
avatar.loop('neutral')
|
|
if self.flyColNode:
|
|
self.flyColNode = None
|
|
self.flyColSphere = None
|
|
if self.flyColNodePath:
|
|
base.cTrav.removeCollider(self.flyColNodePath)
|
|
self.flyColNodePath.removeNode()
|
|
self.flyColNodePath = None
|
|
self.handler = None
|
|
return
|
|
|
|
def _checkFlyingToonCollision(self, task = None):
|
|
curCollisions = set()
|
|
if self.handler.getNumEntries():
|
|
self.handler.sortEntries()
|
|
i = self.handler.getNumEntries()
|
|
activeEntry = None
|
|
while i > 0:
|
|
entry = self.handler.getEntry(i - 1)
|
|
k = (str(entry.getFromNodePath()), str(entry.getIntoNodePath()))
|
|
curCollisions.add(k)
|
|
if activeEntry is None and k not in self._activeCollisions:
|
|
activeEntry = entry
|
|
self._activeCollisions.add(k)
|
|
i -= 1
|
|
|
|
if activeEntry is not None:
|
|
self.__handleFlyingToonCollision(activeEntry)
|
|
if self.handler:
|
|
self.handler.clearEntries()
|
|
for k in list(self._activeCollisions):
|
|
if k not in curCollisions:
|
|
self._activeCollisions.remove(k)
|
|
|
|
return Task.cont
|
|
|
|
def __handleFlyingToonCollision(self, collisionEntry):
|
|
self.notify.debug('%s __handleToonCollision' % self.doId)
|
|
if self.localFlyingToon == None or self.flyColNode == None:
|
|
return
|
|
hitNode = collisionEntry.getIntoNode().getName()
|
|
self.notify.debug('hitNode = %s' % hitNode)
|
|
self.notify.debug('hitNodePath.getParent = %s' % collisionEntry.getIntoNodePath().getParent())
|
|
self.vel = self.trajectory.getVel(self.t)
|
|
vel = self.trajectory.getVel(self.t)
|
|
vel.normalize()
|
|
if self.hitBumper:
|
|
vel = self.lastVel * 1
|
|
vel.normalize()
|
|
self.notify.debug('normalized vel=%s' % vel)
|
|
solid = collisionEntry.getInto()
|
|
intoNormal = collisionEntry.getSurfaceNormal(collisionEntry.getIntoNodePath())
|
|
self.notify.debug('old intoNormal = %s' % intoNormal)
|
|
intoNormal = collisionEntry.getSurfaceNormal(render)
|
|
self.notify.debug('new intoNormal = %s' % intoNormal)
|
|
hitPylonAboveWater = False
|
|
hitPylonBelowWater = False
|
|
hitNormal = intoNormal
|
|
if hitNode.find('cSphere') == 0 or hitNode.find('treasureSphere') == 0 or hitNode.find('prop') == 0 or hitNode.find('distAvatarCollNode') == 0 or hitNode.find('CannonSphere') == 0 or hitNode.find('plotSphere') == 0 or hitNode.find('flySphere') == 0 or hitNode.find('FishingSpotSphere') == 0 or hitNode.find('TrampolineTrigger') == 0 or hitNode == 'gagtree_collision' or hitNode == 'sign_collision' or hitNode == 'FlowerSellBox' or hitPylonBelowWater:
|
|
self.notify.debug('--------------hit and ignoring %s' % hitNode)
|
|
return
|
|
if vel.dot(hitNormal) > 0 and not hitNode == 'collision_roof' and not hitNode == 'collision_fence':
|
|
self.notify.debug('--------------hit and ignoring backfacing %s, dot=%s' % (hitNode, vel.dot(hitNormal)))
|
|
return
|
|
intoNode = collisionEntry.getIntoNodePath()
|
|
bumperNodes = ['sky_collision'] + PartyCannonCollisions['bounce'] + PartyCannonCollisions['fence']
|
|
cloudBumpers = PartyCannonCollisions['clouds']
|
|
bumperNodes += cloudBumpers
|
|
if hitNode in bumperNodes or hitNode.find('cogPie') == 0 or PartyCannonCollisions['trampoline_bounce'] in hitNode:
|
|
if hitNode == 'sky_collision' or hitNode in PartyCannonCollisions['fence'] or hitNode.find('cogPie') == 0:
|
|
self.__hitFence(self.localFlyingToon, collisionEntry)
|
|
elif PartyCannonCollisions['trampoline_bounce'] in hitNode or hitNode in PartyCannonCollisions['bounce']:
|
|
if hitNode == 'wall_collision':
|
|
hitSound = self.sndBounce2
|
|
else:
|
|
hitSound = self.sndBounce3
|
|
self.hitCloud = 1
|
|
self.__hitBumper(self.localFlyingToon, collisionEntry, hitSound, kr=0.09, angVel=5)
|
|
self.hitBumper = 0
|
|
elif hitNode in cloudBumpers:
|
|
self.__hitCloudPlatform(self.localFlyingToon, collisionEntry)
|
|
elif hitNode == 'statuaryCol':
|
|
self.__hitStatuary(self.localFlyingToon, collisionEntry)
|
|
else:
|
|
self.notify.debug('*************** hit something else ************')
|
|
return
|
|
else:
|
|
self.__stopCollisionHandler(self.localFlyingToon)
|
|
self.__stopLocalFlyTask(self.localFlyingToonId)
|
|
self.notify.debug('stopping flying since we hit %s' % hitNode)
|
|
if self.isLocalToonId(self.localFlyingToon.doId):
|
|
camera.wrtReparentTo(render)
|
|
if self.localFlyingDropShadow:
|
|
self.localFlyingDropShadow.reparentTo(hidden)
|
|
pos = collisionEntry.getSurfacePoint(render)
|
|
hpr = self.localFlyingToon.getHpr()
|
|
hitPos = collisionEntry.getSurfacePoint(render)
|
|
pos = hitPos
|
|
self.landingPos = pos
|
|
self.notify.debug('hitNode, Normal = %s,%s' % (hitNode, intoNormal))
|
|
track = Sequence()
|
|
track.append(Func(self.localFlyingToon.wrtReparentTo, render))
|
|
if self.isLocalToonId(self.localFlyingToon.doId):
|
|
track.append(Func(self.localFlyingToon.collisionsOff))
|
|
if hitNode in PartyCannonCollisions['ground']:
|
|
track.append(Func(self.__hitGround, self.localFlyingToon, pos))
|
|
track.append(Wait(1.0))
|
|
track.append(Func(self.__setToonUpright, self.localFlyingToon, self.landingPos))
|
|
elif hitNode in PartyCannonCollisions['fence']:
|
|
track.append(Func(self.__hitFence, self.localFlyingToon, collisionEntry))
|
|
elif hitNode == 'collision3':
|
|
track.append(Func(self.__hitWater, self.localFlyingToon, pos, collisionEntry))
|
|
track.append(Wait(2.0))
|
|
track.append(Func(self.__setToonUpright, self.localFlyingToon, self.landingPos))
|
|
elif hitNode.find('cloudSphere') == 0:
|
|
track.append(Func(self.__hitCloudPlatform, self.localFlyingToon, collisionEntry))
|
|
else:
|
|
self.notify.warning('************* unhandled hitNode=%s parent =%s' % (hitNode, collisionEntry.getIntoNodePath().getParent()))
|
|
track.append(Func(self.d_setLanded, self.localFlyingToonId))
|
|
if self.isLocalToonId(self.localFlyingToonId):
|
|
track.append(Func(self.localFlyingToon.collisionsOn))
|
|
if self.hitTrack:
|
|
self.hitTrack.finish()
|
|
self.hitTrack = track
|
|
self.hitTrack.start()
|
|
return
|
|
|
|
def __hitBumper(self, avatar, collisionEntry, sound, kr = 0.6, angVel = 1):
|
|
self.hitBumper = 1
|
|
base.playSfx(sound)
|
|
hitP = avatar.getPos(render)
|
|
self.lastPos = hitP
|
|
normal = collisionEntry.getSurfaceNormal(render)
|
|
self.notify.debug('normal = %s' % normal)
|
|
vel = self.vel * 1
|
|
speed = vel.length()
|
|
vel.normalize()
|
|
self.notify.debug('old vel = %s' % vel)
|
|
if self.hitCloud:
|
|
centerVec = Vec3(-avatar.getPos(self.getParentNodePath()))
|
|
centerVec.setZ(0)
|
|
d = centerVec.length() / 15.0
|
|
centerVec.setZ(abs(centerVec.length() * math.sin(70.0)))
|
|
centerVec.normalize()
|
|
newVel = centerVec * d + normal * 0.2
|
|
newVel = newVel * (kr * speed)
|
|
self.initialFlyVel = kr * speed
|
|
else:
|
|
newVel = (normal * 2.0 + vel) * (kr * speed)
|
|
self.lastVel = newVel
|
|
self.notify.debug('new vel = %s' % newVel)
|
|
self.angularVel = angVel * 360
|
|
if self.hitCloud:
|
|
return
|
|
t = Sequence(Func(avatar.pose, 'lose', 110))
|
|
t.start()
|
|
|
|
def __hitGround(self, avatar, pos, extraArgs = []):
|
|
self.notify.debug('__hitGround')
|
|
hitP = avatar.getPos(render)
|
|
self.notify.debug('hitGround pos = %s, hitP = %s' % (pos, hitP))
|
|
self.notify.debug('avatar hpr = %s' % avatar.getHpr())
|
|
avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0)
|
|
avatar.setHpr(avatar.getH(), -135, 0)
|
|
self.notify.debug('parent = %s' % avatar.getParent())
|
|
self.notify.debug('pos = %s, hpr = %s' % (avatar.getPos(render), avatar.getHpr(render)))
|
|
self.__playDustCloud(avatar, pos)
|
|
base.playSfx(self.sndHitGround)
|
|
avatar.setPlayRate(2.0, 'run')
|
|
avatar.loop('run')
|
|
|
|
def __playDustCloud(self, toon, pos):
|
|
self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + toon.getHeight() / 3.0)
|
|
self.dustCloud.setScale(0.35)
|
|
self.dustCloud.play()
|
|
|
|
def __hitFence(self, avatar, collisionEntry, extraArgs = []):
|
|
self.notify.debug('__hitFence')
|
|
self.__hitBumper(avatar, collisionEntry, self.sndHitHouse, kr=0.2, angVel=3)
|
|
|
|
def __hitWater(self, avatar, pos, collisionEntry, extraArgs = []):
|
|
hitP = avatar.getPos(render)
|
|
if hitP[2] > ToontownGlobals.EstateWakeWaterHeight:
|
|
self.notify.debug('we hit the ground before we hit water')
|
|
self.__hitGround(avatar, pos, extraArgs)
|
|
return
|
|
self.notify.debug('hit water')
|
|
hitP = avatar.getPos(render)
|
|
avatar.loop('neutral')
|
|
self.splash.setPos(hitP)
|
|
self.splash.setZ(ToontownGlobals.EstateWakeWaterHeight)
|
|
self.splash.setScale(2)
|
|
self.splash.play()
|
|
base.playSfx(self.sndHitWater)
|
|
place = base.cr.playGame.getPlace()
|
|
|
|
def __hitStatuary(self, avatar, collisionEntry, extraArgs = []):
|
|
self.__hitBumper(avatar, collisionEntry, self.sndHitHouse, kr=0.4, angVel=5)
|
|
|
|
def d_cloudsColorRequest(self):
|
|
self.notify.debug('cloudsColorRequest')
|
|
self.sendUpdate('cloudsColorRequest')
|
|
|
|
def cloudsColorResponse(self, cloudColorList):
|
|
self.notify.debug('cloudsColorResponse: %s' % cloudColorList)
|
|
for cloudColor in cloudColorList:
|
|
self.setCloudHit(*cloudColor)
|
|
|
|
def d_requestCloudHit(self, cloudNumber, color):
|
|
self.sendUpdate('requestCloudHit', [cloudNumber,
|
|
color.getX(),
|
|
color.getY(),
|
|
color.getZ()])
|
|
|
|
def setCloudHit(self, cloudNumber, r, g, b):
|
|
cloud = render.find('**/cloud-%d' % cloudNumber)
|
|
if not cloud.isEmpty():
|
|
cloud.setColor(r, g, b, 1.0)
|
|
else:
|
|
self.notify.debug('Could not find cloud-%d' % cloudNumber)
|
|
|
|
def __hitCloudPlatform(self, avatar, collisionEntry, extraArgs = []):
|
|
if not self.hitBumper and not self.hitCloud:
|
|
self.hitCloud = 1
|
|
self.__hitBumper(avatar, collisionEntry, self.sndBounce1, kr=0.35, angVel=5)
|
|
self.hitBumper = 0
|
|
if self._lastCloudHit is None:
|
|
cloud = collisionEntry.getIntoNodePath().getParent()
|
|
self._lastCloudHit = cloud
|
|
cloud.setColor(base.localAvatar.style.getHeadColor())
|
|
cloudNumber = int(cloud.getNetTag('number'))
|
|
self.d_requestCloudHit(cloudNumber, base.localAvatar.style.getHeadColor())
|
|
self.__playDustCloud(avatar, collisionEntry.getSurfacePoint(render))
|
|
self.flyingToonCloudsHit += 1
|
|
taskMgr.doMethodLater(0.25, self.__reactivateLastCloudHit, DistributedPartyCannonActivity.REACTIVATE_CLOUD_TASK)
|
|
return
|
|
|
|
def __reactivateLastCloudHit(self, task):
|
|
self._lastCloudHit = None
|
|
return Task.done
|
|
|
|
def __handleFireworksStarted(self):
|
|
self.notify.debug('__handleFireworksStarted')
|
|
base.cr.playGame.hood.loader.fadeClouds()
|
|
|
|
def __handleFireworksFinished(self):
|
|
self.notify.debug('__handleFireworksFinished')
|
|
if self.__checkHoodValidity():
|
|
base.cr.playGame.hood.loader.fadeClouds()
|
|
else:
|
|
self.notify.debug('Toon has left the party')
|
|
|
|
def __checkHoodValidity(self):
|
|
if hasattr(base.cr.playGame, 'hood') and base.cr.playGame.hood and hasattr(base.cr.playGame.hood, 'loader') and base.cr.playGame.hood.loader and hasattr(base.cr.playGame.hood.loader, 'geom') and base.cr.playGame.hood.loader.geom:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def handleToonExited(self, toonId):
|
|
self.notify.debug('DistributedPartyCannonActivity handleToonExited( toonId=%s ) ' % toonId)
|
|
if toonId in self.cr.doId2do:
|
|
self.notify.warning('handleToonExited is not defined')
|