oldschool-toontown/toontown/minigame/DistributedCannonGame.py

1036 lines
41 KiB
Python
Raw Normal View History

2023-04-29 21:20:11 -05:00
from panda3d.core import Point3, Quat, rad2Deg, Vec3
from panda3d.otp import Nametag, NametagFloat3d
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.fsm.ClassicFSM import ClassicFSM
from direct.fsm.State import State
from direct.gui.DirectGui import DGG, DirectButton, DirectFrame, DirectLabel
from direct.interval.IntervalGlobal import Parallel, Sequence, SoundInterval, Wait
2019-11-02 17:27:54 -05:00
from direct.task.Task import Task
2023-04-29 21:20:11 -05:00
from direct.task.TaskManagerGlobal import taskMgr
from toontown.effects.DustCloud import DustCloud
from toontown.effects.Splash import Splash
from toontown.minigame import CannonGameGlobals
from toontown.minigame import MinigameGlobals
from toontown.minigame.DistributedMinigame import DistributedMinigame
from toontown.minigame.Trajectory import Trajectory
from toontown.toon.ToonHead import ToonHead
from toontown.toonbase import ToontownGlobals
2019-11-02 17:27:54 -05:00
from toontown.toonbase import TTLocalizer
2023-04-29 21:20:11 -05:00
from toontown.toonbase.ToonBaseGlobal import base
from toontown.toonbase.ToontownTimer import ToontownTimer
import math
2019-11-02 17:27:54 -05:00
LAND_TIME = 2
WORLD_SCALE = 2.0
GROUND_SCALE = 1.4 * WORLD_SCALE
CANNON_SCALE = 1.0
FAR_PLANE_DIST = 600 * WORLD_SCALE
CANNON_Y = -int(CannonGameGlobals.TowerYRange / 2 * 1.3)
CANNON_X_SPACING = 12
CANNON_Z = 20
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 = 94.0
WHISTLE_SPEED = INITIAL_VELOCITY * 0.55
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
class DistributedCannonGame(DistributedMinigame):
2023-04-29 21:20:11 -05:00
notify = directNotify.newCategory('DistributedCannonGame')
2019-11-02 17:27:54 -05:00
font = ToontownGlobals.getToonFont()
LOCAL_CANNON_MOVE_TASK = 'localCannonMoveTask'
REWARD_COUNTDOWN_TASK = 'cannonGameRewardCountdown'
HIT_GROUND = 0
HIT_TOWER = 1
HIT_WATER = 2
FIRE_KEY = 'control'
UP_KEY = 'arrow_up'
DOWN_KEY = 'arrow_down'
LEFT_KEY = 'arrow_left'
RIGHT_KEY = 'arrow_right'
INTRO_TASK_NAME = 'CannonGameIntro'
INTRO_TASK_NAME_CAMERA_LERP = 'CannonGameIntroCamera'
def __init__(self, cr):
DistributedMinigame.__init__(self, cr)
2023-04-29 21:20:11 -05:00
self.gameFSM = ClassicFSM('DistributedCannonGame', [State('off', self.enterOff, self.exitOff, ['aim']),
State('aim', self.enterAim, self.exitAim, ['shoot', 'waitForToonsToLand', 'cleanup']),
State('shoot', self.enterShoot, self.exitShoot, ['aim', 'waitForToonsToLand', 'cleanup']),
State('waitForToonsToLand', self.enterWaitForToonsToLand, self.exitWaitForToonsToLand, ['cleanup']),
State('cleanup', self.enterCleanup, self.exitCleanup, [])], 'off', 'cleanup')
2019-11-02 17:27:54 -05:00
self.addChildGameFSM(self.gameFSM)
self.cannonLocationDict = {}
self.cannonPositionDict = {}
self.cannonDict = {}
self.toonModelDict = {}
self.dropShadowDict = {}
self.toonHeadDict = {}
self.toonScaleDict = {}
self.toonIntervalDict = {}
self.leftPressed = 0
self.rightPressed = 0
self.upPressed = 0
self.downPressed = 0
self.cannonMoving = 0
self.modelCount = 14
2019-12-30 23:43:10 -06:00
self.introCameraSeq = None
2019-11-02 17:27:54 -05:00
def getTitle(self):
return TTLocalizer.CannonGameTitle
def getInstructions(self):
return TTLocalizer.CannonGameInstructions
def getMaxDuration(self):
return CannonGameGlobals.GameTime
def load(self):
self.notify.debug('load')
DistributedMinigame.load(self)
2023-04-29 21:20:11 -05:00
self.sky = base.loader.loadModel('phase_3.5/models/props/TT_sky')
self.ground = base.loader.loadModel('phase_4/models/minigames/toon_cannon_gameground')
self.tower = base.loader.loadModel('phase_4/models/minigames/toon_cannon_water_tower')
self.cannon = base.loader.loadModel('phase_4/models/minigames/toon_cannon')
self.dropShadow = base.loader.loadModel('phase_3/models/props/drop_shadow')
self.hill = base.loader.loadModel('phase_4/models/minigames/cannon_hill')
2019-11-02 17:27:54 -05:00
self.sky.setScale(WORLD_SCALE)
self.ground.setScale(GROUND_SCALE)
self.cannon.setScale(CANNON_SCALE)
self.dropShadow.setColor(0, 0, 0, 0.5)
self.ground.setColor(0.85, 0.85, 0.85, 1.0)
self.hill.setScale(1, 1, CANNON_Z / 20.0)
self.dropShadow.setBin('fixed', 0, 1)
2023-04-29 21:20:11 -05:00
self.splash = Splash(base.render)
self.dustCloud = DustCloud(base.render)
purchaseModels = base.loader.loadModel('phase_4/models/gui/purchase_gui')
2019-11-02 17:27:54 -05:00
self.jarImage = purchaseModels.find('**/Jar')
2023-04-29 21:20:11 -05:00
self.jarImage.reparentTo(base.hidden)
self.rewardPanel = DirectLabel(parent=base.hidden, relief=None, pos=(1.16, 0.0, 0.45), scale=0.65, text='', text_scale=0.2, text_fg=(0.95, 0.95, 0, 1), text_pos=(0, -.13), text_font=ToontownGlobals.getSignFont(), image=self.jarImage)
2019-11-02 17:27:54 -05:00
self.rewardPanelTitle = DirectLabel(parent=self.rewardPanel, relief=None, pos=(0, 0, 0.06), scale=0.08, text=TTLocalizer.CannonGameReward, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1))
2020-01-14 13:28:52 -06:00
self.music = base.loader.loadMusic('phase_4/audio/bgm/MG_cannon_game.ogg')
self.sndCannonMove = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg')
self.sndCannonFire = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_fire_alt.ogg')
self.sndHitGround = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg')
self.sndHitTower = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_hit_tower.ogg')
self.sndHitWater = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg')
self.sndWhizz = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_whizz.ogg')
self.sndWin = base.loader.loadSfx('phase_4/audio/sfx/MG_win.ogg')
self.sndRewardTick = base.loader.loadSfx('phase_3.5/audio/sfx/tick_counter.ogg')
2019-11-02 17:27:54 -05:00
guiModel = 'phase_4/models/gui/cannon_game_gui'
2023-04-29 21:20:11 -05:00
cannonGui = base.loader.loadModel(guiModel)
2019-11-02 17:27:54 -05:00
self.aimPad = DirectFrame(image=cannonGui.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8)
cannonGui.removeNode()
self.aimPad.hide()
self.fireButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed)
self.upButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717))
self.downButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180))
self.leftButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90))
self.rightButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90))
self.aimPad.setColor(1, 1, 1, 0.9)
def bindButton(button, upHandler, downHandler):
button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler())
button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler())
bindButton(self.upButton, self.__upPressed, self.__upReleased)
bindButton(self.downButton, self.__downPressed, self.__downReleased)
bindButton(self.leftButton, self.__leftPressed, self.__leftReleased)
bindButton(self.rightButton, self.__rightPressed, self.__rightReleased)
2023-04-29 21:20:11 -05:00
self.timer = ToontownTimer()
2019-11-02 17:27:54 -05:00
self.timer.posInTopRightCorner()
self.timer.hide()
self.DEBUG_TOWER_RANGE = 0
self.DEBUG_CANNON_FAR_LEFT = 0
self.DEBUG_TOWER_NEAR = 1
self.DEBUG_TOWER_FAR_LEFT = 1
def unload(self):
self.notify.debug('unload')
DistributedMinigame.unload(self)
self.sky.removeNode()
del self.sky
self.ground.removeNode()
del self.ground
self.tower.removeNode()
del self.tower
self.cannon.removeNode()
del self.cannon
del self.dropShadowDict
self.dropShadow.removeNode()
del self.dropShadow
self.splash.destroy()
del self.splash
self.dustCloud.destroy()
del self.dustCloud
self.hill.removeNode()
del self.hill
self.rewardPanel.destroy()
del self.rewardPanel
self.jarImage.removeNode()
del self.jarImage
del self.music
del self.sndCannonMove
del self.sndCannonFire
del self.sndHitGround
del self.sndHitTower
del self.sndHitWater
del self.sndWhizz
del self.sndWin
del self.sndRewardTick
self.aimPad.destroy()
del self.aimPad
del self.fireButton
del self.upButton
del self.downButton
del self.leftButton
del self.rightButton
for avId in list(self.toonHeadDict.keys()):
2019-11-02 17:27:54 -05:00
head = self.toonHeadDict[avId]
head.stopBlink()
head.stopLookAroundNow()
av = self.getAvatar(avId)
if av:
av.loop('neutral')
av.setPlayRate(1.0, 'run')
av.nametag.removeNametag(head.tag)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
head.delete()
del self.toonHeadDict
for model in list(self.toonModelDict.values()):
2019-11-02 17:27:54 -05:00
model.removeNode()
del self.toonModelDict
del self.toonScaleDict
for interval in list(self.toonIntervalDict.values()):
2019-11-02 17:27:54 -05:00
interval.finish()
del self.toonIntervalDict
for avId in self.avIdList:
self.cannonDict[avId][0].removeNode()
del self.cannonDict[avId][0]
del self.cannonDict
self.timer.destroy()
del self.timer
del self.cannonLocationDict
self.removeChildGameFSM(self.gameFSM)
del self.gameFSM
def onstage(self):
self.notify.debug('onstage')
DistributedMinigame.onstage(self)
self.__createCannons()
for avId in self.avIdList:
2023-04-29 21:20:11 -05:00
self.cannonDict[avId][0].reparentTo(base.render)
2019-11-02 17:27:54 -05:00
self.towerPos = self.getTowerPosition()
self.tower.setPos(self.towerPos)
2023-04-29 21:20:11 -05:00
self.tower.reparentTo(base.render)
self.sky.reparentTo(base.render)
self.ground.reparentTo(base.render)
2019-11-02 17:27:54 -05:00
self.hill.setPosHpr(0, CANNON_Y + 2.33, 0, 0, 0, 0)
2023-04-29 21:20:11 -05:00
self.hill.reparentTo(base.render)
self.splash.reparentTo(base.render)
self.dustCloud.reparentTo(base.render)
2019-11-02 17:27:54 -05:00
self.__createToonModels(self.localAvId)
2023-04-29 21:20:11 -05:00
base.camera.reparentTo(base.render)
2019-11-02 17:27:54 -05:00
self.__oldCamFar = base.camLens.getFar()
base.camLens.setFar(FAR_PLANE_DIST)
self.__startIntro()
base.transitions.irisIn(0.4)
base.playMusic(self.music, looping=1, volume=0.8)
def offstage(self):
self.notify.debug('offstage')
2023-04-29 21:20:11 -05:00
self.sky.reparentTo(base.hidden)
self.ground.reparentTo(base.hidden)
self.hill.reparentTo(base.hidden)
self.tower.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
for avId in self.avIdList:
2023-04-29 21:20:11 -05:00
self.cannonDict[avId][0].reparentTo(base.hidden)
if avId in self.dropShadowDict:
2023-04-29 21:20:11 -05:00
self.dropShadowDict[avId].reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
av = self.getAvatar(avId)
if av:
av.dropShadow.show()
av.resetLOD()
2023-04-29 21:20:11 -05:00
self.splash.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
self.splash.stop()
2023-04-29 21:20:11 -05:00
self.dustCloud.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
self.dustCloud.stop()
self.__stopIntro()
base.camLens.setFar(self.__oldCamFar)
2023-04-29 21:20:11 -05:00
self.timer.reparentTo(base.hidden)
self.rewardPanel.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
DistributedMinigame.offstage(self)
def getTowerPosition(self):
yRange = TOWER_Y_RANGE
2019-12-30 22:04:48 -06:00
yMin = int(yRange * 0.3)
2019-11-02 17:27:54 -05:00
yMax = yRange
if self.DEBUG_TOWER_RANGE:
if self.DEBUG_TOWER_NEAR:
y = yMin
else:
y = yMax
else:
y = self.randomNumGen.randint(yMin, yMax)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
xRange = TOWER_X_RANGE
if self.DEBUG_TOWER_RANGE:
if self.DEBUG_TOWER_FAR_LEFT:
x = 0
else:
x = xRange
else:
x = self.randomNumGen.randint(0, xRange)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
x = x - int(xRange / 2.0)
if base.wantMinigameDifficulty:
diff = self.getDifficulty()
scale = 0.5 + 0.5 * diff
x *= scale
yCenter = (yMin + yMax) / 2.0
y = (y - yCenter) * scale + yCenter
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
x = float(x) * (float(y) / float(yRange))
y = y - int(yRange / 2.0)
self.notify.debug('getTowerPosition: ' + str(x) + ', ' + str(y))
return Point3(x, y, 0.0)
def __createCannons(self):
for avId in self.avIdList:
2023-04-29 21:20:11 -05:00
cannon = self.cannon.copyTo(base.hidden)
2019-11-02 17:27:54 -05:00
barrel = cannon.find('**/cannon')
self.cannonDict[avId] = [cannon, barrel]
numAvs = self.numPlayers
for i in range(numAvs):
avId = self.avIdList[i]
self.cannonLocationDict[avId] = Point3(i * CANNON_X_SPACING - (numAvs - 1) * CANNON_X_SPACING / 2, CANNON_Y, CANNON_Z)
if self.DEBUG_TOWER_RANGE:
if self.DEBUG_CANNON_FAR_LEFT:
self.cannonLocationDict[avId] = Point3(0 * CANNON_X_SPACING - (4 - 1) * CANNON_X_SPACING / 2, CANNON_Y, CANNON_Z)
else:
self.cannonLocationDict[avId] = Point3(3 * CANNON_X_SPACING - (4 - 1) * CANNON_X_SPACING / 2, CANNON_Y, CANNON_Z)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.cannonPositionDict[avId] = [0, CannonGameGlobals.CANNON_ANGLE_MIN]
self.cannonDict[avId][0].setPos(self.cannonLocationDict[avId])
self.__updateCannonPosition(avId)
def setGameReady(self):
if not self.hasLocalToon:
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.notify.debug('setGameReady')
if DistributedMinigame.setGameReady(self):
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
for avId in self.avIdList:
if avId != self.localAvId:
self.__createToonModels(avId)
def __createToonModels(self, avId):
toon = self.getAvatar(avId)
self.toonScaleDict[avId] = toon.getScale()
toon.useLOD(1000)
2023-04-29 21:20:11 -05:00
toonParent = base.render.attachNewNode('toonOriginChange')
2019-11-02 17:27:54 -05:00
toon.reparentTo(toonParent)
toon.setPosHpr(0, 0, -(toon.getHeight() / 2.0), 0, 0, 0)
self.toonModelDict[avId] = toonParent
2023-04-29 21:20:11 -05:00
head = ToonHead()
2019-11-02 17:27:54 -05:00
head.setupHead(self.getAvatar(avId).style)
2023-04-29 21:20:11 -05:00
head.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
self.toonHeadDict[avId] = head
toon = self.getAvatar(avId)
tag = NametagFloat3d()
tag.setContents(Nametag.CSpeech | Nametag.CThought)
tag.setBillboardOffset(0)
tag.setAvatar(head)
toon.nametag.addNametag(tag)
tagPath = head.attachNewNode(tag.upcastToPandaNode())
tagPath.setPos(0, 0, 1)
head.tag = tag
self.__loadToonInCannon(avId)
self.getAvatar(avId).dropShadow.hide()
2023-04-29 21:20:11 -05:00
self.dropShadowDict[avId] = self.dropShadow.copyTo(base.hidden)
2019-11-02 17:27:54 -05:00
def setGameStart(self, timestamp):
if not self.hasLocalToon:
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.notify.debug('setGameStart')
DistributedMinigame.setGameStart(self, timestamp)
self.__stopIntro()
self.__putCameraBehindCannon()
if not base.config.GetBool('endless-cannon-game', 0):
self.timer.show()
self.timer.countdown(CannonGameGlobals.GameTime, self.__gameTimerExpired)
2023-04-29 21:20:11 -05:00
self.rewardPanel.reparentTo(base.aspect2d)
2019-11-02 17:27:54 -05:00
self.scoreMult = MinigameGlobals.getScoreMult(self.cr.playGame.hood.id)
self.__startRewardCountdown()
self.airborneToons = 0
self.clockStopTime = None
self.gameFSM.request('aim')
def __gameTimerExpired(self):
self.notify.debug('game timer expired')
self.gameOver()
def __playing(self):
return self.gameFSM.getCurrentState() != self.gameFSM.getFinalState()
def updateCannonPosition(self, avId, zRot, angle):
if not self.hasLocalToon:
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if not self.__playing():
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if avId != self.localAvId:
self.cannonPositionDict[avId] = [zRot, angle]
self.__updateCannonPosition(avId)
def setCannonWillFire(self, avId, fireTime, zRot, angle):
if not self.hasLocalToon:
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if not self.__playing():
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.notify.debug('setCannonWillFire: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle) + ', time=' + str(fireTime))
self.cannonPositionDict[avId][0] = zRot
self.cannonPositionDict[avId][1] = angle
self.__updateCannonPosition(avId)
task = Task(self.__fireCannonTask)
task.avId = avId
task.fireTime = fireTime
timeToWait = task.fireTime - self.getCurrentGameTime()
if timeToWait > 0.0:
fireTask = Task.sequence(Task.pause(timeToWait), task)
else:
fireTask = task
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
fireTask = task
taskMgr.add(fireTask, 'fireCannon' + str(avId))
self.airborneToons += 1
def announceToonWillLandInWater(self, avId, landTime):
if not self.hasLocalToon:
return
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.notify.debug('announceToonWillLandInWater: ' + str(avId) + ': time=' + str(landTime))
if self.clockStopTime == None:
self.clockStopTime = landTime
def enterOff(self):
self.notify.debug('enterOff')
def exitOff(self):
pass
def enterAim(self):
self.notify.debug('enterAim')
self.__enableAimInterface()
self.__putCameraBehindCannon()
def exitAim(self):
self.__disableAimInterface()
def enterShoot(self):
self.notify.debug('enterShoot')
self.__broadcastLocalCannonPosition()
self.sendUpdate('setCannonLit', [self.cannonPositionDict[self.localAvId][0], self.cannonPositionDict[self.localAvId][1]])
def exitShoot(self):
pass
def __somebodyWon(self, avId):
if avId == self.localAvId:
base.playSfx(self.sndWin)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.__killRewardCountdown()
self.timer.stop()
self.gameFSM.request('waitForToonsToLand')
def enterWaitForToonsToLand(self):
self.notify.debug('enterWaitForToonsToLand')
if not self.airborneToons:
self.gameOver()
def exitWaitForToonsToLand(self):
pass
def enterCleanup(self):
self.notify.debug('enterCleanup')
self.music.stop()
self.__killRewardCountdown()
if hasattr(self, 'jarIval'):
self.jarIval.finish()
del self.jarIval
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
for avId in self.avIdList:
taskMgr.remove('fireCannon' + str(avId))
taskMgr.remove('flyingToon' + str(avId))
def exitCleanup(self):
pass
def __enableAimInterface(self):
self.aimPad.show()
self.accept(self.FIRE_KEY, self.__fireKeyPressed)
self.accept(self.UP_KEY, self.__upKeyPressed)
self.accept(self.DOWN_KEY, self.__downKeyPressed)
self.accept(self.LEFT_KEY, self.__leftKeyPressed)
self.accept(self.RIGHT_KEY, self.__rightKeyPressed)
self.__spawnLocalCannonMoveTask()
def __disableAimInterface(self):
self.aimPad.hide()
self.ignore(self.FIRE_KEY)
self.ignore(self.UP_KEY)
self.ignore(self.DOWN_KEY)
self.ignore(self.LEFT_KEY)
self.ignore(self.RIGHT_KEY)
self.ignore(self.FIRE_KEY + '-up')
self.ignore(self.UP_KEY + '-up')
self.ignore(self.DOWN_KEY + '-up')
self.ignore(self.LEFT_KEY + '-up')
self.ignore(self.RIGHT_KEY + '-up')
self.__killLocalCannonMoveTask()
def __fireKeyPressed(self):
self.ignore(self.FIRE_KEY)
self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased)
self.__firePressed()
def __upKeyPressed(self):
self.ignore(self.UP_KEY)
self.accept(self.UP_KEY + '-up', self.__upKeyReleased)
self.__upPressed()
def __downKeyPressed(self):
self.ignore(self.DOWN_KEY)
self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased)
self.__downPressed()
def __leftKeyPressed(self):
self.ignore(self.LEFT_KEY)
self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased)
self.__leftPressed()
def __rightKeyPressed(self):
self.ignore(self.RIGHT_KEY)
self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased)
self.__rightPressed()
def __fireKeyReleased(self):
self.ignore(self.FIRE_KEY + '-up')
self.accept(self.FIRE_KEY, self.__fireKeyPressed)
self.__fireReleased()
def __leftKeyReleased(self):
self.ignore(self.LEFT_KEY + '-up')
self.accept(self.LEFT_KEY, self.__leftKeyPressed)
self.__leftReleased()
def __rightKeyReleased(self):
self.ignore(self.RIGHT_KEY + '-up')
self.accept(self.RIGHT_KEY, self.__rightKeyPressed)
self.__rightReleased()
def __upKeyReleased(self):
self.ignore(self.UP_KEY + '-up')
self.accept(self.UP_KEY, self.__upKeyPressed)
self.__upReleased()
def __downKeyReleased(self):
self.ignore(self.DOWN_KEY + '-up')
self.accept(self.DOWN_KEY, self.__downKeyPressed)
self.__downReleased()
def __firePressed(self):
self.notify.debug('fire pressed')
self.gameFSM.request('shoot')
def __upPressed(self):
self.notify.debug('up pressed')
self.upPressed = self.__enterControlActive(self.upPressed)
def __downPressed(self):
self.notify.debug('down pressed')
self.downPressed = self.__enterControlActive(self.downPressed)
def __leftPressed(self):
self.notify.debug('left pressed')
self.leftPressed = self.__enterControlActive(self.leftPressed)
def __rightPressed(self):
self.notify.debug('right pressed')
self.rightPressed = self.__enterControlActive(self.rightPressed)
def __upReleased(self):
self.notify.debug('up released')
self.upPressed = self.__exitControlActive(self.upPressed)
def __downReleased(self):
self.notify.debug('down released')
self.downPressed = self.__exitControlActive(self.downPressed)
def __leftReleased(self):
self.notify.debug('left released')
self.leftPressed = self.__exitControlActive(self.leftPressed)
def __rightReleased(self):
self.notify.debug('right released')
self.rightPressed = self.__exitControlActive(self.rightPressed)
def __enterControlActive(self, control):
return control + 1
def __exitControlActive(self, control):
return max(0, control - 1)
def __spawnLocalCannonMoveTask(self):
self.leftPressed = 0
self.rightPressed = 0
self.upPressed = 0
self.downPressed = 0
self.cannonMoving = 0
task = Task(self.__localCannonMoveTask)
task.lastPositionBroadcastTime = 0.0
taskMgr.add(task, self.LOCAL_CANNON_MOVE_TASK)
def __killLocalCannonMoveTask(self):
taskMgr.remove(self.LOCAL_CANNON_MOVE_TASK)
if self.cannonMoving:
self.sndCannonMove.stop()
def __localCannonMoveTask(self, task):
pos = self.cannonPositionDict[self.localAvId]
oldRot = pos[0]
oldAng = pos[1]
rotVel = 0
if self.leftPressed:
rotVel += CannonGameGlobals.CANNON_ROTATION_VEL
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if self.rightPressed:
rotVel -= CannonGameGlobals.CANNON_ROTATION_VEL
2023-04-29 21:20:11 -05:00
pos[0] += rotVel * base.clock.getDt()
2019-11-02 17:27:54 -05:00
if pos[0] < CannonGameGlobals.CANNON_ROTATION_MIN:
pos[0] = CannonGameGlobals.CANNON_ROTATION_MIN
elif pos[0] > CannonGameGlobals.CANNON_ROTATION_MAX:
pos[0] = CannonGameGlobals.CANNON_ROTATION_MAX
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
angVel = 0
if self.upPressed:
angVel += CannonGameGlobals.CANNON_ANGLE_VEL
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if self.downPressed:
angVel -= CannonGameGlobals.CANNON_ANGLE_VEL
2023-04-29 21:20:11 -05:00
pos[1] += angVel * base.clock.getDt()
2019-11-02 17:27:54 -05:00
if pos[1] < CannonGameGlobals.CANNON_ANGLE_MIN:
pos[1] = CannonGameGlobals.CANNON_ANGLE_MIN
elif pos[1] > CannonGameGlobals.CANNON_ANGLE_MAX:
pos[1] = CannonGameGlobals.CANNON_ANGLE_MAX
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if oldRot != pos[0] or oldAng != pos[1]:
if self.cannonMoving == 0:
self.cannonMoving = 1
base.playSfx(self.sndCannonMove, looping=1)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.__updateCannonPosition(self.localAvId)
if task.time - task.lastPositionBroadcastTime > CANNON_MOVE_UPDATE_FREQ:
task.lastPositionBroadcastTime = task.time
self.__broadcastLocalCannonPosition()
elif self.cannonMoving:
self.cannonMoving = 0
self.sndCannonMove.stop()
self.__broadcastLocalCannonPosition()
2023-04-29 21:20:11 -05:00
return task.cont
2019-11-02 17:27:54 -05:00
def __broadcastLocalCannonPosition(self):
self.sendUpdate('setCannonPosition', [self.cannonPositionDict[self.localAvId][0], self.cannonPositionDict[self.localAvId][1]])
def __updateCannonPosition(self, avId):
self.cannonDict[avId][0].setHpr(self.cannonPositionDict[avId][0], 0.0, 0.0)
self.cannonDict[avId][1].setHpr(0.0, self.cannonPositionDict[avId][1], 0.0)
def __getCameraPositionBehindCannon(self):
return Point3(self.cannonLocationDict[self.localAvId][0], CANNON_Y - 25.0, CANNON_Z + 7)
def __putCameraBehindCannon(self):
2023-04-29 21:20:11 -05:00
base.camera.setPos(self.__getCameraPositionBehindCannon())
base.camera.setHpr(0, 0, 0)
2019-11-02 17:27:54 -05:00
def __loadToonInCannon(self, avId):
self.toonModelDict[avId].detachNode()
head = self.toonHeadDict[avId]
head.startBlink()
head.startLookAround()
head.reparentTo(self.cannonDict[avId][1])
head.setPosHpr(0, 6, 0, 0, -45, 0)
sc = self.toonScaleDict[avId]
2023-04-29 21:20:11 -05:00
head.setScale(base.render, sc[0], sc[1], sc[2])
2019-11-02 17:27:54 -05:00
def __toRadians(self, angle):
return angle * 2.0 * math.pi / 360.0
def __toDegrees(self, angle):
return angle * 360.0 / (2.0 * math.pi)
def __calcFlightResults(self, avId, launchTime):
head = self.toonHeadDict[avId]
2023-04-29 21:20:11 -05:00
startPos = head.getPos(base.render)
startHpr = head.getHpr(base.render)
hpr = self.cannonDict[avId][1].getHpr(base.render)
towerPos = self.tower.getPos(base.render)
2019-11-02 17:27:54 -05:00
rotation = self.__toRadians(hpr[0])
angle = self.__toRadians(hpr[1])
horizVel = INITIAL_VELOCITY * math.cos(angle)
xVel = horizVel * -math.sin(rotation)
yVel = horizVel * math.cos(rotation)
zVel = INITIAL_VELOCITY * math.sin(angle)
startVel = Vec3(xVel, yVel, zVel)
2023-04-29 21:20:11 -05:00
trajectory = Trajectory(launchTime, startPos, startVel)
2019-11-02 17:27:54 -05:00
towerList = [towerPos + Point3(0, 0, BUCKET_HEIGHT), TOWER_RADIUS, TOWER_HEIGHT - BUCKET_HEIGHT]
self.notify.debug('calcFlightResults(%s): rotation(%s), angle(%s), horizVel(%s), xVel(%s), yVel(%s), zVel(%s), startVel(%s), trajectory(%s), towerList(%s)' % (avId,
rotation,
angle,
horizVel,
xVel,
yVel,
zVel,
startVel,
trajectory,
towerList))
timeOfImpact, hitWhat = self.__calcToonImpact(trajectory, towerList)
2019-12-30 23:43:10 -06:00
return startPos, startHpr, startVel, trajectory, timeOfImpact, hitWhat
2019-11-02 17:27:54 -05:00
def __fireCannonTask(self, task):
launchTime = task.fireTime
avId = task.avId
self.notify.debug('FIRING CANNON FOR AVATAR ' + str(avId))
2019-12-30 23:43:10 -06:00
startPos, startHpr, startVel, trajectory, timeOfImpact, hitWhat = self.__calcFlightResults(avId, launchTime)
2019-11-02 17:27:54 -05:00
self.notify.debug('start position: ' + str(startPos))
self.notify.debug('start velocity: ' + str(startVel))
self.notify.debug('time of launch: ' + str(launchTime))
self.notify.debug('time of impact: ' + str(timeOfImpact))
self.notify.debug('location of impact: ' + str(trajectory.getPos(timeOfImpact)))
if hitWhat == self.HIT_WATER:
self.notify.debug('toon will land in the water')
elif hitWhat == self.HIT_TOWER:
self.notify.debug('toon will hit the tower')
else:
self.notify.debug('toon will hit the ground')
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
head = self.toonHeadDict[avId]
head.stopBlink()
head.stopLookAroundNow()
2023-04-29 21:20:11 -05:00
head.reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
av = self.toonModelDict[avId]
2023-04-29 21:20:11 -05:00
av.reparentTo(base.render)
2019-11-02 17:27:54 -05:00
av.setPos(startPos)
av.setHpr(startHpr)
avatar = self.getAvatar(avId)
avatar.loop('swim')
avatar.setPosHpr(0, 0, -(avatar.getHeight() / 2.0), 0, 0, 0)
shootTask = Task(self.__shootTask)
flyTask = Task(self.__flyTask)
seqDoneTask = Task(self.__flySequenceDoneTask)
info = {}
info['avId'] = avId
info['trajectory'] = trajectory
info['launchTime'] = launchTime
info['timeOfImpact'] = timeOfImpact
info['hitWhat'] = hitWhat
info['toon'] = self.toonModelDict[avId]
info['hRot'] = self.cannonPositionDict[avId][0]
info['haveWhistled'] = 0
info['maxCamPullback'] = CAMERA_PULLBACK_MIN
2023-04-29 21:20:11 -05:00
info['timeEnterTowerXY'], info['timeExitTowerXY'] = trajectory.calcEnterAndLeaveCylinderXY(self.tower.getPos(base.render), TOWER_RADIUS)
2019-11-02 17:27:54 -05:00
shootTask.info = info
flyTask.info = info
seqDoneTask.info = info
seqTask = Task.sequence(shootTask, flyTask, Task.pause(LAND_TIME), seqDoneTask)
taskMgr.add(seqTask, 'flyingToon' + str(avId))
if avId == self.localAvId:
if info['hitWhat'] == self.HIT_WATER:
self.sendUpdate('setToonWillLandInWater', [info['timeOfImpact']])
2023-04-29 21:20:11 -05:00
return task.done
2019-11-02 17:27:54 -05:00
def __calcToonImpact(self, trajectory, waterTower):
self.notify.debug('trajectory: %s' % trajectory)
self.notify.debug('waterTower: %s' % waterTower)
waterDiscCenter = Point3(waterTower[0])
waterDiscCenter.setZ(waterDiscCenter[2] + waterTower[2])
t_waterImpact = trajectory.checkCollisionWithDisc(waterDiscCenter, waterTower[1])
self.notify.debug('t_waterImpact: %s' % t_waterImpact)
if t_waterImpact > 0:
return (t_waterImpact, self.HIT_WATER)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
t_towerImpact = trajectory.checkCollisionWithCylinderSides(waterTower[0], waterTower[1], waterTower[2])
self.notify.debug('t_towerImpact: %s' % t_towerImpact)
if t_towerImpact > 0:
return (t_towerImpact, self.HIT_TOWER)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
t_groundImpact = trajectory.checkCollisionWithGround()
self.notify.debug('t_groundImpact: %s' % t_groundImpact)
if t_groundImpact >= trajectory.getStartTime():
return (t_groundImpact, self.HIT_GROUND)
else:
self.notify.error('__calcToonImpact: toon never impacts ground?')
return (self.startTime, self.HIT_GROUND)
def __shootTask(self, task):
base.playSfx(self.sndCannonFire)
2023-04-29 21:20:11 -05:00
self.dropShadowDict[task.info['avId']].reparentTo(base.render)
return task.done
2019-11-02 17:27:54 -05:00
def __flyTask(self, task):
curTime = task.time + task.info['launchTime']
t = min(curTime, task.info['timeOfImpact'])
pos = task.info['trajectory'].getPos(t)
task.info['toon'].setPos(pos)
shadowPos = Point3(pos)
2023-04-29 21:20:11 -05:00
if t >= task.info['timeEnterTowerXY'] and t <= task.info['timeExitTowerXY'] and pos[2] >= self.tower.getPos(base.render)[2] + TOWER_HEIGHT:
shadowPos.setZ(self.tower.getPos(base.render)[2] + TOWER_HEIGHT + SHADOW_Z_OFFSET)
2019-11-02 17:27:54 -05:00
else:
shadowPos.setZ(SHADOW_Z_OFFSET)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.dropShadowDict[task.info['avId']].setPos(shadowPos)
vel = task.info['trajectory'].getVel(t)
run = math.sqrt(vel[0] * vel[0] + vel[1] * vel[1])
rise = vel[2]
theta = self.__toDegrees(math.atan(rise / run))
task.info['toon'].setHpr(task.info['hRot'], -90 + theta, 0)
if task.info['avId'] == self.localAvId:
2023-04-29 21:20:11 -05:00
lookAt = self.tower.getPos(base.render)
2019-11-02 17:27:54 -05:00
lookAt.setZ(lookAt.getZ() - TOWER_HEIGHT / 2.0)
towerPos = Point3(self.towerPos)
towerPos.setZ(TOWER_HEIGHT)
ttVec = Vec3(pos - towerPos)
toonTowerDist = ttVec.length()
multiplier = 0.0
if toonTowerDist < TOON_TOWER_THRESHOLD:
up = Vec3(0.0, 0.0, 1.0)
perp = up.cross(vel)
perp.normalize()
if ttVec.dot(perp) > 0.0:
perp = Vec3(-perp[0], -perp[1], -perp[2])
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
a = 1.0 - toonTowerDist / TOON_TOWER_THRESHOLD
a_2 = a * a
multiplier = -2.0 * a_2 * a + 3 * a_2
lookAt = lookAt + perp * (multiplier * MAX_LOOKAT_OFFSET)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
foo = Vec3(pos - lookAt)
foo.normalize()
task.info['maxCamPullback'] = max(task.info['maxCamPullback'], CAMERA_PULLBACK_MIN + multiplier * (CAMERA_PULLBACK_MAX - CAMERA_PULLBACK_MIN))
foo = foo * task.info['maxCamPullback']
camPos = pos + Point3(foo)
2023-04-29 21:20:11 -05:00
base.camera.setPos(camPos)
base.camera.lookAt(pos)
2019-11-02 17:27:54 -05:00
if task.info['haveWhistled'] == 0:
if -vel[2] > WHISTLE_SPEED:
if t < task.info['timeOfImpact'] - 0.5:
task.info['haveWhistled'] = 1
base.playSfx(self.sndWhizz)
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
if t == task.info['timeOfImpact']:
if task.info['haveWhistled']:
self.sndWhizz.stop()
2023-04-29 21:20:11 -05:00
self.dropShadowDict[task.info['avId']].reparentTo(base.hidden)
2019-11-02 17:27:54 -05:00
avatar = self.getAvatar(task.info['avId'])
if task.info['hitWhat'] == self.HIT_WATER:
avatar.loop('neutral')
self.splash.setPos(task.info['toon'].getPos())
self.splash.setScale(2)
self.splash.play()
base.playSfx(self.sndHitWater)
task.info['toon'].setHpr(task.info['hRot'], 0, 0)
self.__somebodyWon(task.info['avId'])
elif task.info['hitWhat'] == self.HIT_TOWER:
toon = task.info['toon']
pos = toon.getPos()
ttVec = Vec3(pos - self.towerPos)
ttVec.setZ(0)
ttVec.normalize()
h = rad2Deg(math.asin(ttVec[0]))
toon.setHpr(h, 94, 0)
deltaZ = TOWER_HEIGHT - BUCKET_HEIGHT
sf = min(max(pos[2] - BUCKET_HEIGHT, 0), deltaZ) / deltaZ
hitPos = pos + Point3(ttVec * (0.75 * sf))
toon.setPos(hitPos)
hitPos.setZ(hitPos[2] - 1.0)
s = Sequence(Wait(0.5), toon.posInterval(duration=LAND_TIME - 0.5, pos=hitPos, blendType='easeIn'))
self.toonIntervalDict[task.info['avId']] = s
s.start()
avatar.setPos(0, 0, 0)
2019-11-02 17:27:54 -05:00
avatar.pose('slip-forward', 25)
base.playSfx(self.sndHitTower)
elif task.info['hitWhat'] == self.HIT_GROUND:
2023-04-29 21:20:11 -05:00
task.info['toon'].setP(base.render, -150.0)
2019-11-02 17:27:54 -05:00
self.dustCloud.setPos(task.info['toon'], 0, 0, -2.5)
self.dustCloud.setScale(0.35)
self.dustCloud.play()
base.playSfx(self.sndHitGround)
avatar.setPlayRate(2.0, 'run')
avatar.loop('run')
2023-04-29 21:20:11 -05:00
return task.done
return task.cont
2019-11-02 17:27:54 -05:00
def __flySequenceDoneTask(self, task):
self.airborneToons -= 1
if self.gameFSM.getCurrentState().getName() == 'waitForToonsToLand':
if 0 == self.airborneToons:
self.gameOver()
else:
self.__loadToonInCannon(task.info['avId'])
if task.info['avId'] == self.localAvId:
self.gameFSM.request('aim')
2023-04-29 21:20:11 -05:00
return task.done
2019-11-02 17:27:54 -05:00
def __startRewardCountdown(self):
taskMgr.remove(self.REWARD_COUNTDOWN_TASK)
taskMgr.add(self.__updateRewardCountdown, self.REWARD_COUNTDOWN_TASK)
def __killRewardCountdown(self):
taskMgr.remove(self.REWARD_COUNTDOWN_TASK)
def __updateRewardCountdown(self, task):
if not hasattr(self, 'rewardPanel'):
2023-04-29 21:20:11 -05:00
return task.cont
2019-11-02 17:27:54 -05:00
curTime = self.getCurrentGameTime()
if self.clockStopTime is not None:
if self.clockStopTime < curTime:
self.__killRewardCountdown()
curTime = self.clockStopTime
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
score = int(self.scoreMult * CannonGameGlobals.calcScore(curTime) + 0.5)
if not hasattr(task, 'curScore'):
task.curScore = score
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
self.rewardPanel['text'] = str(score)
if task.curScore != score:
if hasattr(self, 'jarIval'):
self.jarIval.finish()
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
s = self.rewardPanel.getScale()
self.jarIval = Parallel(Sequence(self.rewardPanel.scaleInterval(0.15, s * 3.0 / 4.0, blendType='easeOut'), self.rewardPanel.scaleInterval(0.15, s, blendType='easeIn')), SoundInterval(self.sndRewardTick), name='cannonGameRewardJarThrob')
self.jarIval.start()
2023-04-29 21:20:11 -05:00
2019-11-02 17:27:54 -05:00
task.curScore = score
2023-04-29 21:20:11 -05:00
return task.cont
2019-11-02 17:27:54 -05:00
def __startIntro(self):
self.T_WATER = 1
self.T_WATER2LONGVIEW = 1
self.T_LONGVIEW = 1
self.T_LONGVIEW2TOONHEAD = 2
self.T_TOONHEAD = 2
self.T_TOONHEAD2CANNONBACK = 2
taskLookInWater = Task(self.__taskLookInWater)
taskPullBackFromWater = Task(self.__taskPullBackFromWater)
taskFlyUpToToon = Task(self.__flyUpToToon)
taskFlyToBackOfCannon = Task(self.__flyToBackOfCannon)
commonData = {}
taskLookInWater.data = commonData
taskPullBackFromWater.data = commonData
taskFlyUpToToon.data = commonData
taskFlyToBackOfCannon.data = commonData
introTask = Task.sequence(taskLookInWater, Task.pause(self.T_WATER), taskPullBackFromWater, Task.pause(self.T_WATER2LONGVIEW + self.T_LONGVIEW), taskFlyUpToToon, Task.pause(self.T_LONGVIEW2TOONHEAD + self.T_TOONHEAD), taskFlyToBackOfCannon)
taskMgr.add(introTask, self.INTRO_TASK_NAME)
def __stopIntro(self):
taskMgr.remove(self.INTRO_TASK_NAME)
2019-12-30 23:43:10 -06:00
if self.introCameraSeq:
self.introCameraSeq.finish()
self.introCameraSeq = None
2023-04-29 21:20:11 -05:00
base.camera.wrtReparentTo(base.render)
2019-11-02 17:27:54 -05:00
def __spawnCameraLookAtLerp(self, targetPos, targetLookAt, duration):
2023-04-29 21:20:11 -05:00
oldPos = base.camera.getPos()
oldHpr = base.camera.getHpr()
base.camera.setPos(targetPos)
base.camera.lookAt(targetLookAt)
2019-12-30 23:43:10 -06:00
targetQuat = Quat()
2023-04-29 21:20:11 -05:00
targetQuat.setHpr(base.camera.getHpr())
base.camera.setPos(oldPos)
base.camera.setHpr(oldHpr)
self.introCameraSeq = base.camera.posQuatInterval(duration, Point3(targetPos), targetQuat, blendType='easeInOut', name=self.INTRO_TASK_NAME_CAMERA_LERP)
2019-12-30 23:43:10 -06:00
self.introCameraSeq.start()
2019-11-02 17:27:54 -05:00
def __taskLookInWater(self, task):
task.data['cannonCenter'] = Point3(0, CANNON_Y, CANNON_Z)
task.data['towerWaterCenter'] = Point3(self.towerPos + Point3(0, 0, TOWER_HEIGHT))
task.data['vecTowerToCannon'] = Point3(task.data['cannonCenter'] - task.data['towerWaterCenter'])
vecAwayFromCannons = Vec3(Point3(0, 0, 0) - task.data['vecTowerToCannon'])
vecAwayFromCannons.setZ(0.0)
vecAwayFromCannons.normalize()
camLoc = Point3(vecAwayFromCannons * 20) + Point3(0, 0, 20)
camLoc = camLoc + task.data['towerWaterCenter']
2023-04-29 21:20:11 -05:00
base.camera.setPos(camLoc)
base.camera.lookAt(task.data['towerWaterCenter'])
2019-11-02 17:27:54 -05:00
task.data['vecAwayFromCannons'] = vecAwayFromCannons
2023-04-29 21:20:11 -05:00
return task.done
2019-11-02 17:27:54 -05:00
def __taskPullBackFromWater(self, task):
camLoc = Point3(task.data['vecAwayFromCannons'] * 40) + Point3(0, 0, 20)
camLoc = camLoc + task.data['towerWaterCenter']
lookAt = task.data['cannonCenter']
self.__spawnCameraLookAtLerp(camLoc, lookAt, self.T_WATER2LONGVIEW)
2023-04-29 21:20:11 -05:00
return task.done
2019-11-02 17:27:54 -05:00
def __flyUpToToon(self, task):
2023-04-29 21:20:11 -05:00
headPos = self.toonHeadDict[self.localAvId].getPos(base.render)
2019-11-02 17:27:54 -05:00
camLoc = headPos + Point3(0, 5, 0)
lookAt = Point3(headPos)
self.__spawnCameraLookAtLerp(camLoc, lookAt, self.T_LONGVIEW2TOONHEAD)
2023-04-29 21:20:11 -05:00
return task.done
2019-11-02 17:27:54 -05:00
def __flyToBackOfCannon(self, task):
2023-04-29 21:20:11 -05:00
lerpNode = base.hidden.attachNewNode('CannonGameCameraLerpNode')
lerpNode.reparentTo(base.render)
2019-11-02 17:27:54 -05:00
lerpNode.setPos(self.cannonLocationDict[self.localAvId] + Point3(0, 1, 0))
2023-04-29 21:20:11 -05:00
relCamPos = base.camera.getPos(lerpNode)
relCamHpr = base.camera.getHpr(lerpNode)
2019-11-02 17:27:54 -05:00
startRotation = lerpNode.getHpr()
endRotation = Point3(-180, 0, 0)
lerpNode.setHpr(endRotation)
2023-04-29 21:20:11 -05:00
base.camera.setPos(self.__getCameraPositionBehindCannon())
endPos = base.camera.getPos(lerpNode)
2019-11-02 17:27:54 -05:00
lerpNode.setHpr(startRotation)
2023-04-29 21:20:11 -05:00
base.camera.reparentTo(lerpNode)
base.camera.setPos(relCamPos)
base.camera.setHpr(relCamHpr)
self.introCameraSeq = Parallel(lerpNode.hprInterval(self.T_TOONHEAD2CANNONBACK, endRotation, blendType='easeInOut', name=self.INTRO_TASK_NAME_CAMERA_LERP), base.camera.posInterval(self.T_TOONHEAD2CANNONBACK, endPos, blendType='easeInOut', name=self.INTRO_TASK_NAME_CAMERA_LERP))
2019-12-30 23:43:10 -06:00
self.introCameraSeq.start()
2023-04-29 21:20:11 -05:00
return task.done