toontown-just-works/toontown/parties/DistributedPartyCannon.py
2024-07-07 18:08:39 -05:00

449 lines
17 KiB
Python

from panda3d.core import *
from direct.distributed.DistributedObject import DistributedObject
from direct.task.Task import Task
from toontown.minigame import CannonGameGlobals
from toontown.minigame.CannonGameGlobals import *
from toontown.parties.Cannon import Cannon
from toontown.parties.CannonGui import CannonGui
from toontown.parties import PartyGlobals
from toontown.parties.DistributedPartyCannonActivity import DistributedPartyCannonActivity
LAND_TIME = 2
WORLD_SCALE = 2.0
GROUND_SCALE = 1.4 * WORLD_SCALE
CANNON_SCALE = 1.0
FAR_PLANE_DIST = 600 * WORLD_SCALE
GROUND_PLANE_MIN = -15
CANNON_Y = -int(CannonGameGlobals.TowerYRange / 2 * 1.3)
CANNON_X_SPACING = 12
CANNON_Z = 20
CANNON_ROTATION_MIN = -55
CANNON_ROTATION_MAX = 50
CANNON_ROTATION_VEL = 15.0
ROTATIONCANNON_ANGLE_MIN = 15
CANNON_ANGLE_MAX = 85
CANNON_ANGLE_VEL = 15.0
CANNON_MOVE_UPDATE_FREQ = 0.5
CAMERA_PULLBACK_MIN = 20
CAMERA_PULLBACK_MAX = 40
MAX_LOOKAT_OFFSET = 80
TOON_TOWER_THRESHOLD = 150
SHADOW_Z_OFFSET = 0.5
TOWER_HEIGHT = 43.85
TOWER_RADIUS = 10.5
BUCKET_HEIGHT = 36
TOWER_Y_RANGE = CannonGameGlobals.TowerYRange
TOWER_X_RANGE = int(TOWER_Y_RANGE / 2.0)
INITIAL_VELOCITY = 80.0
WHISTLE_SPEED = INITIAL_VELOCITY * 0.35
class DistributedPartyCannon(DistributedObject, Cannon):
notify = directNotify.newCategory('DistributedPartyCannon')
LOCAL_CANNON_MOVE_TASK = 'localCannonMoveTask'
def __init__(self, cr):
DistributedObject.__init__(self, cr)
Cannon.__init__(self, parent=self.getParentNodePath())
self.localCannonMoving = False
self.active = False
self.activityDoId = 0
self.activity = None
self.gui = None
self.toonInsideAvId = 0
self.sign = None
self.controllingToonAvId = None
return
def generateInit(self):
self.load()
self.activate()
def load(self):
self.notify.debug('load')
Cannon.load(self, self.uniqueName('Cannon'))
if base.cr and base.cr.partyManager and base.cr.partyManager.getShowDoid():
nameText = TextNode('nameText')
nameText.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
nameText.setCardDecal(True)
nameText.setCardColor(1.0, 1.0, 1.0, 0.0)
r = 232.0 / 255.0
g = 169.0 / 255.0
b = 23.0 / 255.0
nameText.setTextColor(r, g, b, 1)
nameText.setAlign(nameText.ACenter)
nameText.setShadowColor(0, 0, 0, 1)
nameText.setText(str(self.doId))
namePlate = self.parentNode.attachNewNode(nameText)
namePlate.setDepthWrite(0)
namePlate.setPos(0, 0, 8)
namePlate.setScale(3)
def announceGenerate(self):
self.sign = self.activity.sign.instanceUnderNode(self.activity.getParentNodePath(), self.uniqueName('sign'))
self.sign.reparentTo(self.activity.getParentNodePath())
self.sign.setPos(self.parentNode, self.sign.getPos())
def unload(self):
self.notify.debug('unload')
if self.gui is not None:
self.gui.unload()
del self.gui
Cannon.unload(self)
if self.sign is not None:
self.sign.removeNode()
self.sign = None
self.ignoreAll()
return
def getParentNodePath(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 base.cr.playGame.hood.loader.geom
else:
self.notify.warning('Hood or loader not created, defaulting to render')
return render
def disable(self):
self.notify.debug('disable')
self.ignoreAll()
self.__disableCannonControl()
self.setMovie(PartyGlobals.CANNON_MOVIE_CLEAR, 0)
def delete(self):
self.deactivate()
self.unload()
DistributedObject.delete(self)
def destroy(self):
self.notify.debug('destroy')
DistributedObject.destroy(self)
def setPosHpr(self, x, y, z, h, p, r):
self.parentNode.setPosHpr(x, y, z, h, p, r)
def setActivityDoId(self, doId):
self.activityDoId = doId
self.activity = base.cr.doId2do[doId]
def activate(self):
self.accept(self.getEnterCollisionName(), self.__handleToonCollisionWithCannon)
Cannon.show(self)
self.active = True
def deactivate(self):
self.ignore(self.getEnterCollisionName())
Cannon.hide(self)
self.active = False
def setMovie(self, mode, avId):
self.notify.debug('%s setMovie(%s, %s)' % (self.doId, avId, mode))
if mode == PartyGlobals.CANNON_MOVIE_CLEAR:
self.setClear()
elif mode == PartyGlobals.CANNON_MOVIE_FORCE_EXIT:
self.exitCannon(avId)
self.setClear()
elif mode == PartyGlobals.CANNON_MOVIE_LOAD:
self.enterCannon(avId)
elif mode == PartyGlobals.CANNON_MOVIE_LANDED:
self.setLanded(avId)
else:
self.notify.error('setMovie Unhandled case mode=%d avId=%d' % (mode, avId))
def __handleToonCollisionWithCannon(self, collEntry):
self.notify.debug('collEntry: %s' % collEntry)
if base.cr.playGame.getPlace().getState() == 'walk' and self.toonInsideAvId == 0:
base.cr.playGame.getPlace().setState('activity')
self.d_requestEnter()
def d_requestEnter(self):
self.sendUpdate('requestEnter', [])
def requestExit(self):
self.notify.debug('requestExit')
base.localAvatar.reparentTo(render)
base.cr.playGame.getPlace().setState('walk')
def __avatarGone(self, avId):
if self.toonInsideAvId == avId:
self.notify.debug('__avatarGone in if')
if self.toonInside and not self.toonInside.isEmpty():
self.removeToonDidNotFire()
self.setMovie(PartyGlobals.CANNON_MOVIE_CLEAR, 0)
else:
self.notify.debug('__avatarGone in else, self.toonInsideAvId=%s avId=%s' % (self.toonInsideAvId, avId))
def enterCannon(self, avId):
if avId == base.localAvatar.doId:
base.localAvatar.pose('lose', 110)
base.localAvatar.pose('slip-forward', 25)
base.cr.playGame.getPlace().setState('activity')
base.localAvatar.collisionsOff()
camera.reparentTo(self.barrelNode)
camera.setPos(0, -2, 5)
camera.setP(-20)
if not self.activity.hasPlayedBefore():
self.activity.displayRules()
self.acceptOnce(DistributedPartyCannonActivity.RULES_DONE_EVENT, self.__enableCannonControl)
else:
self.__enableCannonControl()
self.controllingToonAvId = avId
if avId in self.cr.doId2do:
self.toonInsideAvId = avId
self.notify.debug('enterCannon self.toonInsideAvId=%d' % self.toonInsideAvId)
toon = base.cr.doId2do[avId]
if toon:
self.acceptOnce(toon.uniqueName('disable'), self.__avatarGone, extraArgs=[avId])
toon.stopSmooth()
toon.dropShadow.hide()
self.placeToonInside(toon)
else:
self.__avatarGone(avId)
else:
self.notify.warning('Unknown avatar %d in cannon %d' % (avId, self.doId))
def exitCannon(self, avId):
if avId == base.localAvatar.doId:
self.activity.finishRules()
self.ignore(DistributedPartyCannonActivity.RULES_DONE_EVENT)
self.ignoreDisableForAvId(avId)
if self.gui and avId == base.localAvatar.doId:
self.gui.unload()
toon = base.cr.doId2do.get(avId)
if toon and self.getToonInside() == toon:
self.resetToon()
else:
self.notify.debug('not resetting toon, toon=%s, self.getToonInside()=%s' % (toon, self.getToonInside()))
def resetToon(self, pos = None):
self.notify.debug('resetToon')
toon = self.getToonInside()
toonInsideAvId = self.toonInsideAvId
self.notify.debug('%d resetToon self.toonInsideAvId=%d' % (self.doId, self.toonInsideAvId))
self.removeToonDidNotFire()
self.__setToonUpright(toon, pos)
if toonInsideAvId == base.localAvatar.doId:
self.notify.debug('%d resetToon toonInsideAvId ==localAvatar.doId' % self.doId)
if pos:
self.notify.debug('toon setting position to %s' % pos)
base.localAvatar.setPos(pos)
camera.reparentTo(base.localAvatar)
base.localAvatar.collisionsOn()
base.localAvatar.startPosHprBroadcast()
base.localAvatar.enableAvatarControls()
self.notify.debug('currentState=%s, requesting walk' % base.cr.playGame.getPlace().getState())
base.cr.playGame.getPlace().setState('walk')
self.notify.debug('after request walk currentState=%s,' % base.cr.playGame.getPlace().getState())
toon.dropShadow.show()
self.d_setLanded()
def __setToonUpright(self, toon, pos = None):
if not pos:
pos = toon.getPos(render)
toon.setPos(render, pos)
toon.loop('neutral')
toon.lookAt(self.parentNode)
toon.setP(0)
toon.setR(0)
toon.setScale(1, 1, 1)
def d_setLanded(self):
self.notify.debugStateCall(self)
if self.toonInsideAvId == base.localAvatar.doId:
self.sendUpdate('setLanded', [base.localAvatar.doId])
def setLanded(self, avId):
self.removeAvFromCannon(avId)
self.ignoreDisableForAvId(avId)
def removeAvFromCannon(self, avId):
place = base.cr.playGame.getPlace()
av = base.cr.doId2do.get(avId)
print 'removeAvFromCannon'
if place:
if not hasattr(place, 'fsm'):
return
placeState = place.fsm.getCurrentState().getName()
print placeState
if placeState != 'fishing':
if av != None:
av.startSmooth()
self.__destroyToonModels(avId)
return
self.notify.debug('%s removeAvFromCannon' % self.doId)
if av != None:
self.notify.debug('%d removeAvFromCannon: destroying toon models' % self.doId)
av.resetLOD()
if av == base.localAvatar:
if place:
place.fsm.request('walk')
av.setPlayRate(1.0, 'run')
if av.nametag and self.toonHead:
av.nametag.remove(self.toonHead.tag)
if av.getParent().getName() == 'toonOriginChange':
av.wrtReparentTo(render)
self.__setToonUpright(av)
if av == base.localAvatar:
av.startPosHprBroadcast()
av.startSmooth()
av.setScale(1, 1, 1)
self.ignore(av.uniqueName('disable'))
self.__destroyToonModels(avId)
return
def __destroyToonModels(self, avId):
av = base.cr.doId2do.get(avId)
if not av:
return
if av != None:
av.dropShadow.show()
self.hitBumper = 0
self.hitTarget = 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
av = None
self.lastWakeTime = 0
self.localToonShooting = 0
if self.toonHead != None:
self.toonHead.reparentTo(hidden)
self.toonHead.stopBlink()
self.toonHead.stopLookAroundNow()
self.toonHead.delete()
self.toonHead = None
self.model_Created = 0
return
def setClear(self):
toon = base.cr.doId2do.get(self.toonInsideAvId)
toonName = 'None'
self.ignoreDisableForAvId(self.toonInsideAvId)
if toon and self.isToonInside():
toonName = toon.getName()
toon.resetLOD()
toon.setPlayRate(1.0, 'run')
if toon.getParent().getName() == 'toonOriginChange':
toon.wrtReparentTo(render)
self.__setToonUpright(toon)
toon.startSmooth()
toon.setScale(1, 1, 1)
self.ignore(toon.uniqueName('disable'))
if self.toonInsideAvId == base.localAvatar.doId:
toon.startPosHprBroadcast()
try:
base.localAvatar.enableAvatarControls()
except:
self.notify.warning("couldn't enable avatar controls")
base.cr.playGame.getPlace().setState('walk')
else:
self.notify.debug('setClear in else toon=%s, self.isToonInsde()=%s' % (toonName, self.isToonInside()))
self.toonInsideAvId = 0
self.notify.debug('setClear self.toonInsideAvId=%d' % self.toonInsideAvId)
if self.controllingToonAvId == base.localAvatar.doId:
self.notify.debug('set_clear turning off cannon control')
self.__disableCannonControl()
self.controllingToonAvId = 0
def __enableCannonControl(self):
if not self.gui:
self.gui = self.activity.gui
self.gui.load()
self.gui.enable(timer=PartyGlobals.CANNON_TIMEOUT)
self.d_setTimeout()
self.accept(CannonGui.FIRE_PRESSED, self.__handleFirePressed)
self.__startLocalCannonMoveTask()
def d_setTimeout(self):
self.sendUpdate('setTimeout')
def __disableCannonControl(self):
if self.gui:
self.gui.unload()
self.ignore(CannonGui.FIRE_PRESSED)
self.__stopLocalCannonMoveTask()
def __startLocalCannonMoveTask(self):
self.localCannonMoving = False
task = Task(self.__localCannonMoveTask)
task.lastPositionBroadcastTime = 0.0
taskMgr.add(task, self.LOCAL_CANNON_MOVE_TASK)
def __stopLocalCannonMoveTask(self):
taskMgr.remove(self.LOCAL_CANNON_MOVE_TASK)
if self.localCannonMoving:
self.localCannonMoving = False
self.stopMovingSound()
def __localCannonMoveTask(self, task):
rotVel = 0
if self.gui.leftPressed:
rotVel += CANNON_ROTATION_VEL
if self.gui.rightPressed:
rotVel -= CANNON_ROTATION_VEL
self.setRotation(self.getRotation() + rotVel * globalClock.getDt())
angVel = 0
if self.gui.upPressed:
angVel += CANNON_ANGLE_VEL
if self.gui.downPressed:
angVel -= CANNON_ANGLE_VEL
self.setAngle(self.getAngle() + angVel * globalClock.getDt())
if self.hasMoved():
if not self.localCannonMoving:
self.localCannonMoving = True
self.loopMovingSound()
self.updateModel()
if task.time - task.lastPositionBroadcastTime > CANNON_MOVE_UPDATE_FREQ:
self.notify.debug('Broadcast local cannon %s position' % self.doId)
task.lastPositionBroadcastTime = task.time
self.__broadcastLocalCannonPosition()
elif self.localCannonMoving:
self.localCannonMoving = False
self.stopMovingSound()
self.__broadcastLocalCannonPosition()
self.notify.debug('Cannon Rot = %s, Angle = %s' % (self._rotation, self._angle))
return Task.cont
def __broadcastLocalCannonPosition(self):
self.d_setCannonPosition(self._rotation, self._angle)
def d_setCannonPosition(self, zRot, angle):
self.sendUpdate('setCannonPosition', [zRot, angle])
def updateCannonPosition(self, avId, zRot, angle):
if avId and avId == self.toonInsideAvId and avId != base.localAvatar.doId:
self.notify.debug('update cannon %s position zRot = %d, angle = %d' % (self.doId, zRot, angle))
self.setRotation(zRot)
self.setAngle(angle)
self.updateModel()
def __handleFirePressed(self):
self.notify.debug('fire pressed')
self.__disableCannonControl()
self.__broadcastLocalCannonPosition()
self.d_setCannonLit(self._rotation, self._angle)
def d_setCannonLit(self, zRot, angle):
self.sendUpdate('setCannonLit', [zRot, angle])
def fire(self):
if base.localAvatar.doId == self.controllingToonAvId:
self.__disableCannonControl()
self.d_setFired()
self.playFireSequence()
self.controllingToonAvId = None
return
def d_setFired(self):
self.sendUpdate('setFired', [])
def ignoreDisableForAvId(self, avId):
toon = base.cr.doId2do.get(avId)
if toon:
self.notify.debug('ignoring %s' % toon.uniqueName('disable'))
self.ignore(toon.uniqueName('disable'))
else:
self.notify.debug('ignoring disable-%s' % self.toonInsideAvId)
self.ignore('disable-%s' % self.toonInsideAvId)