class SquirtingFlower(SquirtGag): def __init__(self): SquirtGag.__init__(self, CIGlobals.SquirtFlower, GagGlobals.getProp(3.5, 'button'), 3, GagGlobals.FLOWER_HIT_SFX, GagGlobals.FLOWER_HIT_SFX, GagGlobals.NULL_SFX, None, 0, 0, 0) self.setImage('phase_3.5/maps/squirting-flower.png') self.flower = None self.flowerScale = 1.5 self.track = Parallel() self.timeout = 4.0 self.sprayRotation = Vec3(0, 20, 0) return def start(self): SquirtGag.start(self) self.buildFlower() self.build() self.equip() if self.isLocal(): self.startTimeout() self.origin = self.getSprayStartPos() def attachFlower(): flowerJoint = self.avatar.find('**/def_joint_attachFlower') if flowerJoint.isEmpty(): flowerJoint = self.avatar.find('**/joint_attachFlower') self.flower.reparentTo(flowerJoint) self.flower.setY(self.flower.getY()) totalAnimationTime = 2.5 flowerAppear = 1.0 flowerScaleTime = 0.5 animTrack = ActorInterval(self.avatar, 'push-button') self.track.append(animTrack) flowerTrack = Sequence(Func(attachFlower), Wait(flowerAppear), LerpScaleInterval(self.flower, flowerScaleTime, 1.5, startScale=GagGlobals.PNT3NEAR0), Wait(totalAnimationTime - flowerScaleTime - flowerAppear)) flowerTrack.append(Func(self.release)) flowerTrack.append(LerpScaleInterval(self.flower, flowerScaleTime, GagGlobals.PNT3NEAR0)) flowerTrack.append(LerpScaleInterval(self.gag, flowerScaleTime, GagGlobals.PNT3NEAR0)) flowerTrack.append(Func(self.unEquip)) self.track.append(flowerTrack) self.track.start() def getSprayStartPos(self): if not self.avatar.isEmpty() and not self.flower.isEmpty(): self.avatar.update(0) return self.flower.getPos(render) def release(self): SquirtGag.release(self) if not self.avatar.isEmpty() and self.gag: self.sprayJoint = self.flower.find('**/joint_attachSpray') self.sprayRange = self.avatar.getPos(render) + Point3(0, GagGlobals.SELTZER_RANGE, 0) self.doSpray(0.2, 0.2, 0.1, horizScale=0.3, vertScale=0.3) if self.isLocal(): base.localAvatar.sendUpdate('usedGag', [self.id]) def unEquip(self): SquirtGag.unEquip(self) self.cleanup() self.reset() def cleanup(self): if self.flower: self.flower.removeNode() self.flower = None if self.track: self.track.pause() self.track = Parallel() return def setHandJoint(self): if self.avatar: self.handJoint = self.avatar.find('**/def_joint_left_hold') if not self.handJoint: print self.avatar.findAllMatches('**/*joint*') def buildFlower(self): if self.flower: self.flower.removeNode() self.flower = None self.flower = loader.loadModel(GagGlobals.getProp(3.5, 'squirting-flower')) self.flower.setScale(GagGlobals.PNT3NEAR0) return
class DodgeballFirstPerson(FirstPerson): """The first person controls for the local player in Winter Dodgeball""" notify = directNotify.newCategory("DodgeballFirstPerson") MaxPickupDistance = 5.0 def __init__(self, mg): self.mg = mg self.crosshair = None self.soundCatch = None self.vModelRoot = None self.vModel = None self.ival = None self.soundPickup = base.loadSfx( 'phase_4/audio/sfx/MG_snowball_pickup.wav') self.fakeSnowball = loader.loadModel( "phase_5/models/props/snowball.bam") self.hasSnowball = False self.mySnowball = None self.fsm = ClassicFSM.ClassicFSM("DodgeballFirstPerson", [ State.State("off", self.enterOff, self.exitOff), State.State("hold", self.enterHold, self.exitHold), State.State("catch", self.enterCatch, self.exitCatch), State.State("throw", self.enterThrow, self.exitThrow) ], "off", "off") self.fsm.enterInitialState() FirstPerson.__init__(self) def enterOff(self): if self.vModel: self.vModel.hide() def exitOff(self): if self.vModel: self.vModel.show() def enterHold(self): self.ival = Sequence(ActorInterval(self.vModel, "hold-start"), Func(self.vModel.loop, "hold")) self.ival.start() def exitHold(self): if self.ival: self.ival.finish() self.ival = None self.vModel.stop() def enterThrow(self): self.ival = Parallel( Sequence(Wait(0.4), Func(self.mySnowball.b_throw)), Sequence(ActorInterval(self.vModel, "throw"), Func(self.fsm.request, 'off'))) self.ival.start() def exitThrow(self): if self.ival: self.ival.pause() self.ival = None self.vModel.stop() def enterCatch(self): self.ival = Parallel( Sequence(Wait(0.2), Func(self.__tryToCatchOrGrab)), Sequence(ActorInterval(self.vModel, "catch"), Func(self.__maybeHold))) self.ival.start() def __maybeHold(self): if self.hasSnowball: self.fsm.request('hold') else: self.fsm.request('off') def __tryToCatchOrGrab(self): snowballs = list(self.mg.snowballs) snowballs.sort( key=lambda snowball: snowball.getDistance(base.localAvatar)) for i in xrange(len(snowballs)): snowball = snowballs[i] if (not snowball.hasOwner() and not snowball.isAirborne and snowball.getDistance(base.localAvatar) <= DodgeballFirstPerson.MaxPickupDistance): snowball.b_pickup() self.mySnowball = snowball self.fakeSnowball.setPosHpr(0, 0.73, 0, 0, 0, 0) self.fakeSnowball.reparentTo( self.vModel.exposeJoint(None, "modelRoot", "Bone.011")) base.playSfx(self.soundPickup) self.hasSnowball = True break def exitCatch(self): self.vModel.stop() if self.ival: self.ival.pause() self.ival = None def start(self): # Black crosshair because basically the entire arena is white. self.crosshair = getCrosshair(color=(0, 0, 0, 1), hidden=False) self.soundCatch = base.loadSfx( "phase_4/audio/sfx/MG_sfx_vine_game_catch.ogg") self.vModelRoot = camera.attachNewNode('vModelRoot') self.vModelRoot.setPos(-0.09, 1.38, -2.48) self.vModel = Actor( "phase_4/models/minigames/v_dgm.egg", { "hold": "phase_4/models/minigames/v_dgm-ball-hold.egg", "hold-start": "phase_4/models/minigames/v_dgm-ball-hold-start.egg", "throw": "phase_4/models/minigames/v_dgm-ball-throw.egg", "catch": "phase_4/models/minigames/v_dgm-ball-catch.egg" }) self.vModel.setBlend(frameBlend=True) self.vModel.reparentTo(self.vModelRoot) self.vModel.setBin("fixed", 40) self.vModel.setDepthTest(False) self.vModel.setDepthWrite(False) self.vModel.hide() base.localAvatar.walkControls.setWalkSpeed(ToonForwardSpeed, ToonJumpForce, ToonReverseSpeed, ToonRotateSpeed) FirstPerson.start(self) def reallyStart(self): FirstPerson.reallyStart(self) base.localAvatar.startTrackAnimToSpeed() self.accept('mouse3', self.__handleCatchOrGrabButton) self.accept('mouse1', self.__handleThrowButton) def __handleThrowButton(self): if self.hasSnowball and self.mySnowball and self.fsm.getCurrentState( ).getName() == 'hold': self.fakeSnowball.reparentTo(hidden) self.fsm.request('throw') def __handleCatchOrGrabButton(self): if not self.hasSnowball and not self.mySnowball and self.fsm.getCurrentState( ).getName() == 'off': self.fsm.request('catch') def reallyEnd(self): base.localAvatar.setWalkSpeedNormal() FirstPerson.reallyEnd(self)
class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIceWorld.DistributedIceWorld): notify = directNotify.newCategory('DistributedIceGame') MaxLocalForce = 100 MaxPhysicsForce = 25000 def __init__(self, cr): DistributedMinigame.DistributedMinigame.__init__(self, cr) DistributedIceWorld.DistributedIceWorld.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM('DistributedIceGame', [ State.State('off', self.enterOff, self.exitOff, ['inputChoice']), State.State( 'inputChoice', self.enterInputChoice, self.exitInputChoice, ['waitServerChoices', 'moveTires', 'displayVotes', 'cleanup']), State.State('waitServerChoices', self.enterWaitServerChoices, self.exitWaitServerChoices, ['moveTires', 'cleanup']), State.State('moveTires', self.enterMoveTires, self.exitMoveTires, ['synch', 'cleanup']), State.State('synch', self.enterSynch, self.exitSynch, ['inputChoice', 'scoring', 'cleanup']), State.State('scoring', self.enterScoring, self.exitScoring, ['cleanup', 'finalResults', 'inputChoice']), State.State('finalResults', self.enterFinalResults, self.exitFinalResults, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, []) ], 'off', 'cleanup') self.addChildGameFSM(self.gameFSM) self.cameraThreeQuarterView = (0, -22, 45, 0, -62.890000000000001, 0) self.tireDict = {} self.forceArrowDict = {} self.canDrive = False self.timer = None self.timerStartTime = None self.curForce = 0 self.curHeading = 0 self.headingMomentum = 0.0 self.forceMomentum = 0.0 self.allTireInputs = None self.curRound = 0 self.curMatch = 0 self.controlKeyWarningLabel = DirectLabel( text=TTLocalizer.IceGameControlKeyWarning, text_fg=VBase4(1, 0, 0, 1), relief=None, pos=(0.0, 0, 0), scale=0.14999999999999999) self.controlKeyWarningLabel.hide() self.waitingMoveLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForPlayersToFinishMove, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.59999999999999998, 0, -0.75), scale=0.074999999999999997) self.waitingMoveLabel.hide() self.waitingSyncLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForAISync, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.59999999999999998, 0, -0.75), scale=0.074999999999999997) self.waitingSyncLabel.hide() self.infoLabel = DirectLabel(text='', text_fg=VBase4(0, 0, 0, 1), relief=None, pos=(0.0, 0, 0.69999999999999996), scale=0.074999999999999997) self.updateInfoLabel() self.lastForceArrowUpdateTime = 0 self.sendForceArrowUpdateAsap = False self.treasures = [] self.penalties = [] self.obstacles = [] self.controlKeyPressed = False self.controlKeyWarningIval = None def delete(self): DistributedIceWorld.DistributedIceWorld.delete(self) DistributedMinigame.DistributedMinigame.delete(self) if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningLabel.destroy() del self.controlKeyWarningLabel self.waitingMoveLabel.destroy() del self.waitingMoveLabel self.waitingSyncLabel.destroy() del self.waitingSyncLabel self.infoLabel.destroy() del self.infoLabel for treasure in self.treasures: treasure.destroy() del self.treasures for penalty in self.penalties: penalty.destroy() del self.penalties for obstacle in self.obstacles: obstacle.removeNode() del self.obstacles del self.gameFSM def announceGenerate(self): DistributedMinigame.DistributedMinigame.announceGenerate(self) DistributedIceWorld.DistributedIceWorld.announceGenerate(self) self.debugTaskName = self.uniqueName('debugTask') def getTitle(self): return TTLocalizer.IceGameTitle def getInstructions(self): szId = self.getSafezoneId() numPenalties = IceGameGlobals.NumPenalties[szId] result = TTLocalizer.IceGameInstructions if numPenalties == 0: result = TTLocalizer.IceGameInstructionsNoTnt return result def getMaxDuration(self): return 0 def load(self): self.notify.debug('load') DistributedMinigame.DistributedMinigame.load(self) self.music = base.loadMusic('phase_4/audio/bgm/MG_IceGame.mid') self.gameBoard = loader.loadModel( 'phase_4/models/minigames/ice_game_icerink') background = loader.loadModel('phase_4/models/minigames/ice_game_2d') background.reparentTo(self.gameBoard) self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.setupSimulation() index = 0 for avId in self.avIdList: self.setupTire(avId, index) self.setupForceArrow(avId) index += 1 for index in xrange(len(self.avIdList), 4): self.setupTire(-index, index) self.setupForceArrow(-index) self.showForceArrows(realPlayersOnly=True) self.westWallModel = NodePath() if not self.westWallModel.isEmpty(): self.westWallModel.reparentTo(self.gameBoard) self.westWallModel.setPos(IceGameGlobals.MinWall[0], IceGameGlobals.MinWall[1], 0) self.westWallModel.setScale(4) self.eastWallModel = NodePath() if not self.eastWallModel.isEmpty(): self.eastWallModel.reparentTo(self.gameBoard) self.eastWallModel.setPos(IceGameGlobals.MaxWall[0], IceGameGlobals.MaxWall[1], 0) self.eastWallModel.setScale(4) self.eastWallModel.setH(180) self.arrowKeys = ArrowKeys.ArrowKeys() self.target = loader.loadModel('phase_3/models/misc/sphere') self.target.setScale(0.01) self.target.reparentTo(self.gameBoard) self.target.setPos(0, 0, 0) self.scoreCircle = loader.loadModel( 'phase_4/models/minigames/ice_game_score_circle') self.scoreCircle.setScale(0.01) self.scoreCircle.reparentTo(self.gameBoard) self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0) self.scoreCircle.setAlphaScale(0.5) self.scoreCircle.setTransparency(1) self.scoreCircle.hide() self.treasureModel = loader.loadModel( 'phase_4/models/minigames/ice_game_barrel') self.penaltyModel = loader.loadModel( 'phase_4/models/minigames/ice_game_tnt2') self.penaltyModel.setScale(0.75, 0.75, 0.69999999999999996) szId = self.getSafezoneId() obstacles = IceGameGlobals.Obstacles[szId] index = 0 cubicObstacle = IceGameGlobals.ObstacleShapes[szId] for pos in obstacles: newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius) newObstacle = self.createObstacle(newPos, index, cubicObstacle) self.obstacles.append(newObstacle) index += 1 self.countSound = loader.loadSfx( 'phase_3.5/audio/sfx/tick_counter.mp3') self.treasureGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_vine_game_bananas.mp3') self.penaltyGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.tireSounds = [] for tireIndex in xrange(4): tireHit = loader.loadSfx( 'phase_4/audio/sfx/Golf_Hit_Barrier_1.mp3') wallHit = loader.loadSfx('phase_4/audio/sfx/MG_maze_pickup.mp3') obstacleHit = loader.loadSfx( 'phase_4/audio/sfx/Golf_Hit_Barrier_2.mp3') self.tireSounds.append({ 'tireHit': tireHit, 'wallHit': wallHit, 'obstacleHit': obstacleHit }) self.arrowRotateSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_rotate.wav') self.arrowUpSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.mp3') self.arrowDownSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.mp3') self.scoreCircleSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_scoring_1.mp3') def unload(self): self.notify.debug('unload') DistributedMinigame.DistributedMinigame.unload(self) del self.music self.gameBoard.removeNode() del self.gameBoard for forceArrow in self.forceArrowDict.values(): forceArrow.removeNode() del self.forceArrowDict self.scoreCircle.removeNode() del self.scoreCircle del self.countSound def onstage(self): self.notify.debug('onstage') DistributedMinigame.DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) self._DistributedIceGame__placeToon(self.localAvId) self.moveCameraToTop() self.scorePanels = [] base.playMusic(self.music, looping=1, volume=0.80000000000000004) def offstage(self): self.notify.debug('offstage') self.music.stop() self.gameBoard.hide() self.infoLabel.hide() for avId in self.tireDict: self.tireDict[avId]['tireNodePath'].hide() for panel in self.scorePanels: panel.cleanup() del self.scorePanels for obstacle in self.obstacles: obstacle.hide() for treasure in self.treasures: treasure.nodePath.hide() for penalty in self.penalties: penalty.nodePath.hide() for avId in self.avIdList: av = self.getAvatar(avId) if av: av.dropShadow.show() av.resetLOD() continue taskMgr.remove(self.uniqueName('aimtask')) self.arrowKeys.destroy() del self.arrowKeys DistributedMinigame.DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug('handleDisabledAvatar') self.notify.debug('avatar ' + str(avId) + ' disabled') DistributedMinigame.DistributedMinigame.handleDisabledAvatar( self, avId) def setGameReady(self): if not self.hasLocalToon: return None self.notify.debug('setGameReady') if DistributedMinigame.DistributedMinigame.setGameReady(self): return None for index in xrange(self.numPlayers): avId = self.avIdList[index] toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self._DistributedIceGame__placeToon(avId) toon.forwardSpeed = 0 toon.rotateSpeed = False toon.dropShadow.hide() toon.setAnimState('Sit') if avId in self.tireDict: tireNp = self.tireDict[avId]['tireNodePath'] toon.reparentTo(tireNp) toon.setY(1.0) toon.setZ(-3) toon.startLookAround() continue def setGameStart(self, timestamp): if not self.hasLocalToon: return None self.notify.debug('setGameStart') DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp) for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() continue self.scores = [0] * self.numPlayers spacing = 0.40000000000000002 for i in xrange(self.numPlayers): avId = self.avIdList[i] avName = self.getAvatarName(avId) scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel( avId, avName) scorePanel.setScale(0.90000000000000002) scorePanel.setPos(0.75 - spacing * (self.numPlayers - 1 - i), 0.0, 0.875) scorePanel.makeTransparent(0.75) self.scorePanels.append(scorePanel) self.arrowKeys.setPressHandlers([ self._DistributedIceGame__upArrowPressed, self._DistributedIceGame__downArrowPressed, self._DistributedIceGame__leftArrowPressed, self._DistributedIceGame__rightArrowPressed, self._DistributedIceGame__controlPressed ]) def isInPlayState(self): if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == 'play': return False return True def enterOff(self): self.notify.debug('enterOff') def exitOff(self): pass def enterInputChoice(self): self.notify.debug('enterInputChoice') self.forceLocalToonToTire() self.controlKeyPressed = False if self.curRound == 0: self.setupStartOfMatch() else: self.notify.debug('self.curRound = %s' % self.curRound) self.timer = ToontownTimer.ToontownTimer() self.timer.hide() if self.timerStartTime != None: self.startTimer() self.showForceArrows(realPlayersOnly=True) self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0) self.localForceArrow().reparentTo(self.localTireNp()) self.localForceArrow().setY(IceGameGlobals.TireRadius) self.localTireNp().headsUp(self.target) self.notify.debug('self.localForceArrow() heading = %s' % self.localForceArrow().getH()) self.curHeading = self.localTireNp().getH() self.curForce = 25 self.updateLocalForceArrow() for avId in self.forceArrowDict: forceArrow = self.forceArrowDict[avId] forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0) tireNp = self.tireDict[avId]['tireNodePath'] forceArrow.reparentTo(tireNp) forceArrow.setY(IceGameGlobals.TireRadius) tireNp.headsUp(self.target) self.updateForceArrow(avId, tireNp.getH(), 25) taskMgr.add(self._DistributedIceGame__aimTask, self.uniqueName('aimtask')) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() self.sendForceArrowUpdateAsap = False def exitInputChoice(self): if not self.controlKeyPressed: if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningIval = Sequence( Func(self.controlKeyWarningLabel.show), self.controlKeyWarningLabel.colorScaleInterval( 10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1)), Func(self.controlKeyWarningLabel.hide)) self.controlKeyWarningIval.start() if self.timer != None: self.timer.destroy() self.timer = None self.timerStartTime = None self.hideForceArrows() self.arrowRotateSound.stop() self.arrowUpSound.stop() self.arrowDownSound.stop() taskMgr.remove(self.uniqueName('aimtask')) def enterWaitServerChoices(self): self.waitingMoveLabel.show() self.showForceArrows(True) def exitWaitServerChoices(self): self.waitingMoveLabel.hide() self.hideForceArrows() def enterMoveTires(self): for key in self.tireDict: body = self.tireDict[key]['tireBody'] body.setAngularVel(0, 0, 0) body.setLinearVel(0, 0, 0) for index in xrange(len(self.allTireInputs)): input = self.allTireInputs[index] avId = self.avIdList[index] body = self.getTireBody(avId) degs = input[1] + 90 tireNp = self.getTireNp(avId) tireH = tireNp.getH() self.notify.debug('tireH = %s' % tireH) radAngle = deg2Rad(degs) foo = NodePath('foo') dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0) self.notify.debug('dirVector is now=%s' % dirVector) inputForce = input[0] inputForce /= self.MaxLocalForce inputForce *= self.MaxPhysicsForce force = dirVector * inputForce self.notify.debug('adding force %s to %d' % (force, avId)) body.addForce(force) self.enableAllTireBodies() self.totalPhysicsSteps = 0 self.startSim() taskMgr.add(self._DistributedIceGame__moveTiresTask, self.uniqueName('moveTiresTtask')) def exitMoveTires(self): self.forceLocalToonToTire() self.disableAllTireBodies() self.stopSim() self.notify.debug('total Physics steps = %d' % self.totalPhysicsSteps) taskMgr.remove(self.uniqueName('moveTiresTtask')) def enterSynch(self): self.waitingSyncLabel.show() def exitSynch(self): self.waitingSyncLabel.hide() def enterScoring(self): sortedByDistance = [] for avId in self.avIdList: np = self.getTireNp(avId) pos = np.getPos() pos.setZ(0) sortedByDistance.append((avId, pos.length())) def compareDistance(x, y): if x[1] - y[1] > 0: return 1 elif x[1] - y[1] < 0: return -1 else: return 0 sortedByDistance.sort(cmp=compareDistance) self.scoreMovie = Sequence() curScale = 0.01 curTime = 0 self.scoreCircle.setScale(0.01) self.scoreCircle.show() self.notify.debug('newScores = %s' % self.newScores) circleStartTime = 0 for index in xrange(len(sortedByDistance)): distance = sortedByDistance[index][1] avId = sortedByDistance[index][0] scorePanelIndex = self.avIdList.index(avId) time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec if time < 0: time = 0.01 scaleXY = distance + IceGameGlobals.TireRadius self.notify.debug('circleStartTime = %s' % circleStartTime) self.scoreMovie.append( Parallel( LerpScaleInterval(self.scoreCircle, time, Point3(scaleXY, scaleXY, 1.0)), SoundInterval(self.scoreCircleSound, duration=time, startTime=circleStartTime))) circleStartTime += time startScore = self.scorePanels[scorePanelIndex].getScore() destScore = self.newScores[scorePanelIndex] self.notify.debug('for avId %d, startScore=%d, newScores=%d' % (avId, startScore, destScore)) def increaseScores(t, scorePanelIndex=scorePanelIndex, startScore=startScore, destScore=destScore): oldScore = self.scorePanels[scorePanelIndex].getScore() diff = destScore - startScore newScore = int(startScore + diff * t) if newScore > oldScore: base.playSfx(self.countSound) self.scorePanels[scorePanelIndex].setScore(newScore) self.scores[scorePanelIndex] = newScore duration = (destScore - startScore) * IceGameGlobals.ScoreCountUpRate tireNp = self.tireDict[avId]['tireNodePath'] self.scoreMovie.append( Parallel( LerpFunctionInterval(increaseScores, duration), Sequence( LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1))))) curScale += distance self.scoreMovie.append( Func(self.sendUpdate, 'reportScoringMovieDone', [])) self.scoreMovie.start() def exitScoring(self): self.scoreMovie.finish() self.scoreMovie = None self.scoreCircle.hide() def enterFinalResults(self): lerpTrack = Parallel() lerpDur = 0.5 tY = 0.59999999999999998 bY = -0.050000000000000003 lX = -0.5 cX = 0 rX = 0.5 scorePanelLocs = (((cX, bY), ), ((lX, bY), (rX, bY)), ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY), (lX, bY), (rX, bY))) scorePanelLocs = scorePanelLocs[self.numPlayers - 1] for i in xrange(self.numPlayers): panel = self.scorePanels[i] pos = scorePanelLocs[i] lerpTrack.append( Parallel( LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType='easeInOut'), LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType='easeInOut'))) self.showScoreTrack = Parallel( lerpTrack, Sequence(Wait(IceGameGlobals.ShowScoresDuration), Func(self.gameOver))) self.showScoreTrack.start() def exitFinalResults(self): self.showScoreTrack.pause() del self.showScoreTrack def enterCleanup(self): self.notify.debug('enterCleanup') if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() def exitCleanup(self): pass def _DistributedIceGame__placeToon(self, avId): toon = self.getAvatar(avId) if toon: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def setupTire(self, avId, index): (tireNp, tireBody, tireOdeGeom) = self.createTire(index) self.tireDict[avId] = { 'tireNodePath': tireNp, 'tireBody': tireBody, 'tireOdeGeom': tireOdeGeom } if avId <= 0: tireBlocker = tireNp.find('**/tireblockermesh') if not tireBlocker.isEmpty(): tireBlocker.hide() if avId == self.localAvId: tireNp = self.tireDict[avId]['tireNodePath'] self.treasureSphereName = 'treasureCollider' self.treasureCollSphere = CollisionSphere( 0, 0, 0, IceGameGlobals.TireRadius) self.treasureCollSphere.setTangible(0) self.treasureCollNode = CollisionNode(self.treasureSphereName) self.treasureCollNode.setFromCollideMask( ToontownGlobals.PieBitmask) self.treasureCollNode.addSolid(self.treasureCollSphere) self.treasureCollNodePath = tireNp.attachNewNode( self.treasureCollNode) self.treasureHandler = CollisionHandlerEvent() self.treasureHandler.addInPattern('%fn-intoTreasure') base.cTrav.addCollider(self.treasureCollNodePath, self.treasureHandler) eventName = '%s-intoTreasure' % self.treasureCollNodePath.getName() self.notify.debug('eventName = %s' % eventName) self.accept(eventName, self.toonHitSomething) def setupForceArrow(self, avId): arrow = loader.loadModel('phase_4/models/minigames/ice_game_arrow') priority = 0 if avId < 0: priority = -avId else: priority = self.avIdList.index(avId) if avId == self.localAvId: priority = 10 self.forceArrowDict[avId] = arrow def hideForceArrows(self): for forceArrow in self.forceArrowDict.values(): forceArrow.hide() def showForceArrows(self, realPlayersOnly=True): for avId in self.forceArrowDict: if realPlayersOnly: if avId > 0: self.forceArrowDict[avId].show() else: self.forceArrowDict[avId].hide() avId > 0 self.forceArrowDict[avId].show() def localForceArrow(self): if self.localAvId in self.forceArrowDict: return self.forceArrowDict[self.localAvId] else: return None def setChoices(self, input0, input1, input2, input3): pass def startDebugTask(self): taskMgr.add(self.debugTask, self.debugTaskName) def stopDebugTask(self): taskMgr.remove(self.debugTaskName) def debugTask(self, task): if self.canDrive and self.tireDict.has_key(localAvatar.doId): dt = globalClock.getDt() forceMove = 25000 forceMoveDt = forceMove tireBody = self.tireDict[localAvatar.doId]['tireBody'] if self.arrowKeys.upPressed() and not tireBody.isEnabled(): x = 0 y = 1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.downPressed() and not tireBody.isEnabled(): x = 0 y = -1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.leftPressed() and not tireBody.isEnabled(): x = -1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.rightPressed() and not tireBody.isEnabled(): x = 1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) return task.cont def _DistributedIceGame__upArrowPressed(self): pass def _DistributedIceGame__downArrowPressed(self): pass def _DistributedIceGame__leftArrowPressed(self): pass def _DistributedIceGame__rightArrowPressed(self): pass def _DistributedIceGame__controlPressed(self): if self.gameFSM.getCurrentState().getName() == 'inputChoice': self.sendForceArrowUpdateAsap = True self.updateLocalForceArrow() self.controlKeyPressed = True self.sendUpdate('setAvatarChoice', [self.curForce, self.curHeading]) self.gameFSM.request('waitServerChoices') def startTimer(self): now = globalClock.getFrameTime() elapsed = now - self.timerStartTime self.timer.posInTopRightCorner() self.timer.setTime(IceGameGlobals.InputTimeout) self.timer.countdown(IceGameGlobals.InputTimeout - elapsed, self.handleChoiceTimeout) self.timer.show() def setTimerStartTime(self, timestamp): if not self.hasLocalToon: return None self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp) if self.timer != None: self.startTimer() def handleChoiceTimeout(self): self.sendUpdate('setAvatarChoice', [0, 0]) self.gameFSM.request('waitServerChoices') def localTireNp(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]['tireNodePath'] return ret def localTireBody(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]['tireBody'] return ret def getTireBody(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]['tireBody'] return ret def getTireNp(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]['tireNodePath'] return ret def updateForceArrow(self, avId, curHeading, curForce): forceArrow = self.forceArrowDict[avId] tireNp = self.tireDict[avId]['tireNodePath'] tireNp.setH(curHeading) tireBody = self.tireDict[avId]['tireBody'] tireBody.setQuaternion(tireNp.getQuat()) self.notify.debug('curHeading = %s' % curHeading) yScale = curForce / 100.0 yScale *= 1 headY = yScale * 15 xScale = (yScale - 1) / 2.0 + 1.0 shaft = forceArrow.find('**/arrow_shaft') head = forceArrow.find('**/arrow_head') shaft.setScale(xScale, yScale, 1) head.setPos(0, headY, 0) head.setScale(xScale, xScale, 1) def updateLocalForceArrow(self): avId = self.localAvId self.b_setForceArrowInfo(avId, self.curHeading, self.curForce) def _DistributedIceGame__aimTask(self, task): if not hasattr(self, 'arrowKeys'): return task.done dt = globalClock.getDt() headingMomentumChange = dt * 60.0 forceMomentumChange = dt * 160.0 arrowUpdate = False arrowRotating = False arrowUp = False arrowDown = False if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce += self.forceMomentum * dt arrowUpdate = True if oldForce < self.MaxLocalForce: arrowUp = True elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce -= self.forceMomentum * dt arrowUpdate = True if oldForce > 0.01: arrowDown = True else: self.forceMomentum = 0 if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading += self.headingMomentum * dt arrowUpdate = True arrowRotating = True elif self.arrowKeys.rightPressed( ) and not self.arrowKeys.leftPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading -= self.headingMomentum * dt arrowUpdate = True arrowRotating = True else: self.headingMomentum = 0 if arrowUpdate: self.normalizeHeadingAndForce() self.updateLocalForceArrow() if arrowRotating: if not self.arrowRotateSound.status( ) == self.arrowRotateSound.PLAYING: base.playSfx(self.arrowRotateSound, looping=True) else: self.arrowRotateSound.stop() if arrowUp: if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING: base.playSfx(self.arrowUpSound, looping=False) else: self.arrowUpSound.stop() if arrowDown: if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING: base.playSfx(self.arrowDownSound, looping=False) else: self.arrowDownSound.stop() return task.cont def normalizeHeadingAndForce(self): if self.curForce > self.MaxLocalForce: self.curForce = self.MaxLocalForce if self.curForce < 0.01: self.curForce = 0.01 def setTireInputs(self, tireInputs): if not self.hasLocalToon: return None self.allTireInputs = tireInputs self.gameFSM.request('moveTires') def enableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]['tireBody'].enable() def disableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]['tireBody'].disable() def areAllTiresDisabled(self): for avId in self.tireDict.keys(): if self.tireDict[avId]['tireBody'].isEnabled(): return False continue return True def _DistributedIceGame__moveTiresTask(self, task): if self.areAllTiresDisabled(): self.sendTirePositions() self.gameFSM.request('synch') return task.done return task.cont def sendTirePositions(self): tirePositions = [] for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) self.sendUpdate('endingPositions', [tirePositions]) def setFinalPositions(self, finalPos): if not self.hasLocalToon: return None for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) def updateInfoLabel(self): self.infoLabel['text'] = TTLocalizer.IceGameInfo % { 'curMatch': self.curMatch + 1, 'numMatch': IceGameGlobals.NumMatches, 'curRound': self.curRound + 1, 'numRound': IceGameGlobals.NumRounds } def setMatchAndRound(self, match, round): if not self.hasLocalToon: return None self.curMatch = match self.curRound = round self.updateInfoLabel() def setScores(self, match, round, scores): if not self.hasLocalToon: return None self.newMatch = match self.newRound = round self.newScores = scores def setNewState(self, state): if not self.hasLocalToon: return None self.notify.debug('setNewState gameFSM=%s newState=%s' % (self.gameFSM, state)) self.gameFSM.request(state) def putAllTiresInStartingPositions(self): for index in xrange(len(self.avIdList)): avId = self.avIdList[index] np = self.tireDict[avId]['tireNodePath'] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]['tireBody'] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) for index in xrange(len(self.avIdList), 4): avId = -index np = self.tireDict[avId]['tireNodePath'] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]['tireBody'] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) def b_setForceArrowInfo(self, avId, force, heading): self.setForceArrowInfo(avId, force, heading) self.d_setForceArrowInfo(avId, force, heading) def d_setForceArrowInfo(self, avId, force, heading): sendIt = False curTime = self.getCurrentGameTime() if self.sendForceArrowUpdateAsap: sendIt = True elif curTime - self.lastForceArrowUpdateTime > 0.20000000000000001: sendIt = True if sendIt: self.sendUpdate('setForceArrowInfo', [avId, force, heading]) self.sendForceArrowUpdateAsap = False self.lastForceArrowUpdateTime = self.getCurrentGameTime() def setForceArrowInfo(self, avId, force, heading): if not self.hasLocalToon: return None self.updateForceArrow(avId, force, heading) def setupStartOfMatch(self): self.putAllTiresInStartingPositions() szId = self.getSafezoneId() self.numTreasures = IceGameGlobals.NumTreasures[szId] if self.treasures: for treasure in self.treasures: treasure.destroy() self.treasures = [] index = 0 treasureMargin = IceGameGlobals.TireRadius + 1.0 while len(self.treasures) < self.numTreasures: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug('yPos=%s' % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newTreasure = IceTreasure.IceTreasure(self.treasureModel, pos, index, self.doId, penalty=False) goodSpot = True for obstacle in self.obstacles: if newTreasure.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break continue if goodSpot: for treasure in self.treasures: if newTreasure.nodePath.getDistance( treasure.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: self.treasures.append(newTreasure) index += 1 continue newTreasure.destroy() self.numPenalties = IceGameGlobals.NumPenalties[szId] if self.penalties: for penalty in self.penalties: penalty.destroy() self.penalties = [] index = 0 while len(self.penalties) < self.numPenalties: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug('yPos=%s' % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newPenalty = IceTreasure.IceTreasure(self.penaltyModel, pos, index, self.doId, penalty=True) goodSpot = True for obstacle in self.obstacles: if newPenalty.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break continue if goodSpot: for treasure in self.treasures: if newPenalty.nodePath.getDistance( treasure.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: for penalty in self.penalties: if newPenalty.nodePath.getDistance( penalty.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: self.penalties.append(newPenalty) index += 1 continue newPenalty.destroy() def toonHitSomething(self, entry): self.notify.debug('---- treasure Enter ---- ') self.notify.debug('%s' % entry) name = entry.getIntoNodePath().getName() parts = name.split('-') if len(parts) < 3: self.notify.debug('collided with %s, but returning' % name) return None if not int(parts[1]) == self.doId: self.notify.debug("collided with %s, but doId doesn't match" % name) return None treasureNum = int(parts[2]) if 'penalty' in parts[0]: self._DistributedIceGame__penaltyGrabbed(treasureNum) else: self._DistributedIceGame__treasureGrabbed(treasureNum) def _DistributedIceGame__treasureGrabbed(self, treasureNum): self.treasures[treasureNum].showGrab() self.treasureGrabSound.play() self.sendUpdate('claimTreasure', [treasureNum]) def setTreasureGrabbed(self, avId, treasureNum): if not self.hasLocalToon: return None self.notify.debug('treasure %s grabbed by %s' % (treasureNum, avId)) if avId != self.localAvId: self.treasures[treasureNum].showGrab() i = self.avIdList.index(avId) self.scores[i] += 1 self.scorePanels[i].setScore(self.scores[i]) def _DistributedIceGame__penaltyGrabbed(self, penaltyNum): self.penalties[penaltyNum].showGrab() self.sendUpdate('claimPenalty', [penaltyNum]) def setPenaltyGrabbed(self, avId, penaltyNum): if not self.hasLocalToon: return None self.notify.debug('penalty %s grabbed by %s' % (penaltyNum, avId)) if avId != self.localAvId: self.penalties[penaltyNum].showGrab() i = self.avIdList.index(avId) self.scores[i] -= 1 self.scorePanels[i].setScore(self.scores[i]) def postStep(self): DistributedIceWorld.DistributedIceWorld.postStep(self) for count in range(self.colCount): (c0, c1) = self.getOrderedContacts(count) if c1 in self.tireCollideIds: tireIndex = self.tireCollideIds.index(c1) if c0 in self.tireCollideIds: self.tireSounds[tireIndex]['tireHit'].play() elif c0 == self.wallCollideId: self.tireSounds[tireIndex]['wallHit'].play() elif c0 == self.obstacleCollideId: self.tireSounds[tireIndex]['obstacleHit'].play() c0 in self.tireCollideIds def forceLocalToonToTire(self): toon = localAvatar if toon and self.localAvId in self.tireDict: tireNp = self.tireDict[self.localAvId]['tireNodePath'] toon.reparentTo(tireNp) toon.setPosHpr(0, 0, 0, 0, 0, 0) toon.setY(1.0) toon.setZ(-3)
class TestCutscene: def __init__(self, dcs): self.dcs = dcs self.ival = None def run(self): boss = base.bspLoader.getPyEntityByTargetName("groom_boss_suit") boss.show() boss.cleanupPropeller() boss.animFSM.request('neutral') camera.reparentTo(boss) onBtn = base.bspLoader.getPyEntityByTargetName("powerovrd_on_button") # press animation (fingerwag): 1-31 32-1 buttonPos = (-1105 / 16.0, 2683 / 16.0, 76 / 16.0) camBtnPosHpr = (-1027 / 16.0, 2638 / 16.0, 96 / 16.0, 135 - 90, 30, 0) camBtnPosHpr2 = (-1009 / 16.0, 2764 / 16.0, 169 / 16.0, 232 - 90, 0, 0) def __pingpongboss_speak(): boss.pingpong("speak", fromFrame=95, toFrame=100) def __boss_pressseq(): return Sequence( ActorInterval(boss, "fingerwag", startFrame=1, endFrame=31), Func(onBtn.d_requestPress), ActorInterval(boss, "fingerwag", startFrame=32, endFrame=1)) def __localavplay_duck(): base.localAvatar.setAnimState('off') base.localAvatar.play("duck", fromFrame=19) numGoons = 6 goonWakeup = Parallel() for i in xrange(numGoons): delay = random.uniform(0.0, 0.5) goon = base.bspLoader.getPyEntityByTargetName( "groom_goon_{0}".format(i)) goonWakeup.append(Sequence(Wait(delay), Func(goon.wakeup))) bdoor = base.bspLoader.getPyEntityByTargetName("to_groom_botdoor") tdoor = base.bspLoader.getPyEntityByTargetName("to_groom_topdoor") oldHpr = boss.getHpr(render) bossTrack = Parallel( Sequence( Wait(10.0), Func(boss.setHpr, oldHpr), ActorInterval(boss, "speak", startFrame=55, endFrame=105, playRate=1.5), #Func(__pingpongboss_speak), Wait(2.0), Func(boss.loop, "neutral")), Sequence( Func(boss.play, "speak"), Func(boss.setChat, "What's this?! How did a Toon get down here?"), Wait(2.5), Func( boss.setChat, "The only place you'll be going is back to the playground." ), Func(boss.loop, "walk"), Func(boss.headsUp, *buttonPos), LerpPosInterval(boss, 2.5, buttonPos), __boss_pressseq(), Wait(2.5), Func(boss.setChat, "Goons, ATTACK!!!"))) camTrack = Sequence( Func(camera.setPos, 2.5, 14, 7), Func(camera.lookAt, boss, 0, 0, 4), Wait(2.5), Func(camera.reparentTo, render), Func(camera.setPosHpr, *camBtnPosHpr), Wait(2.0), Func(camera.setPosHpr, *camBtnPosHpr2), Wait(0.5), Wait(3.0), Func(camera.setPosHpr, 4.351, 126.686, 5.5, -154.16, 16.11, 0), Wait(0.3), Func(bdoor.request, 'Closing'), Func(tdoor.request, 'Closing'), Func(__localavplay_duck), Wait(0.9), Func(base.doCamShake, 0.5, 0.35), Wait(0.9), Func(camera.reparentTo, boss), Func(camera.setPos, 2.5, 17, 7), Func(camera.lookAt, boss, 0, 0, 4), LerpPosHprInterval(camera, duration=0.75, blendType='easeOut', pos=(1, 5, 4), hpr=(165, 20, 0)), Wait(1.75), Func(camera.reparentTo, render), Func(camera.setPosHpr, 88 / 16.0, 2746 / 16.0, 127 / 16.0, 71 - 90, -10, 0)) goonTrack = Sequence(Wait(12.6), goonWakeup) self.ival = Parallel(camTrack, bossTrack, goonTrack) self.ival.start() def stop(self): if self.ival: self.ival.pause() self.ival = None def cleanup(self): self.dcs = None
class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIceWorld.DistributedIceWorld): notify = directNotify.newCategory("DistributedIceGame") MaxLocalForce = 100 MaxPhysicsForce = 25000 def __init__(self, cr): DistributedMinigame.DistributedMinigame.__init__(self, cr) DistributedIceWorld.DistributedIceWorld.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM( "DistributedIceGame", [ State.State("off", self.enterOff, self.exitOff, ["inputChoice"]), State.State( "inputChoice", self.enterInputChoice, self.exitInputChoice, ["waitServerChoices", "moveTires", "displayVotes", "cleanup"], ), State.State( "waitServerChoices", self.enterWaitServerChoices, self.exitWaitServerChoices, ["moveTires", "cleanup"], ), State.State("moveTires", self.enterMoveTires, self.exitMoveTires, ["synch", "cleanup"]), State.State("synch", self.enterSynch, self.exitSynch, ["inputChoice", "scoring", "cleanup"]), State.State("scoring", self.enterScoring, self.exitScoring, ["cleanup", "finalResults", "inputChoice"]), State.State("finalResults", self.enterFinalResults, self.exitFinalResults, ["cleanup"]), State.State("cleanup", self.enterCleanup, self.exitCleanup, []), ], "off", "cleanup", ) self.addChildGameFSM(self.gameFSM) self.cameraThreeQuarterView = (0, -22, 45, 0, -62.89, 0) self.tireDict = {} self.forceArrowDict = {} self.canDrive = False self.timer = None self.timerStartTime = None self.curForce = 0 self.curHeading = 0 self.headingMomentum = 0.0 self.forceMomentum = 0.0 self.allTireInputs = None self.curRound = 0 self.curMatch = 0 self.controlKeyWarningLabel = DirectLabel( text=TTLocalizer.IceGameControlKeyWarning, text_fg=VBase4(1, 0, 0, 1), relief=None, pos=(0.0, 0, 0), scale=0.15, ) self.controlKeyWarningLabel.hide() self.waitingMoveLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForPlayersToFinishMove, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075, ) self.waitingMoveLabel.hide() self.waitingSyncLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForAISync, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075, ) self.waitingSyncLabel.hide() self.infoLabel = DirectLabel(text="", text_fg=VBase4(0, 0, 0, 1), relief=None, pos=(0.0, 0, 0.7), scale=0.075) self.updateInfoLabel() self.lastForceArrowUpdateTime = 0 self.sendForceArrowUpdateAsap = False self.treasures = [] self.penalties = [] self.obstacles = [] self.controlKeyPressed = False self.controlKeyWarningIval = None return def delete(self): DistributedIceWorld.DistributedIceWorld.delete(self) DistributedMinigame.DistributedMinigame.delete(self) if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningLabel.destroy() del self.controlKeyWarningLabel self.waitingMoveLabel.destroy() del self.waitingMoveLabel self.waitingSyncLabel.destroy() del self.waitingSyncLabel self.infoLabel.destroy() del self.infoLabel for treasure in self.treasures: treasure.destroy() del self.treasures for penalty in self.penalties: penalty.destroy() del self.penalties for obstacle in self.obstacles: obstacle.removeNode() del self.obstacles del self.gameFSM return def announceGenerate(self): DistributedMinigame.DistributedMinigame.announceGenerate(self) DistributedIceWorld.DistributedIceWorld.announceGenerate(self) self.debugTaskName = self.uniqueName("debugTask") def getTitle(self): return TTLocalizer.IceGameTitle def getInstructions(self): szId = self.getSafezoneId() numPenalties = IceGameGlobals.NumPenalties[szId] result = TTLocalizer.IceGameInstructions if numPenalties == 0: result = TTLocalizer.IceGameInstructionsNoTnt return result def getMaxDuration(self): return 0 def load(self): self.notify.debug("load") DistributedMinigame.DistributedMinigame.load(self) self.music = base.loadMusic("phase_4/audio/bgm/MG_IceGame.ogg") self.gameBoard = loader.loadModel("phase_4/models/minigames/ice_game_icerink") background = loader.loadModel("phase_4/models/minigames/ice_game_2d") backgroundWide = loader.loadModel("phase_4/models/minigames/iceslide_ground") background.reparentTo(self.gameBoard) backgroundWide.reparentTo(self.gameBoard) backgroundWide.setPos(0, -0.3, -0.5) self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.setupSimulation() index = 0 for avId in self.avIdList: self.setupTire(avId, index) self.setupForceArrow(avId) index += 1 for index in xrange(len(self.avIdList), 4): self.setupTire(-index, index) self.setupForceArrow(-index) self.showForceArrows(realPlayersOnly=True) self.westWallModel = NodePath() if not self.westWallModel.isEmpty(): self.westWallModel.reparentTo(self.gameBoard) self.westWallModel.setPos(IceGameGlobals.MinWall[0], IceGameGlobals.MinWall[1], 0) self.westWallModel.setScale(4) self.eastWallModel = NodePath() if not self.eastWallModel.isEmpty(): self.eastWallModel.reparentTo(self.gameBoard) self.eastWallModel.setPos(IceGameGlobals.MaxWall[0], IceGameGlobals.MaxWall[1], 0) self.eastWallModel.setScale(4) self.eastWallModel.setH(180) self.arrowKeys = ArrowKeys.ArrowKeys() self.target = loader.loadModel("phase_3/models/misc/sphere") self.target.setScale(0.01) self.target.reparentTo(self.gameBoard) self.target.setPos(0, 0, 0) self.scoreCircle = loader.loadModel("phase_4/models/minigames/ice_game_score_circle") self.scoreCircle.setScale(0.01) self.scoreCircle.reparentTo(self.gameBoard) self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0) self.scoreCircle.setAlphaScale(0.5) self.scoreCircle.setTransparency(1) self.scoreCircle.hide() self.treasureModel = loader.loadModel("phase_4/models/minigames/ice_game_barrel") self.penaltyModel = loader.loadModel("phase_4/models/minigames/ice_game_tnt2") self.penaltyModel.setScale(0.75, 0.75, 0.7) szId = self.getSafezoneId() obstacles = IceGameGlobals.Obstacles[szId] index = 0 cubicObstacle = IceGameGlobals.ObstacleShapes[szId] for pos in obstacles: newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius) newObstacle = self.createObstacle(newPos, index, cubicObstacle) self.obstacles.append(newObstacle) index += 1 self.countSound = loader.loadSfx("phase_3.5/audio/sfx/tick_counter.ogg") self.treasureGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_vine_game_bananas.ogg") self.penaltyGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_cannon_fire_alt.ogg") self.tireSounds = [] for tireIndex in xrange(4): tireHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg") wallHit = loader.loadSfx("phase_4/audio/sfx/MG_maze_pickup.ogg") obstacleHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_2.ogg") self.tireSounds.append({"tireHit": tireHit, "wallHit": wallHit, "obstacleHit": obstacleHit}) self.arrowRotateSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_rotate.ogg") self.arrowUpSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.ogg") self.arrowDownSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.ogg") self.scoreCircleSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_scoring_1.ogg") def unload(self): self.notify.debug("unload") DistributedMinigame.DistributedMinigame.unload(self) del self.music self.gameBoard.removeNode() del self.gameBoard for forceArrow in self.forceArrowDict.values(): forceArrow.removeNode() del self.forceArrowDict self.scoreCircle.removeNode() del self.scoreCircle del self.countSound def onstage(self): self.notify.debug("onstage") DistributedMinigame.DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) self.__placeToon(self.localAvId) self.moveCameraToTop() self.scorePanels = [] base.playMusic(self.music, looping=1, volume=0.8) def offstage(self): self.notify.debug("offstage") self.music.stop() self.gameBoard.hide() self.infoLabel.hide() for avId in self.tireDict: self.tireDict[avId]["tireNodePath"].hide() for panel in self.scorePanels: panel.cleanup() del self.scorePanels for obstacle in self.obstacles: obstacle.hide() for treasure in self.treasures: treasure.nodePath.hide() for penalty in self.penalties: penalty.nodePath.hide() for avId in self.avIdList: av = self.getAvatar(avId) if av: av.dropShadow.show() av.resetLOD() taskMgr.remove(self.uniqueName("aimtask")) self.arrowKeys.destroy() del self.arrowKeys DistributedMinigame.DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug("handleDisabledAvatar") self.notify.debug("avatar " + str(avId) + " disabled") DistributedMinigame.DistributedMinigame.handleDisabledAvatar(self, avId) def setGameReady(self): if not self.hasLocalToon: return self.notify.debug("setGameReady") if DistributedMinigame.DistributedMinigame.setGameReady(self): return for index in xrange(self.numPlayers): avId = self.avIdList[index] toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self.__placeToon(avId) toon.forwardSpeed = 0 toon.rotateSpeed = False toon.dropShadow.hide() toon.setAnimState("Sit") if avId in self.tireDict: tireNp = self.tireDict[avId]["tireNodePath"] toon.reparentTo(tireNp) toon.setY(1.0) toon.setZ(-3) toon.startLookAround() def setGameStart(self, timestamp): if not self.hasLocalToon: return self.notify.debug("setGameStart") DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp) for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() self.scores = [0] * self.numPlayers spacing = 0.4 for i in xrange(self.numPlayers): avId = self.avIdList[i] avName = self.getAvatarName(avId) scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(avId, avName) scorePanel.setScale(0.9) scorePanel.setPos(-0.583 - spacing * (self.numPlayers - 1 - i), 0.0, -0.15) scorePanel.reparentTo(base.a2dTopRight) scorePanel.makeTransparent(0.75) self.scorePanels.append(scorePanel) self.arrowKeys.setPressHandlers( [ self.__upArrowPressed, self.__downArrowPressed, self.__leftArrowPressed, self.__rightArrowPressed, self.__controlPressed, ] ) def isInPlayState(self): if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == "play": return False return True def enterOff(self): self.notify.debug("enterOff") def exitOff(self): pass def enterInputChoice(self): self.notify.debug("enterInputChoice") self.forceLocalToonToTire() self.controlKeyPressed = False if self.curRound == 0: self.setupStartOfMatch() else: self.notify.debug("self.curRound = %s" % self.curRound) self.timer = ToontownTimer.ToontownTimer() self.timer.hide() if self.timerStartTime != None: self.startTimer() self.showForceArrows(realPlayersOnly=True) self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0) self.localForceArrow().reparentTo(self.localTireNp()) self.localForceArrow().setY(IceGameGlobals.TireRadius) self.localTireNp().headsUp(self.target) self.notify.debug("self.localForceArrow() heading = %s" % self.localForceArrow().getH()) self.curHeading = self.localTireNp().getH() self.curForce = 25 self.updateLocalForceArrow() for avId in self.forceArrowDict: forceArrow = self.forceArrowDict[avId] forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0) tireNp = self.tireDict[avId]["tireNodePath"] forceArrow.reparentTo(tireNp) forceArrow.setY(IceGameGlobals.TireRadius) tireNp.headsUp(self.target) self.updateForceArrow(avId, tireNp.getH(), 25) taskMgr.add(self.__aimTask, self.uniqueName("aimtask")) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() self.sendForceArrowUpdateAsap = False return def exitInputChoice(self): if not self.controlKeyPressed: if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningIval = Sequence( Func(self.controlKeyWarningLabel.show), self.controlKeyWarningLabel.colorScaleInterval( 10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1) ), Func(self.controlKeyWarningLabel.hide), ) self.controlKeyWarningIval.start() if self.timer != None: self.timer.destroy() self.timer = None self.timerStartTime = None self.hideForceArrows() self.arrowRotateSound.stop() self.arrowUpSound.stop() self.arrowDownSound.stop() taskMgr.remove(self.uniqueName("aimtask")) return def enterWaitServerChoices(self): self.waitingMoveLabel.show() self.showForceArrows(True) def exitWaitServerChoices(self): self.waitingMoveLabel.hide() self.hideForceArrows() def enterMoveTires(self): for key in self.tireDict: body = self.tireDict[key]["tireBody"] body.setAngularVel(0, 0, 0) body.setLinearVel(0, 0, 0) for index in xrange(len(self.allTireInputs)): input = self.allTireInputs[index] avId = self.avIdList[index] body = self.getTireBody(avId) degs = input[1] + 90 tireNp = self.getTireNp(avId) tireH = tireNp.getH() self.notify.debug("tireH = %s" % tireH) radAngle = deg2Rad(degs) foo = NodePath("foo") dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0) self.notify.debug("dirVector is now=%s" % dirVector) inputForce = input[0] inputForce /= self.MaxLocalForce inputForce *= self.MaxPhysicsForce force = dirVector * inputForce self.notify.debug("adding force %s to %d" % (force, avId)) body.addForce(force) self.enableAllTireBodies() self.totalPhysicsSteps = 0 self.startSim() taskMgr.add(self.__moveTiresTask, self.uniqueName("moveTiresTtask")) def exitMoveTires(self): self.forceLocalToonToTire() self.disableAllTireBodies() self.stopSim() self.notify.debug("total Physics steps = %d" % self.totalPhysicsSteps) taskMgr.remove(self.uniqueName("moveTiresTtask")) def enterSynch(self): self.waitingSyncLabel.show() def exitSynch(self): self.waitingSyncLabel.hide() def enterScoring(self): sortedByDistance = [] for avId in self.avIdList: np = self.getTireNp(avId) pos = np.getPos() pos.setZ(0) sortedByDistance.append((avId, pos.length())) def compareDistance(x, y): if x[1] - y[1] > 0: return 1 elif x[1] - y[1] < 0: return -1 else: return 0 sortedByDistance.sort(cmp=compareDistance) self.scoreMovie = Sequence() curScale = 0.01 curTime = 0 self.scoreCircle.setScale(0.01) self.scoreCircle.show() self.notify.debug("newScores = %s" % self.newScores) circleStartTime = 0 for index in xrange(len(sortedByDistance)): distance = sortedByDistance[index][1] avId = sortedByDistance[index][0] scorePanelIndex = self.avIdList.index(avId) time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec if time < 0: time = 0.01 scaleXY = distance + IceGameGlobals.TireRadius self.notify.debug("circleStartTime = %s" % circleStartTime) self.scoreMovie.append( Parallel( LerpScaleInterval(self.scoreCircle, time, Point3(scaleXY, scaleXY, 1.0)), SoundInterval(self.scoreCircleSound, duration=time, startTime=circleStartTime), ) ) circleStartTime += time startScore = self.scorePanels[scorePanelIndex].getScore() destScore = self.newScores[scorePanelIndex] self.notify.debug("for avId %d, startScore=%d, newScores=%d" % (avId, startScore, destScore)) def increaseScores(t, scorePanelIndex=scorePanelIndex, startScore=startScore, destScore=destScore): oldScore = self.scorePanels[scorePanelIndex].getScore() diff = destScore - startScore newScore = int(startScore + diff * t) if newScore > oldScore: base.playSfx(self.countSound) self.scorePanels[scorePanelIndex].setScore(newScore) self.scores[scorePanelIndex] = newScore duration = (destScore - startScore) * IceGameGlobals.ScoreCountUpRate tireNp = self.tireDict[avId]["tireNodePath"] self.scoreMovie.append( Parallel( LerpFunctionInterval(increaseScores, duration), Sequence( LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), ), ) ) curScale += distance self.scoreMovie.append(Func(self.sendUpdate, "reportScoringMovieDone", [])) self.scoreMovie.start() def exitScoring(self): self.scoreMovie.finish() self.scoreMovie = None self.scoreCircle.hide() return def enterFinalResults(self): lerpTrack = Parallel() lerpDur = 0.5 tY = 0.6 bY = -0.05 lX = -0.5 cX = 0 rX = 0.5 scorePanelLocs = ( ((cX, bY),), ((lX, bY), (rX, bY)), ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY), (lX, bY), (rX, bY)), ) scorePanelLocs = scorePanelLocs[self.numPlayers - 1] for i in xrange(self.numPlayers): panel = self.scorePanels[i] pos = scorePanelLocs[i] panel.wrtReparentTo(aspect2d) lerpTrack.append( Parallel( LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType="easeInOut"), LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType="easeInOut"), ) ) self.showScoreTrack = Parallel( lerpTrack, Sequence(Wait(IceGameGlobals.ShowScoresDuration), Func(self.gameOver)) ) self.showScoreTrack.start() def exitFinalResults(self): self.showScoreTrack.pause() del self.showScoreTrack def enterCleanup(self): self.notify.debug("enterCleanup") if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() def exitCleanup(self): pass def __placeToon(self, avId): toon = self.getAvatar(avId) if toon: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def setupTire(self, avId, index): tireNp, tireBody, tireOdeGeom = self.createTire(index) self.tireDict[avId] = {"tireNodePath": tireNp, "tireBody": tireBody, "tireOdeGeom": tireOdeGeom} if avId <= 0: tireBlocker = tireNp.find("**/tireblockermesh") if not tireBlocker.isEmpty(): tireBlocker.hide() if avId == self.localAvId: tireNp = self.tireDict[avId]["tireNodePath"] self.treasureSphereName = "treasureCollider" self.treasureCollSphere = CollisionSphere(0, 0, 0, IceGameGlobals.TireRadius) self.treasureCollSphere.setTangible(0) self.treasureCollNode = CollisionNode(self.treasureSphereName) self.treasureCollNode.setFromCollideMask(ToontownGlobals.PieBitmask) self.treasureCollNode.addSolid(self.treasureCollSphere) self.treasureCollNodePath = tireNp.attachNewNode(self.treasureCollNode) self.treasureHandler = CollisionHandlerEvent() self.treasureHandler.addInPattern("%fn-intoTreasure") base.cTrav.addCollider(self.treasureCollNodePath, self.treasureHandler) eventName = "%s-intoTreasure" % self.treasureCollNodePath.getName() self.notify.debug("eventName = %s" % eventName) self.accept(eventName, self.toonHitSomething) def setupForceArrow(self, avId): arrow = loader.loadModel("phase_4/models/minigames/ice_game_arrow") priority = 0 if avId < 0: priority = -avId else: priority = self.avIdList.index(avId) if avId == self.localAvId: priority = 10 self.forceArrowDict[avId] = arrow def hideForceArrows(self): for forceArrow in self.forceArrowDict.values(): forceArrow.hide() def showForceArrows(self, realPlayersOnly=True): for avId in self.forceArrowDict: if realPlayersOnly: if avId > 0: self.forceArrowDict[avId].show() else: self.forceArrowDict[avId].hide() else: self.forceArrowDict[avId].show() def localForceArrow(self): if self.localAvId in self.forceArrowDict: return self.forceArrowDict[self.localAvId] else: return None return None def setChoices(self, input0, input1, input2, input3): pass def startDebugTask(self): taskMgr.add(self.debugTask, self.debugTaskName) def stopDebugTask(self): taskMgr.remove(self.debugTaskName) def debugTask(self, task): if self.canDrive and self.tireDict.has_key(localAvatar.doId): dt = globalClock.getDt() forceMove = 25000 forceMoveDt = forceMove tireBody = self.tireDict[localAvatar.doId]["tireBody"] if self.arrowKeys.upPressed() and not tireBody.isEnabled(): x = 0 y = 1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.downPressed() and not tireBody.isEnabled(): x = 0 y = -1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.leftPressed() and not tireBody.isEnabled(): x = -1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.rightPressed() and not tireBody.isEnabled(): x = 1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) return task.cont def __upArrowPressed(self): pass def __downArrowPressed(self): pass def __leftArrowPressed(self): pass def __rightArrowPressed(self): pass def __controlPressed(self): if self.gameFSM.getCurrentState().getName() == "inputChoice": self.sendForceArrowUpdateAsap = True self.updateLocalForceArrow() self.controlKeyPressed = True self.sendUpdate("setAvatarChoice", [self.curForce, self.curHeading]) self.gameFSM.request("waitServerChoices") def startTimer(self): now = globalClock.getFrameTime() elapsed = now - self.timerStartTime self.timer.posInTopRightCorner() self.timer.setTime(IceGameGlobals.InputTimeout) self.timer.countdown(IceGameGlobals.InputTimeout - elapsed, self.handleChoiceTimeout) self.timer.show() def setTimerStartTime(self, timestamp): if not self.hasLocalToon: return self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp) if self.timer != None: self.startTimer() return def handleChoiceTimeout(self): self.sendUpdate("setAvatarChoice", [0, 0]) self.gameFSM.request("waitServerChoices") def localTireNp(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]["tireNodePath"] return ret def localTireBody(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]["tireBody"] return ret def getTireBody(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]["tireBody"] return ret def getTireNp(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]["tireNodePath"] return ret def updateForceArrow(self, avId, curHeading, curForce): forceArrow = self.forceArrowDict[avId] tireNp = self.tireDict[avId]["tireNodePath"] tireNp.setH(curHeading) tireBody = self.tireDict[avId]["tireBody"] tireBody.setQuaternion(tireNp.getQuat()) self.notify.debug("curHeading = %s" % curHeading) yScale = curForce / 100.0 yScale *= 1 headY = yScale * 15 xScale = (yScale - 1) / 2.0 + 1.0 shaft = forceArrow.find("**/arrow_shaft") head = forceArrow.find("**/arrow_head") shaft.setScale(xScale, yScale, 1) head.setPos(0, headY, 0) head.setScale(xScale, xScale, 1) def updateLocalForceArrow(self): avId = self.localAvId self.b_setForceArrowInfo(avId, self.curHeading, self.curForce) def __aimTask(self, task): if not hasattr(self, "arrowKeys"): return task.done dt = globalClock.getDt() headingMomentumChange = dt * 60.0 forceMomentumChange = dt * 160.0 arrowUpdate = False arrowRotating = False arrowUp = False arrowDown = False if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce += self.forceMomentum * dt arrowUpdate = True if oldForce < self.MaxLocalForce: arrowUp = True elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce -= self.forceMomentum * dt arrowUpdate = True if oldForce > 0.01: arrowDown = True else: self.forceMomentum = 0 if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading += self.headingMomentum * dt arrowUpdate = True arrowRotating = True elif self.arrowKeys.rightPressed() and not self.arrowKeys.leftPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading -= self.headingMomentum * dt arrowUpdate = True arrowRotating = True else: self.headingMomentum = 0 if arrowUpdate: self.normalizeHeadingAndForce() self.updateLocalForceArrow() if arrowRotating: if not self.arrowRotateSound.status() == self.arrowRotateSound.PLAYING: base.playSfx(self.arrowRotateSound, looping=True) else: self.arrowRotateSound.stop() if arrowUp: if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING: base.playSfx(self.arrowUpSound, looping=False) else: self.arrowUpSound.stop() if arrowDown: if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING: base.playSfx(self.arrowDownSound, looping=False) else: self.arrowDownSound.stop() return task.cont def normalizeHeadingAndForce(self): if self.curForce > self.MaxLocalForce: self.curForce = self.MaxLocalForce if self.curForce < 0.01: self.curForce = 0.01 def setTireInputs(self, tireInputs): if not self.hasLocalToon: return self.allTireInputs = tireInputs self.gameFSM.request("moveTires") def enableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]["tireBody"].enable() def disableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]["tireBody"].disable() def areAllTiresDisabled(self): for avId in self.tireDict.keys(): if self.tireDict[avId]["tireBody"].isEnabled(): return False return True def __moveTiresTask(self, task): if self.areAllTiresDisabled(): self.sendTirePositions() self.gameFSM.request("synch") return task.done return task.cont def sendTirePositions(self): tirePositions = [] for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) self.sendUpdate("endingPositions", [tirePositions]) def setFinalPositions(self, finalPos): if not self.hasLocalToon: return for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) def updateInfoLabel(self): self.infoLabel["text"] = TTLocalizer.IceGameInfo % { "curMatch": self.curMatch + 1, "numMatch": IceGameGlobals.NumMatches, "curRound": self.curRound + 1, "numRound": IceGameGlobals.NumRounds, } def setMatchAndRound(self, match, round): if not self.hasLocalToon: return self.curMatch = match self.curRound = round self.updateInfoLabel() def setScores(self, match, round, scores): if not self.hasLocalToon: return self.newMatch = match self.newRound = round self.newScores = scores def setNewState(self, state): if not self.hasLocalToon: return self.notify.debug("setNewState gameFSM=%s newState=%s" % (self.gameFSM, state)) self.gameFSM.request(state) def putAllTiresInStartingPositions(self): for index in xrange(len(self.avIdList)): avId = self.avIdList[index] np = self.tireDict[avId]["tireNodePath"] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]["tireBody"] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) for index in xrange(len(self.avIdList), 4): avId = -index np = self.tireDict[avId]["tireNodePath"] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]["tireBody"] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) def b_setForceArrowInfo(self, avId, force, heading): self.setForceArrowInfo(avId, force, heading) self.d_setForceArrowInfo(avId, force, heading) def d_setForceArrowInfo(self, avId, force, heading): sendIt = False curTime = self.getCurrentGameTime() if self.sendForceArrowUpdateAsap: sendIt = True elif curTime - self.lastForceArrowUpdateTime > 0.2: sendIt = True if sendIt: self.sendUpdate("setForceArrowInfo", [avId, force, heading]) self.sendForceArrowUpdateAsap = False self.lastForceArrowUpdateTime = self.getCurrentGameTime() def setForceArrowInfo(self, avId, force, heading): if not self.hasLocalToon: return self.updateForceArrow(avId, force, heading) def setupStartOfMatch(self): self.putAllTiresInStartingPositions() szId = self.getSafezoneId() self.numTreasures = IceGameGlobals.NumTreasures[szId] if self.treasures: for treasure in self.treasures: treasure.destroy() self.treasures = [] index = 0 treasureMargin = IceGameGlobals.TireRadius + 1.0 while len(self.treasures) < self.numTreasures: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug("yPos=%s" % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newTreasure = IceTreasure.IceTreasure(self.treasureModel, pos, index, self.doId, penalty=False) goodSpot = True for obstacle in self.obstacles: if newTreasure.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break if goodSpot: for treasure in self.treasures: if newTreasure.nodePath.getDistance(treasure.nodePath) < treasureMargin: goodSpot = False break if goodSpot: self.treasures.append(newTreasure) index += 1 else: newTreasure.destroy() self.numPenalties = IceGameGlobals.NumPenalties[szId] if self.penalties: for penalty in self.penalties: penalty.destroy() self.penalties = [] index = 0 while len(self.penalties) < self.numPenalties: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug("yPos=%s" % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newPenalty = IceTreasure.IceTreasure(self.penaltyModel, pos, index, self.doId, penalty=True) goodSpot = True for obstacle in self.obstacles: if newPenalty.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break if goodSpot: for treasure in self.treasures: if newPenalty.nodePath.getDistance(treasure.nodePath) < treasureMargin: goodSpot = False break if goodSpot: for penalty in self.penalties: if newPenalty.nodePath.getDistance(penalty.nodePath) < treasureMargin: goodSpot = False break if goodSpot: self.penalties.append(newPenalty) index += 1 else: newPenalty.destroy() def toonHitSomething(self, entry): self.notify.debug("---- treasure Enter ---- ") self.notify.debug("%s" % entry) name = entry.getIntoNodePath().getName() parts = name.split("-") if len(parts) < 3: self.notify.debug("collided with %s, but returning" % name) return if not int(parts[1]) == self.doId: self.notify.debug("collided with %s, but doId doesn't match" % name) return treasureNum = int(parts[2]) if "penalty" in parts[0]: self.__penaltyGrabbed(treasureNum) else: self.__treasureGrabbed(treasureNum) def __treasureGrabbed(self, treasureNum): self.treasures[treasureNum].showGrab() self.treasureGrabSound.play() self.sendUpdate("claimTreasure", [treasureNum]) def setTreasureGrabbed(self, avId, treasureNum): if not self.hasLocalToon: return self.notify.debug("treasure %s grabbed by %s" % (treasureNum, avId)) if avId != self.localAvId: self.treasures[treasureNum].showGrab() i = self.avIdList.index(avId) self.scores[i] += 1 self.scorePanels[i].setScore(self.scores[i]) def __penaltyGrabbed(self, penaltyNum): self.penalties[penaltyNum].showGrab() self.sendUpdate("claimPenalty", [penaltyNum]) def setPenaltyGrabbed(self, avId, penaltyNum): if not self.hasLocalToon: return self.notify.debug("penalty %s grabbed by %s" % (penaltyNum, avId)) if avId != self.localAvId: self.penalties[penaltyNum].showGrab() i = self.avIdList.index(avId) self.scores[i] -= 1 self.scorePanels[i].setScore(self.scores[i]) def postStep(self): DistributedIceWorld.DistributedIceWorld.postStep(self) if not self.colCount: return for count in xrange(self.colCount): c0, c1 = self.getOrderedContacts(count) if c1 in self.tireCollideIds: tireIndex = self.tireCollideIds.index(c1) if c0 in self.tireCollideIds: self.tireSounds[tireIndex]["tireHit"].play() elif c0 == self.wallCollideId: self.tireSounds[tireIndex]["wallHit"].play() elif c0 == self.obstacleCollideId: self.tireSounds[tireIndex]["obstacleHit"].play() def forceLocalToonToTire(self): toon = localAvatar if toon and self.localAvId in self.tireDict: tireNp = self.tireDict[self.localAvId]["tireNodePath"] toon.reparentTo(tireNp) toon.setPosHpr(0, 0, 0, 0, 0, 0) toon.setY(1.0) toon.setZ(-3)
class SquirtGag(Gag): def __init__(self, name, model, damage, hitSfx, spraySfx, missSfx, toonAnim, enableReleaseFrame, completeSquirtFrame, startAnimFrame=0, scale=1, playRate=1): Gag.__init__(self, name, model, damage, GagType.SQUIRT, hitSfx, scale=scale, autoRelease=True, playRate=playRate) self.sprayScale = GagGlobals.splatSizes.get(self.name) self.spraySfx = None self.missSfx = None self.origin = None self.sprayRange = None self.spray = None self.sprayJoint = None self.canSquirt = False self.hitSomething = False self.toonAnim = toonAnim self.startAnimFrame = 0 self.enableReleaseFrame = enableReleaseFrame self.completeSquirtFrame = completeSquirtFrame self.lastFrame = 0 self.tracks = None self.sprayTrack = None self.sprayAttempt = None self.sprayRotation = Vec3(0, 0, 0) if game.process == 'client': if spraySfx: self.spraySfx = base.audio3d.loadSfx(spraySfx) if missSfx: self.missSfx = base.audio3d.loadSfx(missSfx) def start(self): Gag.start(self) if self.sprayTrack: self.sprayTrack.pause() self.sprayTrack = None if self.tracks: self.tracks.pause() self.tracks = None if self.anim: self.build() self.equip() duration = base.localAvatar.getDuration( self.toonAnim, toFrame=self.enableReleaseFrame) self.sprayAttempt = Parallel( ActorInterval(self.avatar, self.toonAnim, startFrame=self.startAnimFrame, endFrame=self.enableReleaseFrame, playRate=self.playRate), Wait(duration - 0.15), Func(self.setSquirtEnabled, True)).start() def startSquirt(self, sprayScale, containerHold): def startSpray(): self.doSpray(sprayScale, containerHold, sprayScale) Sequence( ActorInterval(self.avatar, self.toonAnim, startFrame=self.enableReleaseFrame, endFrame=self.completeSquirtFrame), Func(startSpray)).start() def setSquirtEnabled(self, flag): self.canSquirt = flag self.sprayAttempt = None def doSpray(self, scaleUp, scaleDown, hold, horizScale=1.0, vertScale=1.0): base.audio3d.attachSoundToObject(self.spraySfx, self.gag) base.playSfx(self.spraySfx, node=self.gag) spraySequence = self.getSprayTrack(self.origin, self.sprayRange, scaleUp, hold, scaleDown, horizScale, vertScale) self.sprayTrack = spraySequence self.sprayTrack.start() def completeSquirt(self): numFrames = base.localAvatar.getNumFrames(self.toonAnim) finishSeq = Sequence() finishSeq.append(Wait(0.5)) finishSeq.append( Func(self.avatar.play, self.toonAnim, fromFrame=self.completeSquirtFrame, toFrame=numFrames)) finishSeq.append(Func(self.reset)) finishSeq.append(Func(self.avatar.play, 'neutral')) finishSeq.append(Func(self.cleanupSpray)) finishSeq.start() if self.avatar == base.localAvatar: if base.localAvatar.getBackpack().getSupply() == 0: self.cleanupGag() def onCollision(self, entry): self.hitSomething = True base.audio3d.attachSoundToObject(self.hitSfx, self.sprayNP) base.playSfx(self.hitSfx, node=self.sprayNP) intoNP = entry.getIntoNodePath() avNP = intoNP.getParent() if self.avatar.doId == base.localAvatar.doId: for key in base.cr.doId2do.keys(): obj = base.cr.doId2do[key] if obj.__class__.__name__ in CIGlobals.SuitClasses: if obj.getKey() == avNP.getKey(): obj.sendUpdate('hitByGag', [self.getID()]) elif obj.__class__.__name__ == "DistributedToon": if obj.getKey() == avNP.getKey(): if obj.getHealth() < obj.getMaxHealth(): self.avatar.sendUpdate( 'toonHitByPie', [obj.doId, self.getID()]) if base.localAvatar == self.avatar: self.splatPos = self.sprayNP.getPos(render) gagPos = self.sprayNP.getPos(render) self.handleSplat() self.avatar.sendUpdate( 'setSplatPos', [self.getID(), gagPos.getX(), gagPos.getY(), gagPos.getZ()]) def handleMiss(self): if self.spray and self.hitSomething == False: base.audio3d.attachSoundToObject(self.missSfx, self.spray) base.playSfx(self.missSfx, node=self.spray) self.cleanupSpray() def handleSplat(self): self.cleanupSplat() self.buildSplat(GagGlobals.splatSizes.get(self.getName()), GagGlobals.WATER_SPRAY_COLOR) self.splat.setPos(self.splatPos) self.splat.reparentTo(render) self.splatPos = None taskMgr.doMethodLater(0.5, self.delSplat, 'Delete Splat') def getSprayTrack(self, origin, target, scaleUp, hold, scaleDown, horizScale=1.0, vertScale=1.0): if self.sprayJoint.isEmpty(): self.build() self.origin = self.getSprayStartPos() base.localAvatar.stop(self.toonAnim) self.lastFrame = self.avatar.getCurrentFrame(self.toonAnim) track = Sequence() sprayProp = loader.loadModel(GagGlobals.SPRAY_MDL) sprayProp.setTwoSided(1) sprayScale = hidden.attachNewNode('spray-parent') sprayRot = hidden.attachNewNode('spray-rotate') sprayRot.setColor(GagGlobals.WATER_SPRAY_COLOR) sprayRot.setTransparency(1) collNode = CollisionNode('Collision') spraySphere = CollisionSphere(0, 0, 0, 1) spraySphere.setTangible(0) collNode.addSolid(spraySphere) collNode.setCollideMask(CIGlobals.WallBitmask) sprayNP = sprayRot.attachNewNode(collNode) sprayNP.setY(1) self.sprayNP = sprayNP event = CollisionHandlerEvent() event.set_in_pattern("%fn-into") event.set_out_pattern("%fn-out") base.cTrav.add_collider(sprayNP, event) self.avatar.acceptOnce(sprayNP.node().getName() + '-into', self.onCollision) def showSpray(sprayScale, sprayProp, origin, target): objects = [sprayRot, sprayScale, sprayProp] for item in objects: index = objects.index(item) if index == 0: item.reparentTo(self.sprayJoint) item.setPos(0, 0, 0) item.setHpr(self.sprayRotation) item.wrtReparentTo(render) else: item.reparentTo(objects[index - 1]) track.append(Func(showSpray, sprayScale, sprayProp, origin, target)) self.spray = sprayRot def calcTargetScale(): distance = Vec3(target - origin).length() yScale = distance / GagGlobals.SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append( Parallel( LerpScaleInterval(sprayScale, scaleUp, calcTargetScale, startScale=GagGlobals.PNT3NEAR0), sprayNP.posInterval( 0.25, self.spray.getPos(render) + Point3(0, 50, 0), startPos=self.spray.getPos(render) + Point3(0, 5, 0)))) track.append(Wait(hold)) track.append(Func(self.handleMiss)) track.append(LerpScaleInterval(sprayScale, 0.75, GagGlobals.PNT3NEAR0)) def hideSpray(): lambda prop: prop.removeNode(), [sprayProp, sprayRot, sprayScale] track.append(Func(hideSpray)) track.append(Func(self.completeSquirt)) return track def getSprayRange(self): sprayRange = NodePath('Squirt Range') sprayRange.reparentTo(self.avatar) sprayRange.setScale(render, 1) sprayRange.setPos(0, 160, -90) sprayRange.setHpr(90, -90, 90) return sprayRange @abc.abstractmethod def getSprayStartPos(self): return Point3(0, 0, 0) def cleanupSpray(self): if self.spray: self.spray.removeNode() self.spray = None if self.sprayAttempt: self.sprayAttempt.pause() self.sprayAttempt = None self.hitSomething = False self.canSquirt = False
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode): notify = directNotify.newCategory('DistributedPieTurret') def __init__(self, cr): DistributedAvatar.__init__(self, cr) DistributedSmoothNode.__init__(self, cr) self.fsm = ClassicFSM( 'DistributedPieTurret', [ State('off', self.enterOff, self.exitOff), State('scan', self.enterScan, self.exitScan), State('shoot', self.enterShoot, self.exitShoot) ], 'off', 'off' ) self.fsm.enterInitialState() self.reloadTime = 0.25 self.cannon = None self.track = None self.owner = None self.gag = None self.readyGag = None self.hitGag = None self.explosion = None self.wallCollNode = None self.eventCollNode = None self.event = None self.suit = None self.eventId = None self.entities = [] self.upgradeID = None self.deathEvent = None def setOwner(self, avatar): self.owner = avatar def getOwner(self): return self.owner def setGag(self, upgradeId): gags = {0 : CIGlobals.WholeCreamPie, 1 : CIGlobals.WholeFruitPie, 2 : CIGlobals.BirthdayCake, 3 : CIGlobals.WeddingCake} self.gag = gags.get(upgradeId) if not self.readyGag: self.loadGagInTurret() def b_setGag(self, upgradeId): self.sendUpdate('setGag', [upgradeId]) self.setGag(upgradeId) self.upgradeID = upgradeId def getGag(self): return self.gag def getGagID(self): return self.upgradeID def generate(self): DistributedAvatar.generate(self) DistributedSmoothNode.generate(self) def announceGenerate(self): DistributedAvatar.announceGenerate(self) DistributedSmoothNode.announceGenerate(self) self.healthLabel.setScale(1.1) self.deathEvent = self.uniqueName('DistributedPieTurret-death') self.makeTurret() def disable(self): self.fsm.requestFinalState() del self.fsm # This should fix crashes related to Sequences. if self.track: self.track.pause() self.track = None # Cleanup entities. for ent in self.entities: ent.cleanup() self.entities = None # Get rid of explosions. if self.explosion: self.explosion.removeNode() self.explosion = None self.removeTurret() DistributedSmoothNode.disable(self) DistributedAvatar.disable(self) def showAndMoveHealthLabel(self): self.unstashHpLabel() self.stopMovingHealthLabel() moveTrack = LerpPosInterval(self.healthLabel, duration = 0.5, pos = Point3(0, 0, 5), startPos = Point3(0, 0, 0), blendType = 'easeOut') self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel)) self.healthLabelTrack.start() # BEGIN STATES def enterShoot(self, suitId): if self.cannon: smoke = loader.loadModel("phase_4/models/props/test_clouds.bam") smoke.setBillboardPointEye() smoke.reparentTo(self.cannon.find('**/cannon')) smoke.setPos(0, 6, -3) smoke.setScale(0.5) smoke.wrtReparentTo(render) self.suit = self.cr.doId2do.get(suitId) self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head')) self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head')) self.track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode)) self.track.start() self.createAndShootGag() def exitShoot(self): if hasattr(self, 'suit'): del self.suit def shoot(self, suitId): self.fsm.request('shoot', [suitId]) def scan(self, timestamp = None, afterShooting = 0): if timestamp == None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) self.fsm.request('scan', [ts, afterShooting]) def buildScanTrack(self, ts = None): if self.track: self.track.pause() self.track = None self.track = Parallel( Sequence( LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0), startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0), startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'), ), Sequence( LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0), startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0), startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'), ) ) if ts: self.track.loop(ts) else: self.track.loop() def enterScan(self, ts = 0, afterShooting = 0): if afterShooting: self.track = Parallel( LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0), startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0), startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'), name = "afterShootTrack" + str(id(self)) ) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone) self.track.start(ts) else: self.buildScanTrack(ts) def exitScan(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None def enterOff(self): pass def exitOff(self): pass # END STATES def _afterShootTrackDone(self): self.buildScanTrack() def makeTurret(self): self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon.bam') self.cannon.reparentTo(self) self.loadGagInTurret() self.setupWallSphere() if self.isLocal(): self.setupEventSphere() def removeTurret(self): self.removeWallSphere() self.removeGagInTurret() if self.cannon: self.cannon.removeNode() self.cannon = None def getCannon(self): return self.cannon.find('**/cannon') def setupWallSphere(self): sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0) node = CollisionNode('DistributedPieTurret.WallSphere') node.addSolid(sphere) node.setCollideMask(CIGlobals.WallBitmask) self.wallCollNode = self.cannon.attachNewNode(node) self.wallCollNode.setZ(2) self.wallCollNode.setY(1.0) def removeWallSphere(self): if self.wallCollNode: self.wallCollNode.removeNode() self.wallCollNode = None def createAndShootGag(self): if not self.readyGag: self.loadGagInTurret() if self.readyGag: self.readyGag.shoot(Point3(0, 200, -90)) self.entities.append(self.readyGag) collideEventName = self.readyGag.getCollideEventName() self.readyGag = None if self.isLocal(): self.acceptOnce(collideEventName, self.handleGagCollision) Sequence(Wait(self.reloadTime), Func(self.loadGagInTurret)).start() def loadGagInTurret(self): if self.cannon and self.gag: self.removeGagInTurret() self.eventId = random.uniform(0, 100000000) self.readyGag = TurretGag(self, self.uniqueName('pieTurretCollision') + str(self.eventId), self.gag) self.readyGag.build() def removeGagInTurret(self): if self.readyGag: self.readyGag.cleanup() self.readyGag = None def makeSplat(self, index, pos): if index >= len(self.entities): return ent = self.entities[index] gagClass = ent.gagClass splat = gagClass.buildSplat(gagClass.splatScale, gagClass.splatColor) base.audio3d.attachSoundToObject(gagClass.hitSfx, splat) splat.reparentTo(render) splat.setPos(pos[0], pos[1], pos[2]) gagClass.hitSfx.play() Sequence(Wait(0.5), Func(splat.cleanup)).start() self.hitGag = None def d_makeSplat(self, index, pos): self.sendUpdate('makeSplat', [index, pos]) def b_makeSplat(self, index, pos): self.d_makeSplat(index, pos) self.makeSplat(index, pos) def handleGagCollision(self, entry, ent): x, y, z = ent.getGag().getPos(render) self.b_makeSplat(self.entities.index(ent), [x, y, z]) if self.isLocal(): intoNP = entry.getIntoNodePath() avNP = intoNP.getParent() for key in self.cr.doId2do.keys(): obj = self.cr.doId2do[key] if obj.__class__.__name__ == 'DistributedSuit': if obj.getKey() == avNP.getKey(): if obj.getHealth() > 0: obj.sendUpdate('hitByGag', [ent.getID()]) ent.cleanup() def setHealth(self, hp): DistributedAvatar.setHealth(self, hp) if self.isLocal(): base.localAvatar.getMyBattle().getTurretManager().updateTurretGui() def die(self): self.fsm.requestFinalState() turretPos = self.cannon.getPos(render) self.removeTurret() self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam") self.explosion.setScale(0.5) self.explosion.reparentTo(render) self.explosion.setBillboardPointEye() self.explosion.setPos(turretPos + (0, 0, 5)) sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg") base.audio3d.attachSoundToObject(sfx, self) base.playSfx(sfx) messenger.send(self.deathEvent) def isLocal(self): return self.getOwner() == base.localAvatar.doId def getDeathEvent(self): return self.deathEvent
class DodgeballFirstPerson(FirstPerson): """The first person controls for the local player in Winter Dodgeball""" notify = directNotify.newCategory("DodgeballFirstPerson") MaxPickupDistance = 5.0 def __init__(self, mg): self.mg = mg self.crosshair = None self.soundCatch = None self.vModelRoot = None self.vModel = None self.ival = None self.soundPickup = base.loadSfx( 'phase_4/audio/sfx/MG_snowball_pickup.ogg') self.fakeSnowball = loader.loadModel( "phase_5/models/props/snowball.bam") self.hasSnowball = False self.mySnowball = None self.waitingOnPickupResp = False self.camPivotNode = base.localAvatar.attachNewNode('cameraPivotNode') self.camFSM = ClassicFSM.ClassicFSM("DFPCamera", [ State.State('off', self.enterCamOff, self.exitCamOff), State.State('frozen', self.enterFrozen, self.exitFrozen), State.State('unfrozen', self.enterUnFrozen, self.exitUnFrozen) ], 'off', 'off') self.camFSM.enterInitialState() self.fsm = ClassicFSM.ClassicFSM("DodgeballFirstPerson", [ State.State("off", self.enterOff, self.exitOff), State.State("hold", self.enterHold, self.exitHold), State.State("catch", self.enterCatch, self.exitCatch), State.State("throw", self.enterThrow, self.exitThrow) ], "off", "off") self.fsm.enterInitialState() FirstPerson.__init__(self) def enterCamOff(self): self.releaseSnowball() def exitCamOff(self): pass def releaseSnowball(self): if self.hasSnowball: if self.mySnowball and not self.mySnowball.isAirborne: self.hasSnowball = False self.mySnowball.resetSnowball() self.mySnowball = None self.fsm.request('off') def enterFrozen(self): self.releaseSnowball() self.vModel.hide() base.localAvatar.getGeomNode().show() camera.wrtReparentTo(self.camPivotNode) camHeight = max(base.localAvatar.getHeight(), 3.0) nrCamHeight = base.localAvatar.getHeight() heightScaleFactor = camHeight * 0.3333333333 defLookAt = Point3(0.0, 1.5, camHeight) idealData = (Point3(0.0, -12.0 * heightScaleFactor, camHeight), defLookAt) self.camTrack = Parallel( LerpPosInterval(camera, duration=1.0, pos=idealData[0], startPos=camera.getPos(), blendType='easeOut'), LerpQuatInterval(camera, duration=1.0, hpr=idealData[1], startHpr=camera.getHpr(), blendType='easeOut')) self.camTrack.start() self.max_camerap = 0.0 self.disableMouse() def cameraMovement(self, task): if not self.camFSM: return task.done if self.camFSM.getCurrentState().getName() == 'frozen': if hasattr(self, 'min_camerap') and hasattr(self, 'max_camerap'): md = base.win.getPointer(0) x = md.getX() y = md.getY() if base.win.movePointer(0, base.win.getXSize() / 2, base.win.getYSize() / 2): self.camPivotNode.setP(self.camPivotNode.getP() - (y - base.win.getYSize() / 2) * 0.1) self.camPivotNode.setH(self.camPivotNode.getH() - (x - base.win.getXSize() / 2) * 0.1) if self.camPivotNode.getP() < self.min_camerap: self.camPivotNode.setP(self.min_camerap) elif self.camPivotNode.getP() > self.max_camerap: self.camPivotNode.setP(self.max_camerap) return task.cont else: return task.done return FirstPerson.cameraMovement(self, task) def exitFrozen(self): self.camTrack.finish() del self.camTrack self.max_camerap = 90.0 self.vModel.show() self.enableMouse() base.localAvatar.stopSmartCamera() def enterUnFrozen(self): base.localAvatar.getGeomNode().hide() self.reallyStart() camera.setPosHpr(0, 0, 0, 0, 0, 0) camera.reparentTo(self.player_node) camera.setZ(base.localAvatar.getHeight()) def exitUnFrozen(self): self.end() self.enableMouse() def enterOff(self): if self.vModel: self.vModel.hide() if self.waitingOnPickupResp: taskMgr.add(self.__waitForPickupRespTask, "waitForPickupRespTask") def __waitForPickupRespTask(self, task): if not self.waitingOnPickupResp: if self.hasSnowball: self.fsm.request('hold') return task.done return task.cont def exitOff(self): if self.vModel: self.vModel.show() taskMgr.remove("waitForPickupRespTask") def enterHold(self): self.ival = Sequence(ActorInterval(self.vModel, "hold-start"), Func(self.vModel.loop, "hold")) self.ival.start() def exitHold(self): if self.ival: self.ival.finish() self.ival = None self.vModel.stop() def enterThrow(self): self.ival = Parallel( Sequence(Wait(0.4), Func(self.mySnowball.b_throw)), Sequence(ActorInterval(self.vModel, "throw"), Func(self.fsm.request, 'off'))) self.ival.start() def exitThrow(self): if self.ival: self.ival.pause() self.ival = None self.vModel.stop() def enterCatch(self): self.ival = Parallel( Sequence(Wait(0.2), Func(self.__tryToCatchOrGrab)), Sequence(ActorInterval(self.vModel, "catch"), Func(self.__maybeHold))) self.ival.start() def __maybeHold(self): if self.hasSnowball: self.fsm.request('hold') else: self.fsm.request('off') def __tryToCatchOrGrab(self): snowballs = list(self.mg.snowballs) snowballs.sort( key=lambda snowball: snowball.getDistance(base.localAvatar)) for i in xrange(len(snowballs)): snowball = snowballs[i] if (not snowball.hasOwner() and not snowball.isAirborne and snowball.getDistance(base.localAvatar) <= DodgeballFirstPerson.MaxPickupDistance): self.waitingOnPickupResp = True self.mg.sendUpdate('reqPickupSnowball', [snowball.index]) break def snowballPickupResp(self, flag, idx): if flag: snowball = self.mg.snowballs[idx] snowball.b_pickup() self.mySnowball = snowball self.fakeSnowball.setPosHpr(0, 0.73, 0, 0, 0, 0) self.fakeSnowball.reparentTo( self.vModel.exposeJoint(None, "modelRoot", "Bone.011")) base.playSfx(self.soundPickup) self.hasSnowball = True self.waitingOnPickupResp = False def exitCatch(self): self.vModel.stop() if self.ival: self.ival.pause() self.ival = None def start(self): # Black crosshair because basically the entire arena is white. self.crosshair = getCrosshair(color=(0, 0, 0, 1), hidden=False) self.soundCatch = base.loadSfx( "phase_4/audio/sfx/MG_sfx_vine_game_catch.ogg") self.vModelRoot = camera.attachNewNode('vModelRoot') self.vModelRoot.setPos(-0.09, 1.38, -2.48) self.vModel = Actor( "phase_4/models/minigames/v_dgm.egg", { "hold": "phase_4/models/minigames/v_dgm-ball-hold.egg", "hold-start": "phase_4/models/minigames/v_dgm-ball-hold-start.egg", "throw": "phase_4/models/minigames/v_dgm-ball-throw.egg", "catch": "phase_4/models/minigames/v_dgm-ball-catch.egg" }) self.vModel.setBlend(frameBlend=True) self.vModel.reparentTo(self.vModelRoot) self.vModel.setBin("fixed", 40) self.vModel.setDepthTest(False) self.vModel.setDepthWrite(False) self.vModel.hide() base.localAvatar.walkControls.setWalkSpeed(ToonForwardSpeed, ToonJumpForce, ToonReverseSpeed, ToonRotateSpeed) FirstPerson.start(self) def reallyStart(self): FirstPerson.reallyStart(self) base.localAvatar.startTrackAnimToSpeed() self.accept('mouse3', self.__handleCatchOrGrabButton) self.accept('mouse1', self.__handleThrowButton) def end(self): base.localAvatar.stopTrackAnimToSpeed() self.ignore('mouse3') self.ignore('mouse1') FirstPerson.end(self) def __handleThrowButton(self): if self.hasSnowball and self.mySnowball and self.fsm.getCurrentState( ).getName() == 'hold': self.fakeSnowball.reparentTo(hidden) self.fsm.request('throw') def __handleCatchOrGrabButton(self): if not self.hasSnowball and not self.mySnowball and self.fsm.getCurrentState( ).getName() == 'off': self.fsm.request('catch') def reallyEnd(self): base.localAvatar.setWalkSpeedNormal() if self.camFSM: self.camFSM.requestFinalState() self.camFSM = None if self.fsm: self.fsm.requestFinalState() self.fsm = None if self.crosshair: self.crosshair.destroy() self.crosshair = None if self.vModel: self.vModel.removeNode() self.vModel = None if self.vModelRoot: self.vModelRoot.removeNode() self.vModelRoot = None self.soundCatch = None FirstPerson.reallyEnd(self)
class DistributedTakeOverSuit(DistributedSuit): notify = directNotify.newCategory("DistributedTakeOverSuit") StartPosFromDoor = Point3(1.6, -10, -0.5) AtDoorPos = Point3(1.6, -1, 0) def __init__(self, cr): DistributedSuit.__init__(self, cr) self.showNametagInMargins = True self.doorDoId = None self.door = None self.takeOverTrack = None self.fsm = ClassicFSM('DTOS-fsm', [ State('off', self.enterOff, self.exitOff), State('takeOver', self.enterTakeOver, self.exitTakeOver) ], 'off', 'off') self.fsm.enterInitialState() def interruptTakeOver(self): if self.takeOverTrack: self.takeOverTrack.pause() self.takeOverTrack = None def setState(self, state, timestamp): ts = globalClockDelta.localElapsedTime(timestamp) self.fsm.request(state, [ts]) def disable(self): taskMgr.remove('posTask') self.fsm.requestFinalState() self.fsm = None self.doorDoId = None self.door = None if self.takeOverTrack: self.takeOverTrack.finish() self.takeOverTrack = None DistributedSuit.disable(self) def setDoorDoId(self, doId): self.doorDoId = doId self.door = self.cr.doId2do.get(doId) if self.door is None: taskMgr.add(self.__pollDoor, self.uniqueName('pollDoor')) def stateAndTimestamp(self, state, timestamp): self.setState(state, timestamp) def __pollDoor(self, task): self.door = self.cr.doId2do.get(self.doorDoId) if self.door: self.sendUpdate('requestStateAndTimestamp') return task.done return task.cont def getDoorDoId(self): return self.doorDoId def enterOff(self, ts=0): pass def exitOff(self): pass def enterTakeOver(self, ts=0): if not self.door: return self.stopSmooth() self.hasSpawned = False self.doingActivity = True self.reparentTo(self.door.doorNode) self.setHpr(0, 0, 0) self.takeOverTrack = Parallel( Sequence( Func(self.animFSM.request, 'flyDown', [ts]), Wait(6.834), Func(self.loop, 'neutral'), Wait(0.5), Func(self.loop, 'walk'), LerpPosInterval( self, duration=2.0, pos=render.getRelativePoint(self.door.doorNode, self.AtDoorPos), startPos=render.getRelativePoint(self.door.doorNode, self.StartPosFromDoor)), Func(self.loop, 'neutral'), Wait(0.3), Func(self.loop, 'walk'), LerpPosInterval(self, duration=0.5, pos=self.door.enterWalkBackPos, startPos=self.AtDoorPos), Func(self.loop, 'neutral'), Wait(1.0), Func(self.loop, 'walk'), LerpPosInterval(self, duration=1.0, pos=self.door.enterWalkInPos, startPos=self.door.enterWalkBackPos)), LerpPosInterval(self, duration=4.375, pos=render.getRelativePoint( self.door.doorNode, self.StartPosFromDoor), startPos=render.getRelativePoint( self.door.doorNode, self.StartPosFromDoor) + (0, 0, 6.5 * 4.8))) self.takeOverTrack.start(ts) def exitTakeOver(self): self.doingActivity = False if self.takeOverTrack: self.takeOverTrack.pause() self.takeOverTrack = None
class Suit(Avatar): notify = directNotify.newCategory('Suit') def __init__(self): Avatar.__init__(self) self.dept = None self.suit = None self.head = None self.headModel = None self.variant = None self.handColor = None self.voice = None self.chat = None self.chatDial = None self.shadow = None self.deathSound = None self.propeller = None self.smallExp = None self.largeExp = None self.explosion = None self.hasSpawned = False self.suitTrack = None self.timestampAnimTrack = None self.propellerSounds = {} self.healthBar = None self.healthBarGlow = None self.condition = 0 self.avatarType = CIGlobals.Suit self.suitPlan = None self.footstepSound = None self.showNametagInMargins = False self.surfaceProp = "metal" self.activities = {ACT_WAKE_ANGRY : WakeAngry(self), ACT_SMALL_FLINCH : Flinch(self), ACT_DIE : Die(self), ACT_VICTORY_DANCE: VictoryDance(self), ACT_COG_FLY_DOWN : FlyDown(self)} self.standWalkRunReverse = [('neutral', 'walk', 0.0, 5.0, 1.0, 1.0)] self.gruntSound = base.audio3d.loadSfx("phase_14/audio/sfx/cog_grunt.ogg") base.audio3d.attachSoundToObject(self.gruntSound, self) self.animFSM = ClassicFSM('Suit', [ State('off', self.enterOff, self.exitOff), State('neutral', self.enterNeutral, self.exitNeutral), State('walk', self.enterWalk, self.exitWalk), State('die', self.enterDie, self.exitDie), State('win', self.enterWin, self.exitWin), State('flail', self.enterFlail, self.exitFlail), State('flyDown', self.enterFlyDown, self.exitFlyDown), State('flyAway', self.enterFlyAway, self.exitFlyAway), State('flyNeutral', self.enterFlyNeutral, self.exitFlyNeutral), State('trayWalk', self.enterTrayWalk, self.exitTrayWalk), State('trayNeutral', self.enterTrayNeutral, self.exitTrayNeutral), State('stunned', self.enterStunned, self.exitStunned), State('pie', self.enterPie, self.exitPie), State('drop', self.enterDrop, self.exitDrop), State('drop-react', self.enterDropReact, self.exitDropReact), State('soak', self.enterSoak, self.exitSoak), State('squirt-small', self.enterSquirtSmall, self.exitSquirtSmall) ], 'off', 'off') self.animFSM.enterInitialState() def getRightHandNode(self): return self.find("**/joint_Rhold") def getLeftHandNode(self): return self.find("**/joint_Lhold") def getHeadNode(self): return self.headModel def getUpperBodySubpart(self): return [None] def getLowerBodySubpart(self): return [None] def getMoveAction(self, forward, rotate, strafe): return 0 def enterPie(self, ts = 0): self.play('pie') def exitPie(self): self.stop() def enterDrop(self, ts = 0): self.play("drop") def exitDrop(self): self.stop() def enterDropReact(self, ts = 0): self.play('drop-react') def exitDropReact(self): self.stop() def enterSoak(self, ts = 0): self.play('soak') def exitSoak(self): self.stop() def enterSquirtSmall(self, ts = 0): self.play('squirt-small') def exitSquirtSmall(self): self.stop() def enterStunned(self, animB4Stun, ts = 0): self.show() animB4Stun = SuitGlobals.getAnimById(animB4Stun).getName() self.stunnedSound = base.loadSfxOnNode("phase_4/audio/sfx/SZ_TC_bird1.ogg", self) self.stunnedSound.setLoop(True) self.stunnedSound.play() self.stunnedIval = Parallel(Sequence(ActorInterval(self, animB4Stun), Func(self.loop, 'stunned')), SuitGlobals.createStunInterval(self, 0, 100)) self.stunnedIval.start() def clearStunnedIval(self): if hasattr(self, 'stunnedSound'): self.stunnedSound.stop() del self.stunnedSound if hasattr(self, 'stunnedIval'): self.stunnedIval.pause() del self.stunnedIval def exitStunned(self): self.clearStunnedIval() self.stop() def getLeftHand(self): return self.find("**/joint_Lhold") def getRightHand(self): return self.find("**/joint_Rhold") def getNametagJoints(self): return [] # BEGIN STATES def enterOff(self, ts = 0): pass def exitOff(self): pass def exitGeneral(self): self.stop() def enterTrayWalk(self, ts = 0): self.show() self.loop('tray-walk') def exitTrayWalk(self): self.exitGeneral() def enterTrayNeutral(self, ts = 0): self.loop('tray-neutral') def exitTrayNeutral(self): self.stop() def enterNeutral(self, ts = 0): self.show() self.loop("neutral") def exitNeutral(self): self.exitTimestampAnimTrack() self.exitGeneral() def enterWalk(self, ts = 0): self.show() self.loop("walk") self.enableRay() self.disableShadowRay() self.startFootsteps() def exitWalk(self): self.stopFootsteps() self.exitTimestampAnimTrack() self.exitGeneral() self.enableShadowRay() def enterFlail(self, ts = 0): self.pingpong('flail', fromFrame = 30, toFrame = 35) def exitFlail(self): self.stop() def exitTimestampAnimTrack(self): if self.timestampAnimTrack: self.timestampAnimTrack.pause() self.timestampAnimTrack = None def enterFlyNeutral(self, ts = 0): self.disableRay() self.enableShadowRay() if not self.propeller: self.generatePropeller() sfx = self.propellerSounds['neutral'] base.playSfx(sfx, node = self, looping = 1) self.propeller.loop('chan', fromFrame = 0, toFrame = 3) self.setPlayRate(0.8, 'land') self.pingpong('land', fromFrame = 0, toFrame = 10) def exitFlyNeutral(self): self.cleanupPropeller() def enterFlyDown(self, ts = 0): self.disableRay() self.enableShadowRay() if not self.propeller: self.generatePropeller() sfx = self.propellerSounds['in'] base.playSfx(sfx, node = self) groundF = 28 dur = self.getDuration('land') fr = self.getFrameRate('land') if fr: animTimeInAir = groundF / fr else: animTimeInAir = groundF impactLength = dur - animTimeInAir timeTillLanding = 6.5 - impactLength waitTime = timeTillLanding - animTimeInAir lastSpinFrame = 8 propDur = self.propeller.getDuration('chan') fr = self.propeller.getFrameRate('chan') spinTime = lastSpinFrame / fr openTime = (lastSpinFrame + 1) / fr if hasattr(self, 'uniqueName'): name = self.uniqueName('enterFlyDown') else: name = 'enterFlyDown' animTrack = Sequence(Func(self.pose, 'land', 0), Wait(waitTime), ActorInterval(self, 'land', duration=dur)) propTrack = Parallel(SoundInterval(sfx, duration=waitTime + dur, node=self), Sequence(ActorInterval(self.propeller, 'chan', constrainedLoop=1, duration=waitTime + spinTime, startTime=0.0, endTime=spinTime), ActorInterval(self.propeller, 'chan', duration=propDur - openTime, startTime=openTime))) self.suitTrack = Parallel(animTrack, propTrack, name=self.taskName('flyDown')) if not self.hasSpawned: self.show() fadeInTrack = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(1, colorScale=VBase4(1, 1, 1, 1), startColorScale=VBase4(1, 1, 1, 0)), Func(self.clearColorScale), Func(self.clearTransparency)) self.hasSpawned = True self.suitTrack.append(fadeInTrack) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.exitFlyDown) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self, name) self.suitTrack.start(ts) def exitFlyDown(self): self.cleanupPropeller() self.enableRay() if self.suitTrack != None: self.ignore(self.suitTrack.getDoneEvent()) self.suitTrack.finish() DelayDelete.cleanupDelayDeletes(self.suitTrack) self.suitTrack = None self.exitGeneral() def enterFlyAway(self, ts = 0, doFadeOut = 0): self.show() if not self.propeller: self.generatePropeller() sfx = self.propellerSounds['out'] if hasattr(self, 'uniqueName'): name = self.uniqueName('enterFlyAway') else: name = 'enterFlyAway' dur = self.getDuration('land') actInt = ActorInterval(self, 'land', loop=0, startTime=dur, endTime=0.0) lastSpinFrame = 8 propDur = self.propeller.getDuration('chan') fr = self.propeller.getFrameRate('chan') spinTime = lastSpinFrame / fr openTime = (lastSpinFrame + 1) / fr propTrack = Parallel(SoundInterval(sfx, node=self), Sequence(Func(self.propeller.show), ActorInterval(self.propeller, 'chan', endTime=openTime, startTime=propDur), ActorInterval(self.propeller, 'chan', constrainedLoop=1, duration=propDur - openTime, startTime=spinTime, endTime=0.0))) self.suitTrack = Parallel(actInt, propTrack, name=self.taskName('trackName')) if doFadeOut: fadeOut = Sequence(Wait(4.0), Func(self.setTransparency, 1), self.colorScaleInterval(1, colorScale=VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1)), Func(self.clearColorScale), Func(self.clearTransparency), Func(self.reparentTo, hidden)) self.suitTrack.append(fadeOut) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.exitFlyAway) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self, name) self.suitTrack.start(ts) self.disableRay() self.enableShadowRay() def exitFlyAway(self): self.cleanupPropeller() if self.suitTrack: self.ignore(self.suitTrack.getDoneEvent()) self.suitTrack.finish() DelayDelete.cleanupDelayDeletes(self.suitTrack) self.suitTrack = None self.exitGeneral() def enterDie(self, ts = 0): self.show() self.clearStunnedIval() self.generateCog(isLose = 1) self.nametag.clearChatText() self.deleteNameTag() self.deathSound = base.audio3d.loadSfx("phase_3.5/audio/sfx/Cog_Death_Full.ogg") base.audio3d.attachSoundToObject(self.deathSound, self) trackName = self.uniqueName('enterDie') smallGears = ParticleLoader.loadParticleEffect('phase_3.5/etc/gearExplosionSmall.ptf') smallGears.getParticlesNamed('particles-1').setPoolSize(30) smallGears.setShaderOff(1) singleGear = ParticleLoader.loadParticleEffect('phase_3.5/etc/gearExplosion.ptf') singleGear.getParticlesNamed('particles-1').setPoolSize(1) singleGear.setShaderOff(1) smallGearExplosion = ParticleLoader.loadParticleEffect('phase_3.5/etc/gearExplosion.ptf') smallGearExplosion.getParticlesNamed('particles-1').setPoolSize(10) smallGearExplosion.setShaderOff(1) bigGearExplosion = ParticleLoader.loadParticleEffect('phase_3.5/etc/gearExplosionBig.ptf') bigGearExplosion.getParticlesNamed('particles-1').setPoolSize(30) bigGearExplosion.setShaderOff(1) smallGears.setDepthWrite(False) smallGears.hide(CIGlobals.ShadowCameraBitmask) singleGear.setDepthWrite(False) singleGear.hide(CIGlobals.ShadowCameraBitmask) smallGearExplosion.setDepthWrite(False) smallGearExplosion.hide(CIGlobals.ShadowCameraBitmask) bigGearExplosion.setDepthWrite(False) bigGearExplosion.hide(CIGlobals.ShadowCameraBitmask) self.smallGears = smallGears self.smallGears.setPos(self.find('**/joint_head').getPos() + (0,0, 2)) self.singleGear = singleGear self.smallGearExp = smallGearExplosion self.bigGearExp = bigGearExplosion gearTrack = Sequence(Wait(0.7), Func(self.doSingleGear), Wait(1.5), Func(self.doSmallGears), Wait(3.0), Func(self.doBigExp)) self.suitTrack = Parallel(Sequence(Wait(0.8), SoundInterval(self.deathSound, duration = 4.28)), Sequence(Wait(0.7), Func(self.doSingleGear), Wait(4.5), Func(self.suitExplode), Wait(1.0), Func(self.disableBodyCollisions)), gearTrack, Sequence(ActorInterval(self, 'lose', duration = 6), Func(self.getGeomNode().hide)), name = trackName) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getName(), self.exitDie) if self.isDistributed(): self.suitTrack.delayDelete = DelayDelete.DelayDelete(self, trackName) self.suitTrack.start(ts) def doSingleGear(self): self.singleGear.start(self.getGeomNode()) def doSmallGears(self): self.smallGears.start(self.getGeomNode()) def doSmallExp(self): self.smallGearExp.start(self.getGeomNode()) def doBigExp(self): self.bigGearExp.start(self.getGeomNode()) def suitExplode(self): pos = self.getPart('body').find('**/joint_head').getPos(render) + (0, 0, 2) # Force the loser suit to use UnlitGeneric shader, workaround for the has_mat() assertion BSPUtility.applyUnlitOverride(self) CIGlobals.makeExplosion(pos, 0.5, soundVol = 0.32) def exitDie(self): if self.suitTrack != None: self.ignore(self.suitTrack.getName()) self.suitTrack.finish() if self.isDistributed(): DelayDelete.cleanupDelayDeletes(self.suitTrack) self.suitTrack = None if hasattr(self, 'singleGear'): self.singleGear.softStop() del self.singleGear if hasattr(self, 'smallGears'): self.smallGears.softStop() del self.smallGears if hasattr(self, 'smallGearExp'): self.smallGearExp.softStop() del self.smallGearExp if hasattr(self, 'bigGearExp'): self.bigGearExp.softStop() del self.bigGearExp if self.deathSound: self.deathSound.stop() self.deathSound = None def enterWin(self, ts = 0): self.play('win') def exitWin(self): self.exitGeneral() # END STATES def generateSuit(self, suitPlan, variant, voice = None, hideFirst = False): self.suitPlan = suitPlan self.suit = suitPlan.getSuitType() self.head = suitPlan.getHead() self.dept = suitPlan.getDept() self.handColor = suitPlan.getHandColor() self.variant = variant self.setVoice(voice) self.generateCog() mat = CIGlobals.getCharacterMaterial(shininess = 50.0, specular = (0.4, 0.4, 0.4, 1)) self.setMaterial(mat) #ts = TextureStage('shiny') #ts.setMode(TextureStage.MAdd) #ts.setRgbScale(2) #tex = loader.loadCubeMap('phase_14/maps/cubemap/defaultcubemap_#.png') #tex = loader.loadTexture('phase_14/maps/envmap001a_cog.png') #self.setTexGen(ts, TexGenAttrib.MEyeSphereMap) #self.setTexture(ts, tex) self.initializeBodyCollisions() if hideFirst: self.hide() else: self.show() def __blinkRed(self, task): self.healthBar.setColor(SuitGlobals.healthColors[3], 1) self.healthBarGlow.setColor(SuitGlobals.healthGlowColors[3], 1) if self.condition == 5: self.healthBar.setScale(1.17) return task.done def __blinkGray(self, task): if not self.healthBar: return self.healthBar.setColor(SuitGlobals.healthColors[4], 1) self.healthBarGlow.setColor(SuitGlobals.healthGlowColors[4], 1) if self.condition == 5: self.healthBar.setScale(1.0) return task.done def generateHealthBar(self): self.removeHealthBar() button = loader.loadModel('phase_3.5/models/gui/matching_game_gui.bam').find('**/minnieCircle') button.setScale(3.0) button.setH(180) button.setColor(SuitGlobals.healthColors[0]) chestNull = self.find('**/def_joint_attachMeter') if chestNull.isEmpty(): chestNull = self.find('**/joint_attachMeter') button.reparentTo(chestNull) self.healthBar = button self.healthBarGlow = loader.loadModel('phase_3.5/models/props/glow.bam') self.healthBarGlow.reparentTo(self.healthBar) self.healthBarGlow.setScale(0.28) self.healthBarGlow.setPos(-0.005, 0.01, 0.015) self.healthBarGlow.setColor(SuitGlobals.healthGlowColors[0]) button.flattenLight() button.setLightOff() self.condition = 0 if hasattr(self, 'getHealth'): self.updateHealthBar(self.getHealth()) def updateHealthBar(self, hp): if not self.healthBar: return if hp > self.health: self.health = hp health = 0.0 try: health = float(hp) / float(self.maxHealth) except: pass if health > 0.95: condition = 0 elif health > 0.7: condition = 1 elif health > 0.3: condition = 2 elif health > 0.05: condition = 3 elif health > 0.0: condition = 4 else: condition = 5 if self.condition != condition: taskMgr.remove(self.taskName('blink-task')) if condition == 4: blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.75), Task(self.__blinkGray), Task.pause(0.1)) taskMgr.add(blinkTask, self.taskName('blink-task')) elif condition == 5: blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.25), Task(self.__blinkGray), Task.pause(0.1)) taskMgr.add(blinkTask, self.taskName('blink-task')) else: self.healthBar.setColor(SuitGlobals.healthColors[condition], 1) self.healthBarGlow.setColor(SuitGlobals.healthGlowColors[condition], 1) self.condition = condition def removeHealthBar(self): if self.healthBar: self.healthBar.removeNode() self.healthBar = None if self.condition == 4 or self.condition == 5: taskMgr.remove(self.taskName('blink-task')) self.healthCondition = 0 return def initializeBodyCollisions(self): self.notify.info('Initializing Body Collisions!') self.setupPhysics(2, self.getHeight()) self.enableRay() def hideSuit(self): self.hide() def showSuit(self): self.show() fadeIn = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(0.6, colorScale=Vec4(1,1,1,1), startColorScale=Vec4(1,1,1,0)), Func(self.clearColorScale), Func(self.clearTransparency), Func(self.reparentTo, render)) fadeIn.start() def doStunEffect(self): self.clearStunnedIval() self.stunnedIval = SuitGlobals.createStunInterval(self, 0, 2) self.stunnedIval.start() def doGagEffect(self, flags): GagEffects.doGagEffect(self, flags) def generateCog(self, isLose = 0, nameTag = True): self.cleanup() if not isLose: if self.variant == Variant.SKELETON or self.variant == Variant.ZOMBIE: self.loadModel('phase_5/models/char/cog%s_robot-zero.bam' % (str(self.suit)), 'body') else: self.loadModel('phase_3.5/models/char/suit%s-mod.bam' % (str(self.suit)), 'body') animations = SuitGlobals.animations anims = {} for anim in animations: if not self.suit in anim.getSuitTypes(): continue path = 'phase_%s/models/char/suit%s-%s.bam' % (anim.getPhase(), self.suit, anim.getFile()) anims[anim.getName()] = path self.loadAnims(anims, 'body') self.generateHealthBar() if self.suitPlan.suitType == SuitType.A: self.footstepSound = base.audio3d.loadSfx("phase_5/audio/sfx/ENC_cogafssm.ogg") elif self.suitPlan.suitType == SuitType.B: self.footstepSound = base.audio3d.loadSfx("phase_5/audio/sfx/ENC_cogbfssm.ogg") elif self.suitPlan.suitType == SuitType.C: self.footstepSound = base.audio3d.loadSfx("phase_5/audio/sfx/ENC_cogcfssm.ogg") if self.footstepSound: base.audio3d.attachSoundToObject(self.footstepSound, self) else: if self.variant == Variant.SKELETON or self.variant == Variant.ZOMBIE: self.loadModel('phase_5/models/char/cog%s_robot-lose-mod.bam' % (str(self.suit)), 'body') else: self.loadModel('phase_4/models/char/suit%s-lose-mod.bam' % (str(self.suit)), 'body') self.loadAnims({'lose' : 'phase_4/models/char/suit%s-lose.bam' % (str(self.suit))}, 'body') if self.variant != Variant.SKELETON: self.headModel = self.head.generate() self.headModel.reparentTo(self.find("**/joint_head")) if self.suitPlan.getName() == SuitGlobals.VicePresident: self.headModel.setScale(0.35) self.headModel.setHpr(270, 0, 270) self.headModel.setZ(-0.10) self.headModel.loop('neutral') self.setClothes() classScale = 1.0#self.suitPlan.getCogClassAttrs().scaleMod self.setAvatarScale((self.suitPlan.getScale() / SuitGlobals.scaleFactors[self.suit]) * classScale) #self.setHeight(self.suitPlan.getHeight()) if nameTag: self.setupNameTag() Avatar.initShadow(self) # We've already done all manipulating to the cog, we can just flatten it. self.getPart('body').flattenStrong() self.postFlatten() self.headModel.flattenStrong() if isinstance(self.headModel, Actor): self.headModel.postFlatten() def cleanup(self): if self.footstepSound: self.footstepSound.stop() self.footstepSound = None self.cleanupPropeller() self.clearChatbox() if self.shadow: self.deleteShadow() if self.headModel: self.headModel.removeNode() self.headModel = None if self.getPart('body'): self.removePart('body') self.timestampAnimTrack = None def generatePropeller(self): self.cleanupPropeller() self.propeller = Actor('phase_4/models/props/propeller-mod.bam', {'chan' : 'phase_4/models/props/propeller-chan.bam'}) self.propeller.reparentTo(self.find("**/joint_head")) self.propellerSounds['in'] = base.audio3d.loadSfx(SuitGlobals.propellerInSfx) self.propellerSounds['out'] = base.audio3d.loadSfx(SuitGlobals.propellerOutSfx) self.propellerSounds['neutral'] = base.audio3d.loadSfx(SuitGlobals.propellerNeutSfx) for sound in self.propellerSounds.values(): base.audio3d.attachSoundToObject(sound, self.propeller) def cleanupPropeller(self): for sound in self.propellerSounds.values(): base.audio3d.detachSound(sound) sound.stop() self.propellerSounds = {} if self.propeller and not self.propeller.isEmpty(): self.propeller.cleanup() self.propeller = None def setVoice(self, voice): if not voice: if self.variant == Variant.SKELETON or self.variant == Variant.ZOMBIE: self.voice = Voice.SKELETON else: self.voice = Voice.NORMAL else: self.voice = voice def setClothes(self): if self.variant == Variant.SKELETON: parts = self.findAllMatches('**/pPlane*') for partNum in range(0, parts.getNumPaths()): bb = parts.getPath(partNum) bb.setTwoSided(1) tie = 'phase_5/maps/cog_robot_tie_%s.mat' % self.dept.getTie() #tie.setMinfilter(Texture.FTLinearMipmapLinear) #tie.setMagfilter(Texture.FTLinear) self.find('**/tie').setBSPMaterial(tie, 1) else: prefix = 'phase_3.5/maps/' + self.dept.getClothingPrefix() + '_%s.mat' if self.variant == Variant.WAITER: prefix = 'phase_3.5/maps/waiter_m_%s.mat' elif self.variant == Variant.CORRODED: prefix = 'phase_3.5/maps/' + self.dept.getClothingPrefix() + '_rust_%s.mat' legTex = prefix % 'leg' armTex = prefix % 'sleeve' blazTex = prefix % 'blazer' texs = [legTex, armTex, blazTex] #for texture in texs: # texture.setMinfilter(Texture.FTLinearMipmapLinear) # texture.setMagfilter(Texture.FTLinear) self.find('**/legs').setBSPMaterial(legTex, 1) self.find('**/arms').setBSPMaterial(armTex, 1) self.find('**/torso').setBSPMaterial(blazTex, 1) self.find('**/hands').setBSPMaterial("phase_3.5/maps/tt_t_ene_sellbotRental_hand.mat", 1) if not self.variant == Variant.CORRODED: self.find('**/hands').setColor(self.handColor) else: self.find('**/hands').setColor(Variant.CORRODED_HAND_COLOR) def startFootsteps(self): classAttrs = self.suitPlan.getCogClassAttrs() if not self.footstepSound or not classAttrs.footsteps: return self.footstepSound.setPlayRate(classAttrs.walkMod) self.footstepSound.setLoop(True) self.footstepSound.play() def stopFootsteps(self): if not self.footstepSound: return self.footstepSound.stop() def setName(self, nameString, charName): Avatar.setName(self, nameString, charName = charName, createNow = 1) def setupNameTag(self, tempName = None): Avatar.setupNameTag(self, tempName = tempName) if self.nametag: if self.level > 0: self.nametag.setText(self.nametag.getText() + '\n%s\nLevel %s %s' % (self.dept.getName(), self.level, self.suitPlan.getCogClassName())) else: self.nametag.setText(self.nametag.getText() + '\n%s' % (self.dept.getName())) def chatStompComplete(self, chatString): if not CIGlobals.getSettingsMgr().getSetting("chs").getValue(): return self.chat = chatString chatDial = None questionDial = self.voice.getSoundFile('question') question02Dial = None gruntDial = self.voice.getSoundFile('grunt') statementDial = self.voice.getSoundFile('statement') if self.voice == Voice.NORMAL: question02Dial = self.voice.getSoundFile('question_2') if '!' in self.chat: chatDial = base.audio3d.loadSfx(gruntDial) elif '?' in self.chat: questionDials = [questionDial] if self.voice == Voice.NORMAL: questionDials.append(question02Dial) chatDial = base.audio3d.loadSfx(random.choice(questionDials)) else: chatDial = base.audio3d.loadSfx(statementDial) self.chatDial = chatDial # Make the voice higher/lower based on the class voiceMod = self.suitPlan.getCogClassAttrs().voiceMod self.chatDial.setPlayRate(voiceMod) if self.variant == Variant.SKELETON: base.audio3d.attachSoundToObject(self.chatDial, self) else: base.audio3d.attachSoundToObject(self.chatDial, self.headModel) base.playSfx(self.chatDial, node = self) def setChat(self, chat): self.clearChatbox() Avatar.setChat(self, chat) self.chat = chat def clearChatbox(self): self.clearChat() self.chat = None if self.chatDial: base.audio3d.detachSound(self.chatDial) self.chatDial.stop() self.chatDial = None def getDept(self): return self.dept def getVariant(self): return self.variant def disable(self): if self.suitTrack: self.suitTrack.finish() DelayDelete.cleanupDelayDeletes(self.suitTrack) self.suitTrack = None self.animFSM.requestFinalState() self.cleanup() Avatar.disable(self) def delete(self): Avatar.delete(self) self.cleanup()
class TrainController: """Object to control the locomotive. Implements changing the locomotive speed and animation. Also manages moving the locomotive along motion paths. Args: model (panda3d.core.NodePath): The locomotive model. """ def __init__(self, model): self._model = model self._move_snd, self._stop_snd, self._brake_snd = self._set_sounds( model) self._move_anim_int = model.actorInterval("move_forward", playRate=14) self._move_anim_int.loop() # parallel with the Train model and camera move intervals self._move_par = Parallel() self._is_stopped = False self._outing_available = None self._move_snd_volume = 1 self._garland = None self._confetti = None self._confetti_cooldown = False self._confetti_snd = None self.on_et = False self.critical_damage = False self.max_speed = 1 @property def current_speed(self): """Current locomotive speed. Returns float: Current locomotive speed (play rate). """ return 0 if self._is_stopped else self._move_anim_int.getPlayRate() def _change_speed(self, diff, task): """Actually change the locomotive speed. Args: diff (float): Coefficient to change the Train speed. """ if self._is_stopped and diff > 0: self.start_move() new_rate = round(self._move_anim_int.getPlayRate() + diff, 2) if (self.on_et # don't stop on enemy territory and diff < 0 # stop on enemy territory only # in case of critical damage and not self.critical_damage and new_rate < MIN_SPEED): return task.again if new_rate > self.max_speed and diff > 0: return task.again # change speed if 0 < new_rate <= 1: self._move_anim_int.setPlayRate(new_rate) self._move_par.setPlayRate(new_rate) new_snd_rate = new_rate * 1.2 if 0.25 <= new_snd_rate <= 1: self._move_snd.setPlayRate(new_snd_rate) return task.again if new_rate == 0: self._stop_move() return task.done def _change_speed_delayed(self, diff): """Start changing the locomotive speed. To make speed changing smoother delayed task is used. Args: diff (float): Coefficient to change speed. """ taskMgr.doMethodLater( # noqa: F821 0.6, self._change_speed, "change_train_speed", extraArgs=[diff], appendTask=True, ) def _finish_stopping(self, task): """Finish stopping the damaged Train.""" taskMgr.remove("stop_train") # noqa: F821 base.train.stop_sparks() # noqa: F821 base.main_menu.show(is_game_over=True) # noqa: F821 return task.done def _set_sounds(self, model): """Set interactive locomotive sounds. Args: model (panda3d.core.NodePath): The locomotive model. Returns: (panda3d.core.AudioSound...): Interactive locomotive sounds. """ move_snd = base.sound_mgr.loadSfx( "sounds/train/ride.ogg") # noqa: F821 base.sound_mgr.attachSoundToObject(move_snd, model) # noqa: F821 move_snd.setLoop(True) move_snd.setVolume(0) move_snd.play() stop_snd = base.sound_mgr.loadSfx( "sounds/train/stop.ogg") # noqa: F821 base.sound_mgr.attachSoundToObject(stop_snd, model) # noqa: F821 brake_snd = base.sound_mgr.loadSfx( "sounds/train/brake.ogg") # noqa: F821 brake_snd.setLoop(True) base.sound_mgr.attachSoundToObject(brake_snd, model) # noqa: F821 return move_snd, stop_snd, brake_snd def start_move_sound(self): """Start playing the move sound.""" self._move_snd.setVolume(1) def _shot_flapper(self): """Play an effect and sound of a flapper.""" if not self._confetti_cooldown and self._confetti is not None: for effect in self._confetti: effect.start(self._model, render) # noqa: F821 effect.softStart() taskMgr.doMethodLater( # noqa: F821 1.97, self._stop_flapper, "stop_flapper") self._confetti_cooldown = True self._confetti_snd.play() def _stop_flapper(self, task): """Stop all the flapper effects.""" for effect in self._confetti or []: effect.softStop() self._confetti_cooldown = False return task.done def _stop_move(self): """Stop the Train movement.""" taskMgr.doMethodLater( # noqa: F821 0.6, self._stop_snd.play, "train_stop_snd", extraArgs=[]) base.train.stop_sparks() # noqa: F821 self._move_par.pause() self._move_anim_int.pause() taskMgr.doMethodLater( # noqa: F821 0.7, base.train.stop, "release_steam", extraArgs=[] # noqa: F821 ) self._is_stopped = True taskMgr.doMethodLater( # noqa: F821 0.07, drown_snd, "drown_move_snd", extraArgs=[self._move_snd], appendTask=True, ) if self._outing_available: base.world.start_outing(self._outing_available) # noqa: F821 self._outing_available = None def _switch_garland(self): """Christmas related method. Enables or removes the locomotive garland and an ability to shot a flapper. """ if self._garland is None: self._garland = loader.loadModel(address("garland")) # noqa: F821 self._garland.reparentTo(self._model) self._confetti = [] for color in ("red", "blue", "green"): confetti = ParticleEffect() confetti.loadConfig("effects/confetti_{}.ptf".format(color)) confetti.setPos(0, 0.32, 0.29) self._confetti.append(confetti) self._confetti_snd = base.sound_mgr.loadSfx( # noqa: F821 "sounds/train/flapper.ogg") base.sound_mgr.attachSoundToObject( # noqa: F821 self._confetti_snd, self._model) else: self._garland.removeNode() self._garland = None for effect in self._confetti: effect.softStop() effect.cleanup() self._confetti = None base.sound_mgr.detach_sound(self._confetti_snd) # noqa: F821 self._confetti_snd = None def brake_down_to(self, target): """Slow down the Train to the given speed. Args: target (float): Target speed. """ if self._brake_snd.status() == AudioSound.PLAYING: self._brake_snd.setVolume(1) else: self._brake_snd.play() taskMgr.doMethodLater( # noqa: F821 3, drown_snd, "drown_brake_snd", extraArgs=[self._brake_snd], appendTask=True, ) self.slow_down_to(target) def drown_move_snd(self): """Reduce the main move sound volume.""" if self._move_snd_volume == 1: self._move_snd.setVolume(0.5) self._move_snd_volume = 0.5 def move_along_block(self, block, train_np, do_turn): """Start the locomotive move intervals for the given block. There are two intervals: the locomotive movement and synchronous camera movement. Args: block (world.block.Block): The World block to move along. train_np (panda3d.core.NodePath): Train node. do_turn (int): 0 if default direction was chosen, 1 if a turn is needed. """ self.on_et = block.enemy_territory self._outing_available = block.outing_available # use speed value from the last block rate = self._move_par.getPlayRate() if self._move_par else 1 is_fork = block.name in ("r_fork", "l_fork", "exit_from_fork") self._move_par = Parallel( MopathInterval( # locomotive movement block.path[do_turn] if is_fork else block.path, self._model, duration=4.4, name="current_path", ), MopathInterval( # camera movement block.cam_path[do_turn] if is_fork else block.cam_path, train_np, duration=4.4, name="current_camera_path", ), ) self._move_par.setDoneEvent("block_finished") self._move_par.start() self._move_par.setPlayRate(rate) def load_speed(self, speed): """Load previously saved locomotive speed. Args: speed (float): Rate to set for animation, move and sounds. """ self._move_par.setPlayRate(speed) self._move_anim_int.setPlayRate(speed) self._move_snd.setPlayRate(min(max(0.25, speed * 1.2), 1)) if not speed: self._move_snd.stop() self._is_stopped = True def pause_movement(self): """Make a movement pause (used when a tutorial page is shown).""" self._move_par.pause() self._move_anim_int.pause() self._move_snd.stop() def set_controls(self, train): """Configure the locomotive control keys. Args: train (train.Train): The locomotive object. """ # speed smoothly changes while holding w/s keys base.accept("w", self._change_speed_delayed, [0.05]) # noqa: F821 base.accept("s", self._change_speed_delayed, [-0.05]) # noqa: F821 base.accept("w-up", taskMgr.remove, ["change_train_speed"]) # noqa: F821 base.accept("s-up", taskMgr.remove, ["change_train_speed"]) # noqa: F821 base.accept("7", self._switch_garland) # noqa: F821 base.accept("8", self._shot_flapper) # noqa: F821 base.accept("9", base.effects_mgr.love_fog.switch) # noqa: F821 base.accept("f", train.toggle_lights) # noqa: F821 def start_move(self): """Start the Train movement.""" self._move_par.resume() self._move_anim_int.resume() self._move_snd.play() self._is_stopped = False def speed_to_min(self): """Accelerate to minimum speed. Used when locomotive got on enemy territory. """ taskMgr.remove("change_train_speed") # noqa: F821 speed = self._move_anim_int.getPlayRate() if speed >= MIN_SPEED: return # calculate acceleration length acc_steps = (MIN_SPEED - speed) / 0.05 # start accelerating taskMgr.doMethodLater( # noqa: F821 0.6, self._change_speed, "speed_up_train", extraArgs=[0.05], appendTask=True) # stop accelerating taskMgr.doMethodLater( # noqa: F821 0.6 * acc_steps + 0.2, taskMgr.remove, # noqa: F821 "stop_speedind_up", extraArgs=["speed_up_train"], ) def slow_down_to(self, target): """Slow down the locomotive to the given speed. Args: target (float): Target speed. """ taskMgr.remove("change_train_speed") # noqa: F821 speed = self._move_anim_int.getPlayRate() if speed <= target: return # calculate deceleration length acc_steps = (speed - target) / 0.05 # start decelerating taskMgr.doMethodLater( # noqa: F821 0.6, self._change_speed, "slow_down_train", extraArgs=[-0.05], appendTask=True, ) # stop decelerating taskMgr.doMethodLater( # noqa: F821 0.6 * acc_steps + 0.2, taskMgr.remove, # noqa: F821 "stop_slowing_down", extraArgs=["slow_down_train"], ) def stop(self, urgent=False, place_of_interest=False): """Completely stop the locomotive. Args: urgent (bool): If True, deceleration speed will be much higher. Used for stopping in places of interest and cities. place_of_interest (bool): If True, that means the stop is initiated by a place of interest. """ base.ignore("w") # noqa: F821 base.ignore("s") # noqa: F821 taskMgr.remove("change_train_speed") # noqa: F821 delay = 0.25 if urgent else 0.6 # calculate deceleration length speed = self._move_anim_int.getPlayRate() taskMgr.doMethodLater( # noqa: F821 delay, self._change_speed, "stop_train", extraArgs=[-0.05], appendTask=True) if urgent: if place_of_interest: taskMgr.doMethodLater( # noqa: F821 delay * (speed / 0.05) + 0.8, base.scenario.start_chapter, # noqa: F821 "start_scenario_chapter", ) else: # stop decelerating taskMgr.doMethodLater( # noqa: F821 delay * (speed / 0.05) + 0.8, self._finish_stopping, "finish_stopping") taskMgr.doMethodLater( # noqa: F821 delay * (speed / 0.05) + 0.2, base.world.enemy.stop_ride_anim, # noqa: F821 "stop_riding", ) def raise_move_snd(self): """Restore full volume of the main move sound.""" if self._move_snd_volume == 0.5: self._move_snd.setVolume(1) self._move_snd_volume = 1 def silence_move_snd(self): """Silence the movement sound.""" self._stop_snd.setVolume(0) taskMgr.doMethodLater( # noqa: F821 0.1, drown_snd, "stop_snd", extraArgs=[self._move_snd], appendTask=True) def unset_controls(self): """Disable all the locomotive controls.""" for key in ("w", "s", "w-up", "s-up", "f"): base.ignore(key) # noqa: F821
class Movement(DirectObject.DirectObject): def __init__(self, parent): self.parent = parent self.hovered_unit_id = None self.hovered_tile = None self.hovered_compass_tile = None self.mouse_node = aspect2d.attachNewNode('mouse_node') self.move_node = aspect2d.attachNewNode('move_node') self.move_outline_node = NodePath('') self.move_np_list = [] self.target_info_node = None self.accept("mouse1", self.mouseLeftClick) self.accept("mouse1-up", self.mouseLeftClickUp) #taskMgr.add(self.rayupdate, 'rayupdate_task') taskMgr.add(self.pickerTask, 'picker_task') taskMgr.add(self.positionTask, 'position_task', sort=2) self.color_scale_parallel = None # Create movement compass nodes self.turn_node = NodePath('turn_node') self.turn_node.setTag('show', '0') self.turn_np_list = [] for i in xrange(9): text = TextNode('node name') text.setAlign(TextNode.ACenter) if i == 0: text.setText('NW') key = utils.HEADING_NW elif i == 1: text.setText('N') key = utils.HEADING_N elif i == 2: text.setText('NE') key = utils.HEADING_NE elif i == 3: text.setText('W') key = utils.HEADING_W elif i == 4: text.setText('E') key = utils.HEADING_E elif i == 5: text.setText('SW') key = utils.HEADING_SW elif i == 6: text.setText('S') key = utils.HEADING_S elif i == 7: text.setText('SE') key = utils.HEADING_SE elif i == 8: text.setText('X') key = utils.HEADING_NONE textNodePath = self.turn_node.attachNewNode(text) textNodePath.setColor(1, 1, 1) textNodePath.setScale(0.06) textNodePath.setTag('key', str(key)) self.turn_np_list.append(textNodePath) def calcUnitAvailMove(self, unit_id): """Displays visual indicator of tiles which are in movement range of the selected unit.""" # First delete old movement list for c in self.move_np_list: c.removeNode() self.move_np_list = [] # Start calculation of new list unit = self.parent.local_engine.units[unit_id] if self.parent.turn_player != self.parent.player_id: return if unit: unit['move_dict'] = getMoveDict(unit, self.parent.local_engine.level, self.parent.local_engine.units) self.parent.local_engine.units[unit_id]['move_dict'] = unit[ 'move_dict'] move_dict = unit['move_dict'] for tile in move_dict: text = TextNode('node name') text.setText("%s" % move_dict[tile]) text.setAlign(TextNode.ACenter) textNodePath = self.move_node.attachNewNode(text) textNodePath.setColor(1, 1, 1) textNodePath.setScale(0.06) textNodePath.setPythonTag('pos', tile) pos2d = utils.pointCoordIn2d( Point3(utils.TILE_SIZE * (tile[0] + 0.5), utils.TILE_SIZE * (tile[1] + 0.5), utils.GROUND_LEVEL)) textNodePath.setPos(pos2d) self.move_np_list.append(textNodePath) def showUnitAvailMove(self): self.move_node.reparentTo(aspect2d) self.hovered_tile = None #self.drawMoveOutline(self.calcMoveOutline(move_dict, self.parent.local_engine.units[unit_id]['pos'])) def hideUnitAvailMove(self): self.move_node.detachNode() """ def calcMoveOutline(self, move_dict, pos): outline = {} for tile in move_dict: dir = [] if not (tile[0]-1, tile[1]) in move_dict and (tile[0]-1, tile[1]) != pos: dir.append('W') if not (tile[0], tile[1]-1) in move_dict and (tile[0], tile[1]-1) != pos: dir.append('S') if not (tile[0]+1, tile[1]) in move_dict and (tile[0]+1, tile[1]) != pos: dir.append('E') if not (tile[0], tile[1]+1) in move_dict and (tile[0], tile[1]+1) != pos: dir.append('N') if dir != []: outline[tile] = dir return outline def drawMoveOutline(self, outline): self.move_outline_node.removeNode() zpos = utils.GROUND_LEVEL + 0.01 off = 0.1 segs = LineSegs() segs.setThickness(3) segs.setColor(Vec4(0.686,1,0.992,1)) for tile in outline: for dir in outline[tile]: if dir == 'N': d1 = 0 d2 = 0 if (tile[0]+1, tile[1]) in outline and 'N' in outline[(tile[0]+1, tile[1])]: d2 = off elif (tile[0]+1, tile[1]+1) in outline: d2 = 2*off if (tile[0]-1, tile[1]) in outline and 'N' in outline[(tile[0]-1, tile[1])]: d1 = off elif (tile[0]-1, tile[1]+1) in outline: d1 = 2*off segs.moveTo(tile[0]+off-d1, tile[1]+1-off, zpos) segs.drawTo(tile[0]+1-off+d2, tile[1]+1-off, zpos) elif dir == 'S': d1 = 0 d2 = 0 if (tile[0]+1, tile[1]) in outline and 'S' in outline[(tile[0]+1, tile[1])]: d2 = off elif (tile[0]+1, tile[1]-1) in outline: d2 = 2*off if (tile[0]-1, tile[1]) in outline and 'S' in outline[(tile[0]-1, tile[1])]: d1 = off elif (tile[0]-1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+off-d1, tile[1]+off, zpos) segs.drawTo(tile[0]+1-off+d2, tile[1]+off, zpos) elif dir == 'W': d1 = 0 d2 = 0 if (tile[0], tile[1]+1) in outline and 'W' in outline[(tile[0], tile[1]+1)]: d2 = off elif (tile[0]-1, tile[1]+1) in outline: d2 = 2*off if (tile[0], tile[1]-1) in outline and 'W' in outline[(tile[0], tile[1]-1)]: d1 = off elif (tile[0]-1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+off, tile[1]+off-d1, zpos) segs.drawTo(tile[0]+off, tile[1]+1-off+d2, zpos) elif dir == 'E': d1 = 0 d2 = 0 if (tile[0], tile[1]+1) in outline and 'E' in outline[(tile[0], tile[1]+1)]: d2 = off elif (tile[0]+1, tile[1]+1) in outline: d2 = 2*off if (tile[0], tile[1]-1) in outline and 'E' in outline[(tile[0], tile[1]-1)]: d1 = off elif (tile[0]+1, tile[1]-1) in outline: d1 = 2*off segs.moveTo(tile[0]+1-off, tile[1]+off-d1, zpos) segs.drawTo(tile[0]+1-off, tile[1]+1-off+d2, zpos) self.move_outline_node = render.attachNewNode(segs.create()) self.move_outline_node.setBin("fixed", 40) #self.move_outline_node.setDepthTest(False) #self.move_outline_node.setDepthWrite(False) self.move_outline_node.setLightOff() """ def showMoveCompass(self, dest): # Calculate postion of compass nodes based on destination tile for i in self.turn_np_list: i.setPythonTag('pos', utils.getHeadingTile(i.getTag('key'), dest)) # Show compass nodes self.turn_node.reparentTo(aspect2d) self.turn_node.setPythonTag('pos', dest) self.turn_node.setTag('show', '1') # Hide move nodes self.move_node.detachNode() def hideMoveCompass(self): # Hide compass nodes self.turn_node.detachNode() self.turn_node.setTag('show', '0') if self.hovered_compass_tile != None: self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_compass_tile = None def mouseLeftClick(self): if self.parent.interface.hovered_gui != None: return if self.hovered_unit_id != None: unit_id = int(self.hovered_unit_id) pickedCoord = self.parent.local_engine.getCoordsByUnit(unit_id) # Player can only select his own units if self.parent.local_engine.isThisMyUnit(unit_id): if unit_id != self.parent.sel_unit_id: self.parent.selectUnit(unit_id) else: # Remember movement tile so we can send orientation message when mouse is depressed # Do this only if it is our turn if self.parent.player_id == self.parent.turn_player: self.unit_move_destination = pickedCoord self.showMoveCompass(self.unit_move_destination) elif self.parent.local_engine.isThisEnemyUnit(unit_id): if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player: self.parent.render_manager.unit_renderer_dict[ self.parent. sel_unit_id].target_unit = self.parent.render_manager.unit_renderer_dict[ unit_id] if self.parent._anim_in_process == False: ClientMsg.shoot(self.parent.sel_unit_id, unit_id) elif self.hovered_tile != None: if self.parent.sel_unit_id != None and self.parent.player_id == self.parent.turn_player: # Remember movement tile so we can send movement message when mouse is depressed # Do this only if it is our turn move_coord = self.hovered_tile.getPythonTag('pos') if self.parent.local_engine.units[self.parent.sel_unit_id][ 'move_dict'].has_key(move_coord): self.unit_move_destination = move_coord self.showMoveCompass(self.unit_move_destination) def mouseLeftClickUp(self): """Handles left mouse click actions when mouse button is depressed. Used for unit movement. """ o = None if self.hovered_compass_tile != None: x = self.turn_node.getPythonTag('pos')[0] y = self.turn_node.getPythonTag('pos')[1] orientation = int(self.hovered_compass_tile.getTag('key')) if orientation == utils.HEADING_NW: o = Point2(x - 1, y + 1) elif orientation == utils.HEADING_N: o = Point2(x, y + 1) elif orientation == utils.HEADING_NE: o = Point2(x + 1, y + 1) elif orientation == utils.HEADING_W: o = Point2(x - 1, y) elif orientation == utils.HEADING_E: o = Point2(x + 1, y) elif orientation == utils.HEADING_SW: o = Point2(x - 1, y - 1) elif orientation == utils.HEADING_S: o = Point2(x, y - 1) elif orientation == utils.HEADING_SE: o = Point2(x + 1, y - 1) else: o = None self.hideMoveCompass() if o != None: ClientMsg.move(self.parent.sel_unit_id, (x, y), (o.x, o.y)) def positionTask(self, task): # If turn node is displayed, you have to cancel turning or turn to be able to pick another unit or another tile to move to if self.turn_node.getTag('show') == '1': for tile in self.turn_np_list: pos = Point3( utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5), utils.TILE_SIZE * (tile.getPythonTag('pos')[1]) + 0.5, utils.GROUND_LEVEL) pos2d = utils.pointCoordIn2d(pos) tile.setPos(pos2d) else: for unit in self.parent.render_manager.unit_renderer_dict.itervalues( ): p = utils.nodeCoordIn2d(unit.model) unit.node_2d.setPos(p) for tile in self.move_np_list: pos = Point3( utils.TILE_SIZE * (tile.getPythonTag('pos')[0] + 0.5), utils.TILE_SIZE * (tile.getPythonTag('pos')[1] + 0.5), utils.GROUND_LEVEL) pos2d = utils.pointCoordIn2d(pos) tile.setPos(pos2d) return task.cont def pickerTask(self, task): if self.parent._anim_in_process: self.hovered_unit_id = None self.hovered_tile = None self.hovered_compass_tile = None return task.cont if self.parent.interface.hovered_gui != None: if self.hovered_unit_id != None: self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() return task.cont min_distance = 0.5 min_unit_id = None min_tile = None min_compass_tile = None if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() r2d = Point3(mpos.getX(), 0, mpos.getY()) a2d = aspect2d.getRelativePoint(render2d, r2d) self.mouse_node.setPos(a2d) # At the end of all this we have: # - min_distance to a unit or a movement node, IF this distance is lower than 0.5 which is set at the beginning # - min_unit_id - ID of unit which is closest to the mouse, or None if there is a movement tile closer, or if everything is further than 0.5 # - min_tile - nodepath of the movement tile closest to the mouse, or None if there is a unit closer, or if evertythin is further than 0.5 if self.turn_node.getTag('show') == '1': # Get 2d coordinates for every compass node for tile in self.turn_np_list: # We cannot do nodepath.getDistance() because tiles are reparented to self.turn_node and are in different coord space than mouse node # So we do simple vector math to get distance d = Vec3(self.mouse_node.getPos() - tile.getPos()).length() if d < min_distance: min_distance = d min_unit_id = None min_tile = None min_compass_tile = tile else: # Get 2d coordinates of all units for unit_id in self.parent.render_manager.unit_renderer_dict: unit = self.parent.render_manager.unit_renderer_dict[ unit_id] if self.parent.local_engine.isThisMyUnit(unit_id): # Calculate distance between every friendly unit and mouse cursor and remember closest unit d = self.mouse_node.getDistance(unit.node_2d) if d < min_distance: min_distance = d min_unit_id = unit_id else: # Calculate distance between every enemy unit and mouse cursor and remember closest unit d = self.mouse_node.getDistance(unit.node_2d) # To target enemy unit, distance has to be even smaller than needed for regular selection/movement if d < min_distance and d < 0.1: min_distance = d min_unit_id = unit_id # Get 2d coordinates for every movement node of the selected unit for tile in self.move_np_list: # We cannot do nodepath.getDistance() because tiles are reparented to self.move_node and are in different coord space than mouse node # So we do simple vector math to get distance d = Vec3(self.mouse_node.getPos() - tile.getPos()).length() if d < min_distance: min_distance = d min_unit_id = None min_tile = tile # If a unit is the closest to the mouse: # - hide movement nodes (Incubation style!) # - unmark last hovered unit # - unmark last hovered tile # - mark new hovered unit # TODO: ogs: potencijalna optimizacija da se provjeri da li je self.hovered_unit_id = min_unit_id, tada ne treba unmark+mark if min_compass_tile != None: if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None if min_compass_tile != self.hovered_compass_tile: if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() min_compass_tile.setColor(1, 0, 0) s1 = Sequence( LerpColorInterval(min_compass_tile, 0.5, (1, 1, 0, 1)), LerpColorInterval(min_compass_tile, 0.5, (1, 0, 0, 1))) s2 = Sequence(LerpScaleInterval(min_compass_tile, 0.5, (0.1)), LerpScaleInterval(min_compass_tile, 0.5, (0.05))) self.color_scale_parallel = Parallel(s1, s2) self.color_scale_parallel.loop() self.hovered_compass_tile = min_compass_tile elif min_unit_id != None: self.move_node.detachNode() if min_unit_id != self.hovered_unit_id and self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.parent.render_manager.unit_marker_renderer.markHovered( min_unit_id) if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None self.hovered_unit_id = min_unit_id # If a movement tile is closest to the mouse: # - unmark last hovered unit # - unmark last marked tile # - show movement nodes (Incubation style!) # - mark new hovered tile elif min_tile != None: if self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if min_tile != self.hovered_tile: self.move_node.reparentTo(aspect2d) if self.hovered_tile != None and not self.hovered_tile.isEmpty( ): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() min_tile.setColor(1, 0, 0) s1 = Sequence(LerpColorInterval(min_tile, 0.5, (1, 1, 0, 1)), LerpColorInterval(min_tile, 0.5, (1, 0, 0, 1))) s2 = Sequence(LerpScaleInterval(min_tile, 0.5, (0.1)), LerpScaleInterval(min_tile, 0.5, (0.05))) self.color_scale_parallel = Parallel(s1, s2) self.color_scale_parallel.loop() self.hovered_tile = min_tile # If neither any of the units nor any of the movement tiles is closer than 0.5: # - unmark last hovered unit # - unmark last hovered tile else: if self.hovered_unit_id != None: if self.parent.render_manager.unit_renderer_dict.has_key( int(self.hovered_unit_id)): self.parent.render_manager.unit_marker_renderer.unmarkHovered( self.hovered_unit_id) self.hovered_unit_id = None if self.hovered_tile != None and not self.hovered_tile.isEmpty(): self.hovered_tile.setColor(1, 1, 1) self.hovered_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_tile = None if self.hovered_compass_tile != None and not self.hovered_compass_tile.isEmpty( ): self.hovered_compass_tile.setColor(1, 1, 1) self.hovered_compass_tile.setScale(0.05) self.color_scale_parallel.pause() self.hovered_compass_tile = None return task.cont