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
|
2019-12-30 00:07:56 -06:00
|
|
|
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
|
2019-12-30 00:07:56 -06:00
|
|
|
for model in list(self.toonModelDict.values()):
|
2019-11-02 17:27:54 -05:00
|
|
|
model.removeNode()
|
|
|
|
|
|
|
|
del self.toonModelDict
|
|
|
|
del self.toonScaleDict
|
2019-12-30 00:07:56 -06:00
|
|
|
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)
|
2019-12-30 00:07:56 -06:00
|
|
|
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()
|
2019-11-23 16:30:18 -06:00
|
|
|
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
|