class DistCogdoGame(DistCogdoGameBase, DistributedObject): notify = directNotify.newCategory('DistCogdoGame') def __init__(self, cr): DistributedObject.__init__(self, cr) base.cogdoGame = self cr.cogdoGame = self self._waitingStartLabel = DirectLabel(text=TTL.MinigameWaitingForOtherPlayers, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075) self._waitingStartLabel.hide() self.loadFSM = ClassicFSM.ClassicFSM('DistCogdoGame.loaded', [State.State('NotLoaded', self.enterNotLoaded, self.exitNotLoaded, ['Loaded']), State.State('Loaded', self.enterLoaded, self.exitLoaded, ['NotLoaded'])], 'NotLoaded', 'NotLoaded') self.loadFSM.enterInitialState() self.fsm = ClassicFSM.ClassicFSM('DistCogdoGame', [State.State('Visible', self.enterVisible, self.exitVisible, ['Intro']), State.State('Intro', self.enterIntro, self.exitIntro, ['WaitServerStart']), State.State('WaitServerStart', self.enterWaitServerStart, self.exitWaitServerStart, ['Game']), State.State('Game', self.enterGame, self.exitGame, ['Finish']), State.State('Finish', self.enterFinish, self.exitFinish, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Visible'])], 'Off', 'Off') self.fsm.enterInitialState() self.difficultyOverride = None self.exteriorZoneOverride = None self._gotInterior = StateVar(False) self._toonsInEntranceElev = StateVar(False) self._wantStashElevator = StateVar(False) self._stashElevatorFC = FunctionCall(self._doStashElevator, self._toonsInEntranceElev, self._gotInterior, self._wantStashElevator) def getTitle(self): pass def getInstructions(self): pass def setInteriorId(self, interiorId): self._interiorId = interiorId def setExteriorZone(self, exteriorZone): self.exteriorZone = exteriorZone def setDifficultyOverrides(self, difficultyOverride, exteriorZoneOverride): if difficultyOverride != CogdoGameConsts.NoDifficultyOverride: self.difficultyOverride = difficultyOverride / float(CogdoGameConsts.DifficultyOverrideMult) if exteriorZoneOverride != CogdoGameConsts.NoExteriorZoneOverride: self.exteriorZoneOverride = exteriorZoneOverride def getInterior(self): return self.cr.getDo(self._interiorId) def getEntranceElevator(self, callback): return self.getInterior().getEntranceElevator(callback) def getToonIds(self): interior = self.getInterior() if interior is not None: return interior.getToonIds() else: return [] def getToon(self, toonId): if self.cr.doId2do.has_key(toonId): return self.cr.doId2do[toonId] else: return None def getNumPlayers(self): return len(self.getToonIds()) def isSinglePlayer(self): if self.getNumPlayers() == 1: return 1 else: return 0 def announceGenerate(self): DistributedObject.announceGenerate(self) self.loadFSM.request('Loaded') self._requestInterior() self.notify.info('difficulty: %s, safezoneId: %s' % (self.getDifficulty(), self.getSafezoneId())) def _requestInterior(self): self.cr.relatedObjectMgr.requestObjects([self._interiorId], allCallback=self._handleGotInterior) def _handleGotInterior(self, objs): self._gotInterior.set(True) self.getEntranceElevator(self.placeEntranceElev) def stashEntranceElevator(self): self._wantStashElevator.set(True) def placeEntranceElev(self, elev): pass def _doStashElevator(self, toonsInEntranceElev, gotInterior, wantStashElevator): if gotInterior: interior = self.getInterior() if interior: if not toonsInEntranceElev and wantStashElevator: interior.stashElevatorIn() else: interior.stashElevatorIn(False) def disable(self): base.cogdoGame = None self.cr.cogdoGame = None self.fsm.requestFinalState() self.loadFSM.requestFinalState() self.fsm = None self.loadFSM = None DistributedObject.disable(self) def delete(self): self._stashElevatorFC.destroy() self._wantStashElevator.destroy() self._toonsInEntranceElev.destroy() self._gotInterior.destroy() self._waitingStartLabel.destroy() self._waitingStartLabel = None DistributedObject.delete(self) def getDifficulty(self): if self.difficultyOverride is not None: return self.difficultyOverride if hasattr(base, 'cogdoGameDifficulty'): return float(base.cogdoGameDifficulty) return CogdoGameConsts.getDifficulty(self.getSafezoneId()) def getSafezoneId(self): if self.exteriorZoneOverride is not None: return self.exteriorZoneOverride if hasattr(base, 'cogdoGameSafezoneId'): return CogdoGameConsts.getSafezoneId(base.cogdoGameSafezoneId) return CogdoGameConsts.getSafezoneId(self.exteriorZone) def enterNotLoaded(self): pass def exitNotLoaded(self): pass def enterLoaded(self): pass def exitLoaded(self): pass def enterOff(self): pass def exitOff(self): pass def setVisible(self): self.fsm.request('Visible') def setIntroStart(self): self.fsm.request('Intro') def enterVisible(self): self._toonsInEntranceElev.set(True) def exitVisible(self): pass def enterIntro(self, duration = MinigameGlobals.rulesDuration): base.cr.playGame.getPlace().fsm.request('Game') self._rulesDoneEvent = self.uniqueName('cogdoGameRulesDone') self.accept(self._rulesDoneEvent, self._handleRulesDone) self._rulesPanel = CogdoGameRulesPanel('CogdoGameRulesPanel', self.getTitle(), '', self._rulesDoneEvent, timeout=duration) self._rulesPanel.load() self._rulesPanel.enter() def exitIntro(self): self._toonsInEntranceElev.set(False) self.ignore(self._rulesDoneEvent) if self._rulesPanel: self._rulesPanel.exit() self._rulesPanel.unload() self._rulesPanel = None def _handleRulesDone(self): self.ignore(self._rulesDoneEvent) self._rulesPanel.exit() self._rulesPanel.unload() self._rulesPanel = None self.fsm.request('WaitServerStart') self.d_setAvatarReady() def d_setAvatarReady(self): self.sendUpdate('setAvatarReady', []) def enterWaitServerStart(self): numToons = 1 interior = self.getInterior() if interior: numToons = len(interior.getToonIds()) if numToons > 1: msg = TTL.MinigameWaitingForOtherPlayers else: msg = TTL.MinigamePleaseWait self._waitingStartLabel['text'] = msg self._waitingStartLabel.show() def exitWaitServerStart(self): self._waitingStartLabel.hide() def setGameStart(self, timestamp): self._startTime = globalClockDelta.networkToLocalTime(timestamp) self.fsm.request('Game') def getStartTime(self): return self._startTime def enterGame(self): if SCHELLGAMES_DEV: self.acceptOnce('escape', messenger.send, ['magicWord', ['~endMaze']]) def exitGame(self): if SCHELLGAMES_DEV: self.ignore('escape') def setGameFinish(self, timestamp): self._finishTime = globalClockDelta.networkToLocalTime(timestamp) self.fsm.request('Finish') def getFinishTime(self): return self._finishTime def enterFinish(self): pass def exitFinish(self): pass def setToonSad(self, toonId): pass def setToonDisconnect(self, toonId): pass
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity): notify = directNotify.newCategory('DistributedPartyTugOfWarActivity') def __init__(self, cr): DistributedPartyTeamActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTugOfWar, startDelay=PartyGlobals.TugOfWarStartDelay) self.buttons = [0, 1] self.arrowKeys = None self.keyTTL = [] self.idealRate = 0.0 self.keyRate = 0 self.allOutMode = False self.rateMatchAward = 0.0 self.toonIdsToStartPositions = {} self.toonIdsToIsPullingFlags = {} self.toonIdsToRightHands = {} self.fallenToons = [] self.fallenPositions = [] self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.toonIdsToAnimIntervals = {} self.tugRopes = [] return def generate(self): DistributedPartyTeamActivity.generate(self) self._hopOffFinishedSV = StateVar(True) self._rewardFinishedSV = StateVar(True) self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady, self._hopOffFinishedSV, self._rewardFinishedSV) def delete(self): self._isWalkStateReadyFC.destroy() self._hopOffFinishedSV.destroy() self._rewardFinishedSV.destroy() DistributedPartyTeamActivity.delete(self) def handleToonJoined(self, toonId): DistributedPartyTeamActivity.handleToonJoined(self, toonId) self.toonIdsToAnimIntervals[toonId] = None if toonId == base.localAvatar.doId: base.cr.playGame.getPlace().fsm.request('activity') camera.wrtReparentTo(self.root) self.cameraMoveIval = LerpPosHprInterval(camera, 1.5, PartyGlobals.TugOfWarCameraPos, PartyGlobals.TugOfWarCameraInitialHpr, other=self.root) self.cameraMoveIval.start() self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) self.notify.debug('posIndex: %d' % self.localToonPosIndex) toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex] if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ: toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ) targetH = fitDestAngle2Src(toon.getH(self.root), PartyGlobals.TugOfWarHeadings[self.localToonTeam]) travelVector = targetPos - toon.getPos(self.root) duration = travelVector.length() / 5.0 if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() self.toonIdsToAnimIntervals[toonId] = Sequence(Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), LerpPosHprInterval(toon, duration, targetPos, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral')) self.toonIdsToAnimIntervals[toonId].start() return def handleToonExited(self, toonId): DistributedPartyTeamActivity.handleToonExited(self, toonId) if toonId == base.localAvatar.doId: self.cameraMoveIval.pause() if toonId not in self.fallenToons: if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) targetH = fitDestAngle2Src(toon.getH(self.root), 180.0) targetPos = self.hopOffPositions[self.getTeam(toonId)][self.getIndex(toonId, self.getTeam(toonId))] hopOffAnim = Sequence(Func(toon.startPosHprBroadcast, 0.1), toon.hprInterval(0.2, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0, self.root), Func(toon.stopPosHprBroadcast), Func(toon.sendCurrentPosition), Func(self.hopOffFinished, toonId)) self.toonIdsToAnimIntervals[toonId] = hopOffAnim self._hopOffFinishedSV.set(False) self.toonIdsToAnimIntervals[toonId].start() else: self._hopOffFinishedSV.set(True) del self.toonIdsToAnimIntervals[toonId] return def handleRewardDone(self): self._rewardFinishedSV.set(True) def _testWalkStateReady(self, hoppedOff, rewardFinished): if hoppedOff and rewardFinished: DistributedPartyTeamActivity.handleRewardDone(self) def hopOffFinished(self, toonId): if hasattr(self, 'toonIdsToAnimIntervals') and toonId in self.toonIdsToAnimIntervals: del self.toonIdsToAnimIntervals[toonId] if toonId == base.localAvatar.doId: if hasattr(self._hopOffFinishedSV, '_value'): self._hopOffFinishedSV.set(True) def handleToonShifted(self, toonId): if toonId == base.localAvatar.doId: self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex] self.toonIdsToAnimIntervals[toonId] = Sequence(Wait(0.6), Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), toon.posInterval(0.5, targetPos, other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral')) self.toonIdsToAnimIntervals[toonId].start() return def handleToonDisabled(self, toonId): if self.toonIdsToAnimIntervals.has_key(toonId): if self.toonIdsToAnimIntervals[toonId]: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() else: self.notify.debug('self.toonIdsToAnimIntervals[%d] is none' % toonId) def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds): DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds) self.toonIdsToRightHands.clear() for toonId in self.getToonIdsAsList(): toon = self.getAvatar(toonId) if toon: self.toonIdsToRightHands[toonId] = toon.getRightHands()[0] def load(self): DistributedPartyTeamActivity.load(self) self.loadModels() self.loadGuiElements() self.loadSounds() self.loadIntervals() self.arrowKeys = ArrowKeys() def loadModels(self): self.playArea = loader.loadModel('phase_13/models/parties/partyTugOfWar') self.playArea.reparentTo(self.root) self.sign.reparentTo(self.playArea.find('**/TugOfWar_sign_locator')) self.dockPositions = [[], []] for i in xrange(4): self.dockPositions[0].append(Point3(-PartyGlobals.TugOfWarInitialToonPositionsXOffset - PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ)) for i in xrange(4): self.dockPositions[1].append(Point3(PartyGlobals.TugOfWarInitialToonPositionsXOffset + PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ)) self.hopOffPositions = [[], []] for i in xrange(1, 5): self.hopOffPositions[PartyGlobals.TeamActivityTeams.LeftTeam].append(self.playArea.find('**/leftTeamHopOff%d_locator' % i).getPos()) self.hopOffPositions[PartyGlobals.TeamActivityTeams.RightTeam].append(self.playArea.find('**/rightTeamHopOff%d_locator' % i).getPos()) for i in xrange(1, 5): pos = self.playArea.find('**/fallenToon%d_locator' % i).getPos() self.fallenPositions.append(pos) self.joinCollision = [] self.joinCollisionNodePaths = [] for i in xrange(len(PartyGlobals.TeamActivityTeams)): collShape = CollisionTube(PartyGlobals.TugOfWarJoinCollisionEndPoints[0], PartyGlobals.TugOfWarJoinCollisionEndPoints[1], PartyGlobals.TugOfWarJoinCollisionRadius) collShape.setTangible(True) self.joinCollision.append(CollisionNode('TugOfWarJoinCollision%d' % i)) self.joinCollision[i].addSolid(collShape) tubeNp = self.playArea.attachNewNode(self.joinCollision[i]) tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask) self.joinCollisionNodePaths.append(tubeNp) self.joinCollisionNodePaths[i].setPos(PartyGlobals.TugOfWarJoinCollisionPositions[i]) self.__enableCollisions() ropeModel = loader.loadModel('phase_4/models/minigames/tug_of_war_rope') self.ropeTexture = ropeModel.findTexture('*') ropeModel.removeNode() for i in xrange(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1): rope = Rope(self.uniqueName('TugRope%d' % i)) if rope.showRope: rope.ropeNode.setRenderMode(RopeNode.RMBillboard) rope.ropeNode.setThickness(0.2) rope.setTexture(self.ropeTexture) rope.ropeNode.setUvMode(RopeNode.UVDistance) rope.ropeNode.setUvDirection(1) rope.setTransparency(1) rope.setColor(0.89, 0.89, 0.6, 1.0) rope.reparentTo(self.root) rope.stash() self.tugRopes.append(rope) self.splash = Splash.Splash(self.root) self.splash.setScale(2.0, 4.0, 1.0) pos = self.fallenPositions[0] self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset) self.splash.hide() def loadGuiElements(self): self.powerMeter = MinigamePowerMeter(PartyGlobals.TugOfWarPowerMeterSize) self.powerMeter.reparentTo(aspect2d) self.powerMeter.setPos(0.0, 0.0, 0.6) self.powerMeter.hide() self.arrows = [None] * 2 for x in xrange(len(self.arrows)): self.arrows[x] = loader.loadModel('phase_3/models/props/arrow') self.arrows[x].reparentTo(self.powerMeter) self.arrows[x].setScale(0.2 - 0.4 * x, 0.2, 0.2) self.arrows[x].setPos(0.12 - 0.24 * x, 0, -.26) return def loadSounds(self): self.splashSound = base.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg') self.whistleSound = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg') def loadIntervals(self): self.updateIdealRateInterval = Sequence() self.updateIdealRateInterval.append(Wait(PartyGlobals.TugOfWarTargetRateList[0][0])) for i in xrange(1, len(PartyGlobals.TugOfWarTargetRateList)): duration = PartyGlobals.TugOfWarTargetRateList[i][0] idealRate = PartyGlobals.TugOfWarTargetRateList[i][1] self.updateIdealRateInterval.append(Func(self.setIdealRate, idealRate)) if i == len(PartyGlobals.TugOfWarTargetRateList) - 1: self.updateIdealRateInterval.append(Func(setattr, self, 'allOutMode', True)) else: self.updateIdealRateInterval.append(Wait(duration)) self.updateKeyPressRateInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressUpdateRate), Func(self.updateKeyPressRate)) self.reportToServerInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressReportRate), Func(self.reportToServer)) self.setupInterval = Parallel() self.globalSetupInterval = Sequence(Wait(PartyGlobals.TugOfWarReadyDuration + PartyGlobals.TugOfWarGoDuration), Func(self.tightenRopes)) self.localSetupInterval = Sequence(Func(self.setStatus, TTLocalizer.PartyTugOfWarReady), Func(self.showStatus), Wait(PartyGlobals.TugOfWarReadyDuration), Func(base.playSfx, self.whistleSound), Func(self.setStatus, TTLocalizer.PartyTugOfWarGo), Wait(PartyGlobals.TugOfWarGoDuration), Func(self.enableKeys), Func(self.hideStatus), Func(self.updateIdealRateInterval.start), Func(self.updateKeyPressRateInterval.loop), Func(self.reportToServerInterval.loop)) self.splashInterval = Sequence(Func(base.playSfx, self.splashSound), Func(self.splash.play)) def unload(self): DistributedPartyTeamActivity.unload(self) self.arrowKeys.destroy() self.unloadIntervals() self.unloadModels() self.unloadGuiElements() self.unloadSounds() if hasattr(self, 'toonIds'): del self.toonIds del self.buttons del self.arrowKeys del self.keyTTL del self.idealRate del self.keyRate del self.allOutMode del self.rateMatchAward del self.toonIdsToStartPositions del self.toonIdsToIsPullingFlags del self.toonIdsToRightHands del self.fallenToons del self.fallenPositions del self.unusedFallenPositionsIndices self.toonIdsToAnimIntervals.clear() del self.toonIdsToAnimIntervals def unloadModels(self): self.playArea.removeNode() del self.playArea del self.dockPositions del self.hopOffPositions self.__disableCollisions() while len(self.joinCollision) > 0: collNode = self.joinCollision.pop() del collNode while len(self.joinCollisionNodePaths) > 0: collNodePath = self.joinCollisionNodePaths.pop() collNodePath.removeNode() del collNodePath while len(self.tugRopes) > 0: rope = self.tugRopes.pop() if rope is not None: rope.removeNode() del rope del self.tugRopes self.splash.destroy() del self.splash return def unloadGuiElements(self): for arrow in self.arrows: if arrow is not None: arrow.removeNode() del arrow del self.arrows if self.powerMeter is not None: self.powerMeter.cleanup() del self.powerMeter return def unloadSounds(self): del self.splashSound del self.whistleSound def unloadIntervals(self): self.updateIdealRateInterval.pause() del self.updateIdealRateInterval self.updateKeyPressRateInterval.pause() del self.updateKeyPressRateInterval self.reportToServerInterval.pause() del self.reportToServerInterval self.setupInterval.pause() del self.setupInterval self.globalSetupInterval.pause() del self.globalSetupInterval self.localSetupInterval.pause() del self.localSetupInterval self.splashInterval.pause() del self.splashInterval def __enableCollisions(self): for i in xrange(len(PartyGlobals.TeamActivityTeams)): self.accept('enterTugOfWarJoinCollision%d' % i, getattr(self, '_join%s' % PartyGlobals.TeamActivityTeams.getString(i))) def __disableCollisions(self): for i in xrange(len(PartyGlobals.TeamActivityTeams)): self.ignore('enterTugOfWarJoinCollision%d' % i) def startWaitForEnough(self): DistributedPartyTeamActivity.startWaitForEnough(self) self.__enableCollisions() def finishWaitForEnough(self): DistributedPartyTeamActivity.finishWaitForEnough(self) self.__disableCollisions() def startWaitToStart(self, waitStartTimestamp): DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp) self.__enableCollisions() def finishWaitToStart(self): DistributedPartyTeamActivity.finishWaitToStart(self) self.__disableCollisions() def startRules(self): DistributedPartyTeamActivity.startRules(self) self.setUpRopes() if self.isLocalToonPlaying: self.showControls() def finishRules(self): DistributedPartyTeamActivity.finishRules(self) if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough': self.hideRopes() self.hideControls() def finishWaitForServer(self): DistributedPartyTeamActivity.finishWaitForServer(self) if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough': self.hideRopes() self.hideControls() def startActive(self): DistributedPartyTeamActivity.startActive(self) self.toonIdsToStartPositions.clear() self.toonIdsToIsPullingFlags.clear() for toonId in self.getToonIdsAsList(): self.toonIdsToIsPullingFlags[toonId] = False toon = self.getAvatar(toonId) if toon: self.toonIdsToStartPositions[toonId] = toon.getPos(self.root) else: self.notify.warning("couldn't find toon %d assigning 0,0,0 to startPos" % toonId) self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0) self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.setupInterval = Parallel(self.globalSetupInterval) if self.isLocalToonPlaying: self.keyTTL = [] self.idealForce = 0.0 self.keyRate = 0 self.rateMatchAward = 0.0 self.allOutMode = False self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1]) self.setupInterval.append(self.localSetupInterval) self.setupInterval.start() def finishActive(self): DistributedPartyTeamActivity.finishActive(self) self.hideControls() self.disableKeys() self.setupInterval.pause() self.reportToServerInterval.pause() self.updateKeyPressRateInterval.pause() self.updateIdealRateInterval.pause() self.hideRopes() def startConclusion(self, losingTeam): DistributedPartyTeamActivity.startConclusion(self, losingTeam) if self.isLocalToonPlaying: self._rewardFinishedSV.set(False) if losingTeam == PartyGlobals.TeamActivityNeitherTeam: self.setStatus(TTLocalizer.PartyTeamActivityGameTie) else: self.setStatus(TTLocalizer.PartyTugOfWarGameEnd) self.showStatus() if losingTeam == PartyGlobals.TeamActivityNeitherTeam: for toonId in self.getToonIdsAsList(): if self.getAvatar(toonId): self.getAvatar(toonId).loop('neutral') else: for toonId in self.toonIds[losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop('neutral') for toonId in self.toonIds[1 - losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop('victory') for ival in self.toonIdsToAnimIntervals.values(): if ival is not None: ival.finish() return def finishConclusion(self): DistributedPartyTeamActivity.finishConclusion(self) self.fallenToons = [] def getTitle(self): return TTLocalizer.PartyTugOfWarTitle def getInstructions(self): return TTLocalizer.TugOfWarInstructions def showControls(self): for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor) self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) self.powerMeter.clearTooSlowTooFast() self.powerMeter.show() def hideControls(self): self.powerMeter.hide() def setUpRopes(self): self.notify.debug('setUpRopes') ropeIndex = 0 leftToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]: leftToonId = self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0] rightToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]: rightToonId = self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0] if leftToonId in self.toonIdsToRightHands and rightToonId in self.toonIdsToRightHands: self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[leftToonId], (0, 0, 0)), (self.root, (0.0, 0.0, 2.5)), (self.toonIdsToRightHands[rightToonId], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 teams = [PartyGlobals.TeamActivityTeams.LeftTeam, PartyGlobals.TeamActivityTeams.RightTeam] for currTeam in teams: numToons = len(self.toonIds[currTeam]) if numToons > 1: for i in xrange(numToons - 1, 0, -1): toon1 = self.toonIds[currTeam][i] toon2 = self.toonIds[currTeam][i - 1] if not self.toonIdsToRightHands.has_key(toon1): self.notify.warning('Toon in tug of war activity but not properly setup: %s' % toon1) elif not self.toonIdsToRightHands.has_key(toon2): self.notify.warning('Toon in tug of war activity but not properly setup: %s' % toon2) else: self.notify.debug('Connecting rope between toon %d and toon %d of team %d.' % (i, i - 1, currTeam)) self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon2], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 def tightenRopes(self): self.notify.debug('tightenRopes') self.tugRopes[0].setup(3, ((self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) def hideRopes(self): self.notify.debug('hideRopes') for rope in self.tugRopes: rope.stash() def handleGameTimerExpired(self): self.disableKeys() def setIdealRate(self, idealRate): self.notify.debug('setIdealRate( %d )' % idealRate) self.idealRate = idealRate self.idealForce = self.advantage * (4 + 0.4 * self.idealRate) def updateKeyPressRate(self): for i in xrange(len(self.keyTTL)): self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate for i in xrange(len(self.keyTTL)): if self.keyTTL[i] <= 0.0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1: self.rateMatchAward += 0.3 else: self.rateMatchAward = 0.0 def reportToServer(self): self.currentForce = self.computeForce(self.keyRate) self.sendUpdate('reportKeyRateForce', [self.keyRate, self.currentForce]) self.setSpeedGauge() self.setAnimState(base.localAvatar.doId, self.keyRate) def computeForce(self, keyRate): F = 0 if self.allOutMode: F = 0.75 * keyRate else: stdDev = 0.25 * self.idealRate F = self.advantage * (self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow(math.e, -math.pow(keyRate - self.idealRate, 2) / (2.0 * math.pow(stdDev, 2))) return F def setSpeedGauge(self): self.powerMeter.setPower(self.keyRate) self.powerMeter.setTarget(self.idealRate) if not self.allOutMode: self.powerMeter.updateTooSlowTooFast() index = float(self.currentForce) / self.idealForce bonus = 0.0 if index > 1.0: bonus = max(1.0, index - 1.0) index = 1.0 color = (0, 0.75 * index + 0.25 * bonus, 0.75 * (1 - index), 0.5) self.powerMeter.setBarColor(color) else: self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) def updateToonKeyRate(self, toonId, keyRate): if toonId != base.localAvatar.doId: self.setAnimState(toonId, keyRate) def setAnimState(self, toonId, keyRate): if self.activityFSM.state != 'Active': return toon = self.getAvatar(toonId) if not self.toonIdsToIsPullingFlags.has_key(toonId): if self.getTeam(toonId) == None: self.notify.warning("setAnimState called with toonId (%d) that wasn't in self.toonIds" % toonId) return else: self.notify.warning('setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it.' % toonId) self.toonIdsToIsPullingFlags[toonId] = False if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]: if toon: toon.loop('tug-o-war') else: self.notify.warning('toon %d is None, skipping toon.loop(tugowar)' % toonId) self.toonIdsToIsPullingFlags[toonId] = True if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]: if toon: toon.pose('tug-o-war', 3) toon.startLookAround() else: self.notify.warning('toon %d is None, skipping toon.startLookAround' % toonId) self.toonIdsToIsPullingFlags[toonId] = False return def enableKeys(self): self.notify.debug('enableKeys') self.arrowKeys.setPressHandlers([lambda : self.__pressHandler(2), lambda : self.__pressHandler(3), lambda : self.__pressHandler(1), lambda : self.__pressHandler(0)]) self.arrowKeys.setReleaseHandlers([lambda : self.__releaseHandler(2), lambda : self.__releaseHandler(3), lambda : self.__releaseHandler(1), lambda : self.__releaseHandler(0)]) for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor) def disableKeys(self): self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS) self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS) def __pressHandler(self, index): if index == self.buttons[0]: self.arrows[index].setColor(PartyGlobals.TugOfWarHilightedArrowColor) self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive) self.buttons.reverse() def __releaseHandler(self, index): if index in self.buttons: self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor) def updateToonPositions(self, offset): if self.activityFSM.state != 'Active': return if self.isLocalToonPlaying: camera.lookAt(self.root, offset, 0.0, PartyGlobals.TugOfWarCameraLookAtHeightOffset) for toonId in self.getToonIdsAsList(): if hasattr(self, 'fallenToons') and toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon is not None: origPos = self.toonIdsToStartPositions[toonId] curPos = toon.getPos(self.root) newPos = Point3(origPos[0] + offset, curPos[1], curPos[2]) if self.toonIdsToAnimIntervals[toonId] != None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() self.checkIfFallen(toonId) if toonId not in self.fallenToons: self.toonIdsToAnimIntervals[toonId] = Sequence(LerpPosInterval(toon, duration=PartyGlobals.TugOfWarKeyPressReportRate, pos=newPos, other=self.root), Func(self.checkIfFallen, toonId)) self.toonIdsToAnimIntervals[toonId].start() return def checkIfFallen(self, toonId): if hasattr(self, 'fallenToons') and toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon: curPos = toon.getPos(self.root) team = self.getTeam(toonId) if team == PartyGlobals.TeamActivityTeams.LeftTeam and curPos[0] > -2.0 or team == PartyGlobals.TeamActivityTeams.RightTeam and curPos[0] < 2.0: losingTeam = self.getTeam(toonId) self.throwTeamInWater(losingTeam) self.sendUpdate('reportFallIn', [losingTeam]) def throwTeamInWater(self, losingTeam): self.notify.debug('throwTeamInWater( %s )' % PartyGlobals.TeamActivityTeams.getString(losingTeam)) splashSet = False for toonId in self.toonIds[losingTeam]: self.fallenToons.append(toonId) toon = self.getAvatar(toonId) fallenPosIndex = self.toonIds[losingTeam].index(toonId) if fallenPosIndex < 0 or fallenPosIndex >= 4: fallenPosIndex = 0 newPos = self.fallenPositions[fallenPosIndex] if self.toonIdsToAnimIntervals.has_key(toonId) and self.toonIdsToAnimIntervals[toonId] is not None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() if toon: parallel = Parallel(ActorInterval(actor=toon, animName='slip-forward', duration=2.0), LerpPosInterval(toon, duration=2.0, pos=newPos, other=self.root)) else: self.notify.warning('toon %d is none, skipping slip-forward' % toonId) parallel = Parallel() if not splashSet: splashSet = True parallel.append(self.splashInterval) if toon: self.toonIdsToAnimIntervals[toonId] = Sequence(parallel, Func(toon.loop, 'neutral')) else: self.notify.warning('toon %d is none, skipping toon.loop(neutral)' % toonId) self.toonIdsToAnimIntervals[toonId] = parallel self.toonIdsToAnimIntervals[toonId].start() return def setAdvantage(self, advantage): DistributedPartyTeamActivity.setAdvantage(self, advantage) if self.isLocalToonPlaying: self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity): notify = directNotify.newCategory('DistributedPartyTugOfWarActivity') def __init__(self, cr): DistributedPartyTeamActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTugOfWar, startDelay=PartyGlobals.TugOfWarStartDelay) self.buttons = [0, 1] self.arrowKeys = None self.keyTTL = [] self.idealRate = 0.0 self.keyRate = 0 self.allOutMode = False self.rateMatchAward = 0.0 self.toonIdsToStartPositions = {} self.toonIdsToIsPullingFlags = {} self.toonIdsToRightHands = {} self.fallenToons = [] self.fallenPositions = [] self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.toonIdsToAnimIntervals = {} self.tugRopes = [] return def generate(self): DistributedPartyTeamActivity.generate(self) self._hopOffFinishedSV = StateVar(True) self._rewardFinishedSV = StateVar(True) self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady, self._hopOffFinishedSV, self._rewardFinishedSV) def delete(self): self._isWalkStateReadyFC.destroy() self._hopOffFinishedSV.destroy() self._rewardFinishedSV.destroy() DistributedPartyTeamActivity.delete(self) def handleToonJoined(self, toonId): DistributedPartyTeamActivity.handleToonJoined(self, toonId) self.toonIdsToAnimIntervals[toonId] = None if toonId == base.localAvatar.doId: base.cr.playGame.getPlace().fsm.request('activity') camera.wrtReparentTo(self.root) self.cameraMoveIval = LerpPosHprInterval(camera, 1.5, PartyGlobals.TugOfWarCameraPos, PartyGlobals.TugOfWarCameraInitialHpr, other=self.root) self.cameraMoveIval.start() self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) self.notify.debug('posIndex: %d' % self.localToonPosIndex) toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex] if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ: toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ) targetH = fitDestAngle2Src(toon.getH(self.root), PartyGlobals.TugOfWarHeadings[self.localToonTeam]) travelVector = targetPos - toon.getPos(self.root) duration = travelVector.length() / 5.0 if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() self.toonIdsToAnimIntervals[toonId] = Sequence(Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), LerpPosHprInterval(toon, duration, targetPos, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral')) self.toonIdsToAnimIntervals[toonId].start() return def handleToonExited(self, toonId): DistributedPartyTeamActivity.handleToonExited(self, toonId) if toonId == base.localAvatar.doId: self.cameraMoveIval.pause() if toonId not in self.fallenToons: if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) targetH = fitDestAngle2Src(toon.getH(self.root), 180.0) targetPos = self.hopOffPositions[self.getTeam(toonId)][self.getIndex(toonId, self.getTeam(toonId))] hopOffAnim = Sequence(Func(toon.startPosHprBroadcast, 0.1), toon.hprInterval(0.2, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0, self.root), Func(toon.stopPosHprBroadcast), Func(toon.sendCurrentPosition), Func(self.hopOffFinished, toonId)) self.toonIdsToAnimIntervals[toonId] = hopOffAnim self._hopOffFinishedSV.set(False) self.toonIdsToAnimIntervals[toonId].start() else: self._hopOffFinishedSV.set(True) del self.toonIdsToAnimIntervals[toonId] return def handleRewardDone(self): self._rewardFinishedSV.set(True) def _testWalkStateReady(self, hoppedOff, rewardFinished): if hoppedOff and rewardFinished: DistributedPartyTeamActivity.handleRewardDone(self) def hopOffFinished(self, toonId): if hasattr(self, 'toonIdsToAnimIntervals') and toonId in self.toonIdsToAnimIntervals: del self.toonIdsToAnimIntervals[toonId] if toonId == base.localAvatar.doId: if hasattr(self._hopOffFinishedSV, '_value'): self._hopOffFinishedSV.set(True) def handleToonShifted(self, toonId): if toonId == base.localAvatar.doId: self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex] self.toonIdsToAnimIntervals[toonId] = Sequence(Wait(0.6), Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), toon.posInterval(0.5, targetPos, other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral')) self.toonIdsToAnimIntervals[toonId].start() return def handleToonDisabled(self, toonId): if toonId in self.toonIdsToAnimIntervals: if self.toonIdsToAnimIntervals[toonId]: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() else: self.notify.debug('self.toonIdsToAnimIntervals[%d] is none' % toonId) def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds): DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds) self.toonIdsToRightHands.clear() for toonId in self.getToonIdsAsList(): toon = self.getAvatar(toonId) if toon: self.toonIdsToRightHands[toonId] = toon.getRightHands()[0] def load(self): DistributedPartyTeamActivity.load(self) self.loadModels() self.loadGuiElements() self.loadSounds() self.loadIntervals() self.arrowKeys = ArrowKeys() def loadModels(self): self.playArea = loader.loadModel('phase_13/models/parties/partyTugOfWar') self.playArea.reparentTo(self.root) self.sign.reparentTo(self.playArea.find('**/TugOfWar_sign_locator')) self.dockPositions = [[], []] for i in range(4): self.dockPositions[0].append(Point3(-PartyGlobals.TugOfWarInitialToonPositionsXOffset - PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ)) for i in range(4): self.dockPositions[1].append(Point3(PartyGlobals.TugOfWarInitialToonPositionsXOffset + PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ)) self.hopOffPositions = [[], []] for i in range(1, 5): self.hopOffPositions[PartyGlobals.TeamActivityTeams.LeftTeam].append(self.playArea.find('**/leftTeamHopOff%d_locator' % i).getPos()) self.hopOffPositions[PartyGlobals.TeamActivityTeams.RightTeam].append(self.playArea.find('**/rightTeamHopOff%d_locator' % i).getPos()) for i in range(1, 5): pos = self.playArea.find('**/fallenToon%d_locator' % i).getPos() self.fallenPositions.append(pos) self.joinCollision = [] self.joinCollisionNodePaths = [] for i in range(len(PartyGlobals.TeamActivityTeams)): collShape = CollisionTube(PartyGlobals.TugOfWarJoinCollisionEndPoints[0], PartyGlobals.TugOfWarJoinCollisionEndPoints[1], PartyGlobals.TugOfWarJoinCollisionRadius) collShape.setTangible(True) self.joinCollision.append(CollisionNode('TugOfWarJoinCollision%d' % i)) self.joinCollision[i].addSolid(collShape) tubeNp = self.playArea.attachNewNode(self.joinCollision[i]) tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask) self.joinCollisionNodePaths.append(tubeNp) self.joinCollisionNodePaths[i].setPos(PartyGlobals.TugOfWarJoinCollisionPositions[i]) self.__enableCollisions() ropeModel = loader.loadModel('phase_4/models/minigames/tug_of_war_rope') self.ropeTexture = ropeModel.findTexture('*') ropeModel.removeNode() for i in range(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1): rope = Rope(self.uniqueName('TugRope%d' % i)) if rope.showRope: rope.ropeNode.setRenderMode(RopeNode.RMBillboard) rope.ropeNode.setThickness(0.2) rope.setTexture(self.ropeTexture) rope.ropeNode.setUvMode(RopeNode.UVDistance) rope.ropeNode.setUvDirection(1) rope.setTransparency(1) rope.setColor(0.89, 0.89, 0.6, 1.0) rope.reparentTo(self.root) rope.stash() self.tugRopes.append(rope) self.splash = Splash.Splash(self.root) self.splash.setScale(2.0, 4.0, 1.0) pos = self.fallenPositions[0] self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset) self.splash.hide() def loadGuiElements(self): self.powerMeter = MinigamePowerMeter(PartyGlobals.TugOfWarPowerMeterSize) self.powerMeter.reparentTo(aspect2d) self.powerMeter.setPos(0.0, 0.0, 0.6) self.powerMeter.hide() self.arrows = [None] * 2 for x in range(len(self.arrows)): self.arrows[x] = loader.loadModel('phase_3/models/props/arrow') self.arrows[x].reparentTo(self.powerMeter) self.arrows[x].setScale(0.2 - 0.4 * x, 0.2, 0.2) self.arrows[x].setPos(0.12 - 0.24 * x, 0, -.26) return def loadSounds(self): self.splashSound = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg') self.whistleSound = base.loader.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg') def loadIntervals(self): self.updateIdealRateInterval = Sequence() self.updateIdealRateInterval.append(Wait(PartyGlobals.TugOfWarTargetRateList[0][0])) for i in range(1, len(PartyGlobals.TugOfWarTargetRateList)): duration = PartyGlobals.TugOfWarTargetRateList[i][0] idealRate = PartyGlobals.TugOfWarTargetRateList[i][1] self.updateIdealRateInterval.append(Func(self.setIdealRate, idealRate)) if i == len(PartyGlobals.TugOfWarTargetRateList) - 1: self.updateIdealRateInterval.append(Func(setattr, self, 'allOutMode', True)) else: self.updateIdealRateInterval.append(Wait(duration)) self.updateKeyPressRateInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressUpdateRate), Func(self.updateKeyPressRate)) self.reportToServerInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressReportRate), Func(self.reportToServer)) self.setupInterval = Parallel() self.globalSetupInterval = Sequence(Wait(PartyGlobals.TugOfWarReadyDuration + PartyGlobals.TugOfWarGoDuration), Func(self.tightenRopes)) self.localSetupInterval = Sequence(Func(self.setStatus, TTLocalizer.PartyTugOfWarReady), Func(self.showStatus), Wait(PartyGlobals.TugOfWarReadyDuration), Func(base.playSfx, self.whistleSound), Func(self.setStatus, TTLocalizer.PartyTugOfWarGo), Wait(PartyGlobals.TugOfWarGoDuration), Func(self.enableKeys), Func(self.hideStatus), Func(self.updateIdealRateInterval.start), Func(self.updateKeyPressRateInterval.loop), Func(self.reportToServerInterval.loop)) self.splashInterval = Sequence(Func(base.playSfx, self.splashSound), Func(self.splash.play)) def unload(self): DistributedPartyTeamActivity.unload(self) self.arrowKeys.destroy() self.unloadIntervals() self.unloadModels() self.unloadGuiElements() self.unloadSounds() if hasattr(self, 'toonIds'): del self.toonIds del self.buttons del self.arrowKeys del self.keyTTL del self.idealRate del self.keyRate del self.allOutMode del self.rateMatchAward del self.toonIdsToStartPositions del self.toonIdsToIsPullingFlags del self.toonIdsToRightHands del self.fallenToons del self.fallenPositions del self.unusedFallenPositionsIndices self.toonIdsToAnimIntervals.clear() del self.toonIdsToAnimIntervals def unloadModels(self): self.playArea.removeNode() del self.playArea del self.dockPositions del self.hopOffPositions self.__disableCollisions() while len(self.joinCollision) > 0: collNode = self.joinCollision.pop() del collNode while len(self.joinCollisionNodePaths) > 0: collNodePath = self.joinCollisionNodePaths.pop() collNodePath.removeNode() del collNodePath while len(self.tugRopes) > 0: rope = self.tugRopes.pop() if rope is not None: rope.removeNode() del rope del self.tugRopes self.splash.destroy() del self.splash return def unloadGuiElements(self): for arrow in self.arrows: if arrow is not None: arrow.removeNode() del arrow del self.arrows if self.powerMeter is not None: self.powerMeter.cleanup() del self.powerMeter return def unloadSounds(self): del self.splashSound del self.whistleSound def unloadIntervals(self): self.updateIdealRateInterval.pause() del self.updateIdealRateInterval self.updateKeyPressRateInterval.pause() del self.updateKeyPressRateInterval self.reportToServerInterval.pause() del self.reportToServerInterval self.setupInterval.pause() del self.setupInterval self.globalSetupInterval.pause() del self.globalSetupInterval self.localSetupInterval.pause() del self.localSetupInterval self.splashInterval.pause() del self.splashInterval def __enableCollisions(self): for i in range(len(PartyGlobals.TeamActivityTeams)): self.accept('enterTugOfWarJoinCollision%d' % i, getattr(self, '_join%s' % PartyGlobals.TeamActivityTeams.getString(i))) def __disableCollisions(self): for i in range(len(PartyGlobals.TeamActivityTeams)): self.ignore('enterTugOfWarJoinCollision%d' % i) def startWaitForEnough(self): DistributedPartyTeamActivity.startWaitForEnough(self) self.__enableCollisions() def finishWaitForEnough(self): DistributedPartyTeamActivity.finishWaitForEnough(self) self.__disableCollisions() def startWaitToStart(self, waitStartTimestamp): DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp) self.__enableCollisions() def finishWaitToStart(self): DistributedPartyTeamActivity.finishWaitToStart(self) self.__disableCollisions() def startRules(self): DistributedPartyTeamActivity.startRules(self) self.setUpRopes() if self.isLocalToonPlaying: self.showControls() def finishRules(self): DistributedPartyTeamActivity.finishRules(self) if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough': self.hideRopes() self.hideControls() def finishWaitForServer(self): DistributedPartyTeamActivity.finishWaitForServer(self) if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough': self.hideRopes() self.hideControls() def startActive(self): DistributedPartyTeamActivity.startActive(self) self.toonIdsToStartPositions.clear() self.toonIdsToIsPullingFlags.clear() for toonId in self.getToonIdsAsList(): self.toonIdsToIsPullingFlags[toonId] = False toon = self.getAvatar(toonId) if toon: self.toonIdsToStartPositions[toonId] = toon.getPos(self.root) else: self.notify.warning("couldn't find toon %d assigning 0,0,0 to startPos" % toonId) self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0) self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.setupInterval = Parallel(self.globalSetupInterval) if self.isLocalToonPlaying: self.keyTTL = [] self.idealForce = 0.0 self.keyRate = 0 self.rateMatchAward = 0.0 self.allOutMode = False self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1]) self.setupInterval.append(self.localSetupInterval) self.setupInterval.start() def finishActive(self): DistributedPartyTeamActivity.finishActive(self) self.hideControls() self.disableKeys() self.setupInterval.pause() self.reportToServerInterval.pause() self.updateKeyPressRateInterval.pause() self.updateIdealRateInterval.pause() self.hideRopes() def startConclusion(self, losingTeam): DistributedPartyTeamActivity.startConclusion(self, losingTeam) if self.isLocalToonPlaying: self._rewardFinishedSV.set(False) if losingTeam == PartyGlobals.TeamActivityNeitherTeam: self.setStatus(TTLocalizer.PartyTeamActivityGameTie) else: self.setStatus(TTLocalizer.PartyTugOfWarGameEnd) self.showStatus() if losingTeam == PartyGlobals.TeamActivityNeitherTeam: for toonId in self.getToonIdsAsList(): if self.getAvatar(toonId): self.getAvatar(toonId).loop('neutral') else: for toonId in self.toonIds[losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop('neutral') for toonId in self.toonIds[1 - losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop('victory') for ival in list(self.toonIdsToAnimIntervals.values()): if ival is not None: ival.finish() return def finishConclusion(self): DistributedPartyTeamActivity.finishConclusion(self) self.fallenToons = [] def getTitle(self): return TTLocalizer.PartyTugOfWarTitle def getInstructions(self): return TTLocalizer.TugOfWarInstructions def showControls(self): for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor) self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) self.powerMeter.clearTooSlowTooFast() self.powerMeter.show() def hideControls(self): self.powerMeter.hide() def setUpRopes(self): self.notify.debug('setUpRopes') ropeIndex = 0 leftToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]: leftToonId = self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0] rightToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]: rightToonId = self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0] if leftToonId in self.toonIdsToRightHands and rightToonId in self.toonIdsToRightHands: self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[leftToonId], (0, 0, 0)), (self.root, (0.0, 0.0, 2.5)), (self.toonIdsToRightHands[rightToonId], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 teams = [PartyGlobals.TeamActivityTeams.LeftTeam, PartyGlobals.TeamActivityTeams.RightTeam] for currTeam in teams: numToons = len(self.toonIds[currTeam]) if numToons > 1: for i in range(numToons - 1, 0, -1): toon1 = self.toonIds[currTeam][i] toon2 = self.toonIds[currTeam][i - 1] if toon1 not in self.toonIdsToRightHands: self.notify.warning('Toon in tug of war activity but not properly setup: %s' % toon1) elif toon2 not in self.toonIdsToRightHands: self.notify.warning('Toon in tug of war activity but not properly setup: %s' % toon2) else: self.notify.debug('Connecting rope between toon %d and toon %d of team %d.' % (i, i - 1, currTeam)) self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon2], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 def tightenRopes(self): self.notify.debug('tightenRopes') self.tugRopes[0].setup(3, ((self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0))), [0, 0, 0, 1, 1, 1]) def hideRopes(self): self.notify.debug('hideRopes') for rope in self.tugRopes: rope.stash() def handleGameTimerExpired(self): self.disableKeys() def setIdealRate(self, idealRate): self.notify.debug('setIdealRate( %d )' % idealRate) self.idealRate = idealRate self.idealForce = self.advantage * (4 + 0.4 * self.idealRate) def updateKeyPressRate(self): for i in range(len(self.keyTTL)): self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0.0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1: self.rateMatchAward += 0.3 else: self.rateMatchAward = 0.0 def reportToServer(self): self.currentForce = self.computeForce(self.keyRate) self.sendUpdate('reportKeyRateForce', [self.keyRate, self.currentForce]) self.setSpeedGauge() self.setAnimState(base.localAvatar.doId, self.keyRate) def computeForce(self, keyRate): F = 0 if self.allOutMode: F = 0.75 * keyRate else: stdDev = 0.25 * self.idealRate F = self.advantage * (self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow(math.e, -math.pow(keyRate - self.idealRate, 2) / (2.0 * math.pow(stdDev, 2))) return F def setSpeedGauge(self): self.powerMeter.setPower(self.keyRate) self.powerMeter.setTarget(self.idealRate) if not self.allOutMode: self.powerMeter.updateTooSlowTooFast() index = float(self.currentForce) / self.idealForce bonus = 0.0 if index > 1.0: bonus = max(1.0, index - 1.0) index = 1.0 color = (0, 0.75 * index + 0.25 * bonus, 0.75 * (1 - index), 0.5) self.powerMeter.setBarColor(color) else: self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) def updateToonKeyRate(self, toonId, keyRate): if toonId != base.localAvatar.doId: self.setAnimState(toonId, keyRate) def setAnimState(self, toonId, keyRate): if self.activityFSM.state != 'Active': return toon = self.getAvatar(toonId) if toonId not in self.toonIdsToIsPullingFlags: if self.getTeam(toonId) == None: self.notify.warning("setAnimState called with toonId (%d) that wasn't in self.toonIds" % toonId) return else: self.notify.warning('setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it.' % toonId) self.toonIdsToIsPullingFlags[toonId] = False if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]: if toon: toon.loop('tug-o-war') else: self.notify.warning('toon %d is None, skipping toon.loop(tugowar)' % toonId) self.toonIdsToIsPullingFlags[toonId] = True if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]: if toon: toon.pose('tug-o-war', 3) toon.startLookAround() else: self.notify.warning('toon %d is None, skipping toon.startLookAround' % toonId) self.toonIdsToIsPullingFlags[toonId] = False return def enableKeys(self): self.notify.debug('enableKeys') self.arrowKeys.setPressHandlers([lambda : self.__pressHandler(2), lambda : self.__pressHandler(3), lambda : self.__pressHandler(1), lambda : self.__pressHandler(0)]) self.arrowKeys.setReleaseHandlers([lambda : self.__releaseHandler(2), lambda : self.__releaseHandler(3), lambda : self.__releaseHandler(1), lambda : self.__releaseHandler(0)]) for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor) def disableKeys(self): self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS) self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS) def __pressHandler(self, index): if index == self.buttons[0]: self.arrows[index].setColor(PartyGlobals.TugOfWarHilightedArrowColor) self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive) self.buttons.reverse() def __releaseHandler(self, index): if index in self.buttons: self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor) def updateToonPositions(self, offset): if self.activityFSM.state != 'Active': return if self.isLocalToonPlaying: camera.lookAt(self.root, offset, 0.0, PartyGlobals.TugOfWarCameraLookAtHeightOffset) for toonId in self.getToonIdsAsList(): if hasattr(self, 'fallenToons') and toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon is not None: origPos = self.toonIdsToStartPositions[toonId] curPos = toon.getPos(self.root) newPos = Point3(origPos[0] + offset, curPos[1], curPos[2]) if self.toonIdsToAnimIntervals[toonId] != None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() self.checkIfFallen(toonId) if toonId not in self.fallenToons: self.toonIdsToAnimIntervals[toonId] = Sequence(LerpPosInterval(toon, duration=PartyGlobals.TugOfWarKeyPressReportRate, pos=newPos, other=self.root), Func(self.checkIfFallen, toonId)) self.toonIdsToAnimIntervals[toonId].start() return def checkIfFallen(self, toonId): if hasattr(self, 'fallenToons') and toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon: curPos = toon.getPos(self.root) team = self.getTeam(toonId) if team == PartyGlobals.TeamActivityTeams.LeftTeam and curPos[0] > -2.0 or team == PartyGlobals.TeamActivityTeams.RightTeam and curPos[0] < 2.0: losingTeam = self.getTeam(toonId) self.throwTeamInWater(losingTeam) self.sendUpdate('reportFallIn', [losingTeam]) def throwTeamInWater(self, losingTeam): self.notify.debug('throwTeamInWater( %s )' % PartyGlobals.TeamActivityTeams.getString(losingTeam)) splashSet = False for toonId in self.toonIds[losingTeam]: self.fallenToons.append(toonId) toon = self.getAvatar(toonId) fallenPosIndex = self.toonIds[losingTeam].index(toonId) if fallenPosIndex < 0 or fallenPosIndex >= 4: fallenPosIndex = 0 newPos = self.fallenPositions[fallenPosIndex] if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() if toon: parallel = Parallel(ActorInterval(actor=toon, animName='slip-forward', duration=2.0), LerpPosInterval(toon, duration=2.0, pos=newPos, other=self.root)) else: self.notify.warning('toon %d is none, skipping slip-forward' % toonId) parallel = Parallel() if not splashSet: splashSet = True parallel.append(self.splashInterval) if toon: self.toonIdsToAnimIntervals[toonId] = Sequence(parallel, Func(toon.loop, 'neutral')) else: self.notify.warning('toon %d is none, skipping toon.loop(neutral)' % toonId) self.toonIdsToAnimIntervals[toonId] = parallel self.toonIdsToAnimIntervals[toonId].start() return def setAdvantage(self, advantage): DistributedPartyTeamActivity.setAdvantage(self, advantage) if self.isLocalToonPlaying: self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
class DistributedCogdoInterior(DistributedObject.DistributedObject): id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.loadSfx( 'phase_5/audio/sfx/elevator_door_close.ogg') self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0) self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 self.BottomFloor_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0) ] self.BottomFloor_SuitHs = [75, 170, -91, -44] self.Cubicle_SuitPositions = [ Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0) ] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0) ] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1) self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loadMusic( 'phase_7/audio/bgm/encntr_toon_winning_indoor.ogg') self.elevatorMusic = base.loadMusic( 'phase_7/audio/bgm/tt_elevator.ogg') self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [ State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game', 'BattleIntro', 'BarrelRoomIntro']), State.State('Game', self.enterGame, self.exitGame, [ 'Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro', 'Elevator' ]), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle']) ], 'Off', 'Off') self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall( self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall( self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def getFOType(self): return self.FOType def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return name + '%d' % DistributedCogdoInterior.id def generate(self): DistributedObject.DistributedObject.generate(self) self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) self.elevatorModelIn = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left_door') self.rightDoorIn = self.elevatorModelIn.find('**/right_door') self.elevatorModelOut = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevator') self.leftDoorOut = self.elevatorModelOut.find('**/left_door') self.rightDoorOut = self.elevatorModelOut.find('**/right_door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning( 'No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons' ) random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): npc = elevatorModel.findAllMatches('**/floor_light_?;+s') for i in xrange(npc.getNumPaths()): np = npc.getPath(i) np.setDepthOffset(120) floor = int(np.getName()[-1:]) - 1 if floor == self.currentFloor: np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors() + ( 1 if self.FOType != "s" else 0): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find('**/floor_light_%s' % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals['alertElevatorLight'] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval('alertElevatorLight') self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_door.ogg') self.cageLowerSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg') self.sendUpdate('setAvatarJoined', []) def disable(self): self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): if not self.layout.hasBossBattle(): return False return (self.layout.getBossBattleFloor() + 0) == floorNum def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] if self.elevatorModelIn != None: self.elevatorModelIn.removeNode() if self.elevatorModelOut != None: self.elevatorModelOut.removeNode() if self.floorModel != None: self.floorModel.removeNode() if self.cage != None: self.cage = None if self.barrelRoom != None: self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected=0): if self.toons.count(toon) == 1: self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] if interval.isPlaying(): interval.finish() def __cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if toonId != 0: if toonId in self.cr.doId2do: toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if not oldtoons.count(toon): self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if not self.toons.count(toon): self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.suits.append(suit) suit.fsm.request('Battle') suit.buildingSuit = 1 suit.reparentTo(render) if not oldsuits.count(suit): self.joiningReserves.append(suit) if 'Elevator' in repr(self.fsm): pos, h = BattleBase.BattleBase.suitPoints[ len(suitIds) - 1][suitIds.index(suitId)] suit.setPos(pos) suit.setH(h) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] for index in xrange(len(reserveIds)): suitId = reserveIds[index] if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if len(self.joiningReserves) > 0: self.fsm.request('ReservesJoining') def setState(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash=True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() def d_elevatorDone(self): self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): self.sendUpdate('reserveJoinDone', []) def enterOff(self, ts=0): messenger.send('sellbotFieldOfficeChanged', [False]) def exitOff(self): pass def enterWaitForAllToonsInside(self, ts=0): base.transitions.fadeOut(0) def exitWaitForAllToonsInside(self): pass def enterGame(self, ts=0): base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) def __playElevator(self, ts, name, callback): SuitHs = [] SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if self.currentFloor == 0: SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): self.notify.info('__playElevator: currentFloor %s is boss' % self.currentFloor) self.barrelRoom.unload() if self.FOType: penthouseName = SUITE_DICT.get(self.FOType) for i in range(4): self.floorModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % penthouseName) self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in xrange(4): paintingModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) if not self.floorModel.find('**/trophyCase').isEmpty(): for i in range(4): goldEmblem = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam' ) loc = self.floorModel.find('**/gold_0%d' % (i + 1)) goldEmblem.reparentTo(loc) for i in range(20): silverEmblem = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam' ) loc = self.floorModel.find('**/silver_0%d' % (i + 1)) silverEmblem.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.info('Load boss_suit_office') elevIn = self.floorModel.find( CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find( CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) self.elevatorModelOut.setY(0) else: elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded( ) and self.currentFloor == 2 and self.FOType == 'l': elevIn = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorInPath) elevOut = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: floorModel = loader.loadModel( 'phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn self.elevOut = elevOut self._haveEntranceElevator.set(True) for index in range(len(self.suits)): if not self.suits[index].isEmpty(): self.suits[index].setPos(SuitPositions[index]) if len(self.suits) > 2: self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH(170) self.suits[index].loop('neutral') for toon in self.toons: toon.reparentTo(self.elevatorModelIn) index = self.toonIds.index(toon.doId) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') self.elevatorModelIn.reparentTo(elevIn) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) base.playMusic(self.elevatorMusic, looping=1, volume=0.8) track = Sequence( Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render)) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts=0): if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: if self.FOType == 's': self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) def __setupBarrelRoom(self): self.currentFloor += 1 base.transitions.irisOut(0.0) self.elevatorModelOut.setY(-12) self.elevatorModelIn.reparentTo( self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) self.setElevatorLights(self.elevatorModelOut) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval( ) self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) self._movie = CogdoBarrelRoomIntro() self._movie.load() self._movie.play() else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) base.localAvatar.questMap.stop() def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task=None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) self.fsm.request('Battle') def enterBarrelRoomReward(self, ts=0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi( callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts=0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() def __playCloseElevatorOut(self, name, delay=0): track = Sequence( Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel( SoundInterval(self.closeSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'))) track.start() self.activeIntervals[name] = track def enterBattle(self, ts=0): if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): self.elevatorModelOut.reparentTo(self.elevOut) self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def exitBattle(self): if self.elevatorOutOpen == 1: self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 def __playReservesJoining(self, ts, name, callback): index = 0 for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos( self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') if len(self.suits) == len(self.joiningReserves): camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, Point3(0, 5, 5)), Func(camera.headsUp, self.elevatorModelOut)) else: camSequence = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0))) track = Sequence( camSequence, Parallel( SoundInterval(self.openSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME), Func(camera.wrtReparentTo, render), Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts=0): self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) return None def __handleReserveJoinDone(self): self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) return None def enterResting(self, ts=0): self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -22, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() def enterReward(self, ts=0): if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug( 'exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None def enterFailed(self, ts=0): self.exitCogdoBuilding() def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = { 'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId } messenger.send('DSIDoneEvent', [request]) def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in xrange(len(self.toons)): goldBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in xrange(numFloors): silverBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') if self.FOType == "l": speech = TTLocalizer.CogdoLawbotExecutiveSuiteToonThankYou else: speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append( Sequence( Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel( self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel( self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether( self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed=None): self.shopOwnerNpc.setChatAbsolute( TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel( Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, settings['fieldofview']))) track.start() self.penthouseOutroChatDoneTrack = track
class DistCogdoGame(DistCogdoGameBase, DistributedObject): notify = directNotify.newCategory('DistCogdoGame') def __init__(self, cr): DistributedObject.__init__(self, cr) base.cogdoGame = self cr.cogdoGame = self self._waitingStartLabel = DirectLabel( text=TTL.MinigameWaitingForOtherPlayers, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075) self._waitingStartLabel.hide() self.loadFSM = ClassicFSM.ClassicFSM('DistCogdoGame.loaded', [ State.State('NotLoaded', self.enterNotLoaded, self.exitNotLoaded, ['Loaded']), State.State('Loaded', self.enterLoaded, self.exitLoaded, ['NotLoaded']) ], 'NotLoaded', 'NotLoaded') self.loadFSM.enterInitialState() self.fsm = ClassicFSM.ClassicFSM('DistCogdoGame', [ State.State('Visible', self.enterVisible, self.exitVisible, ['Intro']), State.State('Intro', self.enterIntro, self.exitIntro, ['WaitServerStart']), State.State('WaitServerStart', self.enterWaitServerStart, self.exitWaitServerStart, ['Game']), State.State('Game', self.enterGame, self.exitGame, ['Finish']), State.State('Finish', self.enterFinish, self.exitFinish, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Visible']) ], 'Off', 'Off') self.fsm.enterInitialState() self.difficultyOverride = None self.exteriorZoneOverride = None self._gotInterior = StateVar(False) self._toonsInEntranceElev = StateVar(False) self._wantStashElevator = StateVar(False) self._stashElevatorFC = FunctionCall(self._doStashElevator, self._toonsInEntranceElev, self._gotInterior, self._wantStashElevator) return def getTitle(self): pass def getInstructions(self): pass def setInteriorId(self, interiorId): self._interiorId = interiorId def setExteriorZone(self, exteriorZone): self.exteriorZone = exteriorZone def setDifficultyOverrides(self, difficultyOverride, exteriorZoneOverride): if difficultyOverride != CogdoGameConsts.NoDifficultyOverride: self.difficultyOverride = difficultyOverride / float( CogdoGameConsts.DifficultyOverrideMult) if exteriorZoneOverride != CogdoGameConsts.NoExteriorZoneOverride: self.exteriorZoneOverride = exteriorZoneOverride def getInterior(self): return self.cr.getDo(self._interiorId) def getEntranceElevator(self, callback): return self.getInterior().getEntranceElevator(callback) def getToonIds(self): interior = self.getInterior() if interior is not None: return interior.getToonIds() else: return [] return def getToon(self, toonId): if self.cr.doId2do.has_key(toonId): return self.cr.doId2do[toonId] else: return None return None def getNumPlayers(self): return len(self.getToonIds()) def isSinglePlayer(self): if self.getNumPlayers() == 1: return 1 else: return 0 def announceGenerate(self): DistributedObject.announceGenerate(self) self.loadFSM.request('Loaded') self._requestInterior() self.notify.info('difficulty: %s, safezoneId: %s' % (self.getDifficulty(), self.getSafezoneId())) def _requestInterior(self): self.cr.relatedObjectMgr.requestObjects( [self._interiorId], allCallback=self._handleGotInterior) def _handleGotInterior(self, objs): self._gotInterior.set(True) self.getEntranceElevator(self.placeEntranceElev) def stashEntranceElevator(self): self._wantStashElevator.set(True) def placeEntranceElev(self, elev): pass def _doStashElevator(self, toonsInEntranceElev, gotInterior, wantStashElevator): if gotInterior: interior = self.getInterior() if interior: if not toonsInEntranceElev and wantStashElevator: interior.stashElevatorIn() else: interior.stashElevatorIn(False) def disable(self): base.cogdoGame = None self.cr.cogdoGame = None self.fsm.requestFinalState() self.loadFSM.requestFinalState() self.fsm = None self.loadFSM = None DistributedObject.disable(self) return def delete(self): self._stashElevatorFC.destroy() self._wantStashElevator.destroy() self._toonsInEntranceElev.destroy() self._gotInterior.destroy() self._waitingStartLabel.destroy() self._waitingStartLabel = None DistributedObject.delete(self) return def getDifficulty(self): if self.difficultyOverride is not None: return self.difficultyOverride if hasattr(base, 'cogdoGameDifficulty'): return float(base.cogdoGameDifficulty) return CogdoGameConsts.getDifficulty(self.getSafezoneId()) def getSafezoneId(self): if self.exteriorZoneOverride is not None: return self.exteriorZoneOverride if hasattr(base, 'cogdoGameSafezoneId'): return CogdoGameConsts.getSafezoneId(base.cogdoGameSafezoneId) return CogdoGameConsts.getSafezoneId(self.exteriorZone) def enterNotLoaded(self): pass def exitNotLoaded(self): pass def enterLoaded(self): pass def exitLoaded(self): pass def enterOff(self): pass def exitOff(self): pass def setVisible(self): self.fsm.request('Visible') def setIntroStart(self): self.fsm.request('Intro') def enterVisible(self): self._toonsInEntranceElev.set(True) def exitVisible(self): pass def enterIntro(self, duration=MinigameGlobals.rulesDuration): base.cr.playGame.getPlace().fsm.request('Game') self._rulesDoneEvent = self.uniqueName('cogdoGameRulesDone') self.accept(self._rulesDoneEvent, self._handleRulesDone) self._rulesPanel = CogdoGameRulesPanel('CogdoGameRulesPanel', self.getTitle(), '', self._rulesDoneEvent, timeout=duration) self._rulesPanel.load() self._rulesPanel.enter() def exitIntro(self): self._toonsInEntranceElev.set(False) self.ignore(self._rulesDoneEvent) if self._rulesPanel: self._rulesPanel.exit() self._rulesPanel.unload() self._rulesPanel = None return def _handleRulesDone(self): self.ignore(self._rulesDoneEvent) self._rulesPanel.exit() self._rulesPanel.unload() self._rulesPanel = None self.fsm.request('WaitServerStart') self.d_setAvatarReady() return def d_setAvatarReady(self): self.sendUpdate('setAvatarReady', []) def enterWaitServerStart(self): numToons = 1 interior = self.getInterior() if interior: numToons = len(interior.getToonIds()) if numToons > 1: msg = TTL.MinigameWaitingForOtherPlayers else: msg = TTL.MinigamePleaseWait self._waitingStartLabel['text'] = msg self._waitingStartLabel.show() def exitWaitServerStart(self): self._waitingStartLabel.hide() def setGameStart(self, timestamp): self._startTime = globalClockDelta.networkToLocalTime(timestamp) self.fsm.request('Game') def getStartTime(self): return self._startTime #def enterGame(self): #if SCHELLGAMES_DEV: #self.acceptOnce('escape', messenger.send, ['magicWord', ['~endMaze']]) def exitGame(self): if SCHELLGAMES_DEV: self.ignore('escape') def setGameFinish(self, timestamp): self._finishTime = globalClockDelta.networkToLocalTime(timestamp) self.fsm.request('Finish') def getFinishTime(self): return self._finishTime def enterFinish(self): pass def exitFinish(self): pass def setToonSad(self, toonId): pass def setToonDisconnect(self, toonId): pass
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity): notify = directNotify.newCategory("DistributedPartyTugOfWarActivity") def __init__(self, cr): """ cr: instance of ClientRepository """ DistributedPartyTeamActivity.__init__( self, cr, PartyGlobals.ActivityIds.PartyTugOfWar, startDelay=PartyGlobals.TugOfWarStartDelay) assert (self.notify.debug("__init__")) # these are the indices of the active buttons self.buttons = [0, 1] # these variables are used for calculation how fast the player is pressing the keys self.arrowKeys = None self.keyTTL = [] self.idealRate = 0.0 self.keyRate = 0 self.allOutMode = False self.rateMatchAward = 0.0 # bonus for consistently hitting the ideal rate self.toonIdsToStartPositions = {} # initial positions of toons self.toonIdsToIsPullingFlags = {} # whether or not a toon is pulling self.toonIdsToRightHands = {} # used for setting up ropes self.fallenToons = [] # toons in the water self.fallenPositions = [] self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.toonIdsToAnimIntervals = {} self.tugRopes = [] def generate(self): DistributedPartyTeamActivity.generate(self) assert (self.notify.debug("generate")) self._hopOffFinishedSV = StateVar(True) self._rewardFinishedSV = StateVar(True) self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady, self._hopOffFinishedSV, self._rewardFinishedSV) def delete(self): self._isWalkStateReadyFC.destroy() self._hopOffFinishedSV.destroy() self._rewardFinishedSV.destroy() DistributedPartyTeamActivity.delete(self) def handleToonJoined(self, toonId): DistributedPartyTeamActivity.handleToonJoined(self, toonId) self.toonIdsToAnimIntervals[toonId] = None if toonId == base.localAvatar.doId: base.cr.playGame.getPlace().fsm.request("activity") # set camera to a 3rd person view of play area camera.wrtReparentTo(self.root) self.cameraMoveIval = LerpPosHprInterval( camera, 1.5, PartyGlobals.TugOfWarCameraPos, PartyGlobals.TugOfWarCameraInitialHpr, other=self.root, ) self.cameraMoveIval.start() self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) self.notify.debug("posIndex: %d" % self.localToonPosIndex) toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][ self.localToonPosIndex] # prevent toons from clipping through the dock by warping them to dock height if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ: toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ) targetH = fitDestAngle2Src( toon.getH(self.root), PartyGlobals.TugOfWarHeadings[self.localToonTeam]) travelVector = targetPos - toon.getPos(self.root) duration = travelVector.length() / 5.0 if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() self.toonIdsToAnimIntervals[toonId] = Sequence( Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, "run"), LerpPosHprInterval(toon, duration, targetPos, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, "neutral"), ) self.toonIdsToAnimIntervals[toonId].start() def handleToonExited(self, toonId): DistributedPartyTeamActivity.handleToonExited(self, toonId) # clean up local toon stuff if toonId == base.localAvatar.doId: self.cameraMoveIval.pause() # make toon jump off the dock if needed if toonId not in self.fallenToons: # finish any existing interval for that toon if toonId in self.toonIdsToAnimIntervals and \ self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) # clamp targetHeading to minimize spin targetH = fitDestAngle2Src(toon.getH(self.root), 180.0) targetPos = self.hopOffPositions[self.getTeam(toonId)][ self.getIndex(toonId, self.getTeam(toonId))] hopOffAnim = Sequence( Func(toon.startPosHprBroadcast, 0.1), toon.hprInterval(0.2, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.b_setAnimState, "jump", 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0, self.root), Func(toon.stopPosHprBroadcast), # make sure toon ends up on the ground on remote clients Func(toon.sendCurrentPosition), Func(self.hopOffFinished, toonId), ) self.toonIdsToAnimIntervals[toonId] = hopOffAnim self._hopOffFinishedSV.set(False) self.toonIdsToAnimIntervals[toonId].start() # local toons not on the dock are put back into the walk state else: self._hopOffFinishedSV.set(True) del self.toonIdsToAnimIntervals[toonId] def handleRewardDone(self): # don't call down, it puts the toon in a bad state because it interferes with # the 'hopOffAnim' self._rewardFinishedSV.set(True) def _testWalkStateReady(self, hoppedOff, rewardFinished): assert (self.notify.debug("_testWalkStateReady %d %d" % (hoppedOff, rewardFinished))) if hoppedOff and rewardFinished: DistributedPartyTeamActivity.handleRewardDone(self) def hopOffFinished(self, toonId): assert (self.notify.debug("hopOffFinished( toonId=%d )" % toonId)) if hasattr(self,"toonIdsToAnimIntervals") and \ toonId in self.toonIdsToAnimIntervals: del self.toonIdsToAnimIntervals[toonId] # clean up anim dictionary if toonId == base.localAvatar.doId: if hasattr(self._hopOffFinishedSV, '_value'): self._hopOffFinishedSV.set(True) def handleToonShifted(self, toonId): assert (self.notify.debug("handleToonShifted( toonId=%d )" % toonId)) if toonId == base.localAvatar.doId: # update local toon's position on the dock if they got shifted self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam) if self.toonIdsToAnimIntervals[toonId] is not None: self.toonIdsToAnimIntervals[toonId].finish() toon = self.getAvatar(toonId) targetPos = self.dockPositions[self.localToonTeam][ self.localToonPosIndex] self.toonIdsToAnimIntervals[toonId] = Sequence( Wait(0.6), # give leaving toon time to jump off dock Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, "run"), toon.posInterval(0.5, targetPos, other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, "neutral"), ) self.toonIdsToAnimIntervals[toonId].start() def handleToonDisabled(self, toonId): """ A toon dropped unexpectedly from the game. Handle it! """ assert (self.notify.debug("handleToonDisabled( toonId:%d )" % toonId)) if self.toonIdsToAnimIntervals.has_key(toonId): if self.toonIdsToAnimIntervals[toonId]: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() else: self.notify.debug("self.toonIdsToAnimIntervals[%d] is none" % toonId) def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds): """Overrides DistributedPartyActivity's setToonsPlaying""" DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds) # update table of right hands self.toonIdsToRightHands.clear() for toonId in self.getToonIdsAsList(): toon = self.getAvatar(toonId) if toon: self.toonIdsToRightHands[toonId] = toon.getRightHands()[0] def load(self): """ Load the necessary assets """ DistributedPartyTeamActivity.load(self) assert (self.notify.debug("load")) self.loadModels() self.loadGuiElements() self.loadSounds() self.loadIntervals() self.arrowKeys = ArrowKeys() def loadModels(self): # load the tug of war play area self.playArea = loader.loadModel( "phase_13/models/parties/partyTugOfWar") # reparent to the party ground root self.playArea.reparentTo(self.root) # place the activity sign self.sign.reparentTo(self.playArea.find("**/TugOfWar_sign_locator")) # define initial positions, with index 0 being closest to the other team self.dockPositions = [ [], # left team positions [], # right team positions ] for i in range(4): self.dockPositions[0].append( Point3( -PartyGlobals.TugOfWarInitialToonPositionsXOffset - PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ, )) for i in range(4): self.dockPositions[1].append( Point3( PartyGlobals.TugOfWarInitialToonPositionsXOffset + PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ, )) self.hopOffPositions = [ [], # left team positions [], # right team positions ] for i in range(1, 5): self.hopOffPositions[ PartyGlobals.TeamActivityTeams.LeftTeam].append( self.playArea.find("**/leftTeamHopOff%d_locator" % i).getPos()) self.hopOffPositions[ PartyGlobals.TeamActivityTeams.RightTeam].append( self.playArea.find("**/rightTeamHopOff%d_locator" % i).getPos()) # load positions for when toons fall into the water for i in range(1, 5): pos = self.playArea.find("**/fallenToon%d_locator" % i).getPos() self.fallenPositions.append(pos) # load collision that allows toons to play the game # create one for each dock that lets toons join a particular team self.joinCollision = [] self.joinCollisionNodePaths = [] for i in range(len(PartyGlobals.TeamActivityTeams)): collShape = CollisionTube( PartyGlobals.TugOfWarJoinCollisionEndPoints[0], PartyGlobals.TugOfWarJoinCollisionEndPoints[1], PartyGlobals.TugOfWarJoinCollisionRadius) collShape.setTangible(True) self.joinCollision.append( CollisionNode("TugOfWarJoinCollision%d" % i)) self.joinCollision[i].addSolid(collShape) tubeNp = self.playArea.attachNewNode(self.joinCollision[i]) tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask) self.joinCollisionNodePaths.append(tubeNp) self.joinCollisionNodePaths[i].setPos( PartyGlobals.TugOfWarJoinCollisionPositions[i]) self.__enableCollisions() # Get the rope texture by extracting it from its model. ropeModel = loader.loadModel( "phase_4/models/minigames/tug_of_war_rope") self.ropeTexture = ropeModel.findTexture("*") ropeModel.removeNode() # create as many ropes as we will ever need for i in range(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1): rope = Rope(self.uniqueName("TugRope%d" % i)) if rope.showRope: rope.ropeNode.setRenderMode(RopeNode.RMBillboard) rope.ropeNode.setThickness(0.2) rope.setTexture(self.ropeTexture) rope.ropeNode.setUvMode(RopeNode.UVDistance) rope.ropeNode.setUvDirection(1) rope.setTransparency(1) rope.setColor(0.89, 0.89, 0.6, 1.0) rope.reparentTo(self.root) rope.stash() self.tugRopes.append(rope) # Splash object for when toon hits the water self.splash = Splash.Splash(self.root) self.splash.setScale(2.0, 4.0, 1.0) pos = self.fallenPositions[0] self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset) self.splash.hide() def loadGuiElements(self): # load gui power meter self.powerMeter = MinigamePowerMeter( PartyGlobals.TugOfWarPowerMeterSize) self.powerMeter.reparentTo(aspect2d) self.powerMeter.setPos(0.0, 0.0, 0.6) self.powerMeter.hide() # Load the arrows for button indicator self.arrows = [None] * 2 for x in range(len(self.arrows)): self.arrows[x] = loader.loadModel('phase_3/models/props/arrow') self.arrows[x].reparentTo(self.powerMeter) self.arrows[x].setScale(.2 - .4 * x, .2, .2) self.arrows[x].setPos(.12 - .24 * x, 0, -.26) def loadSounds(self): self.splashSound = base.loadSfx( "phase_4/audio/sfx/MG_cannon_splash.mp3") self.whistleSound = base.loadSfx( "phase_4/audio/sfx/AA_sound_whistle.mp3") def loadIntervals(self): # create an interval that updates the ideal key press rate for each stage self.updateIdealRateInterval = Sequence() # other code handles setting the initial ideal rate, so only add the # wait for the first state self.updateIdealRateInterval.append( Wait(PartyGlobals.TugOfWarTargetRateList[0][0]), ) # for each stage after the first for i in range(1, len(PartyGlobals.TugOfWarTargetRateList)): duration = PartyGlobals.TugOfWarTargetRateList[i][0] idealRate = PartyGlobals.TugOfWarTargetRateList[i][1] # set ideal speed self.updateIdealRateInterval.append( Func(self.setIdealRate, idealRate)) # add delay for stage's length or set last stage flag if i == (len(PartyGlobals.TugOfWarTargetRateList) - 1): self.updateIdealRateInterval.append( Func(setattr, self, "allOutMode", True)) else: self.updateIdealRateInterval.append(Wait(duration), ) # create an interval that updates the local player's key press rate self.updateKeyPressRateInterval = Sequence( Wait(PartyGlobals.TugOfWarKeyPressUpdateRate), Func(self.updateKeyPressRate), ) # create an interval that updates the local player's force and tells the # server self.reportToServerInterval = Sequence( Wait(PartyGlobals.TugOfWarKeyPressReportRate), Func(self.reportToServer), ) self.setupInterval = Parallel() # run this even if the local toon is not playing self.globalSetupInterval = Sequence( Wait(PartyGlobals.TugOfWarReadyDuration + PartyGlobals.TugOfWarGoDuration), Func(self.tightenRopes), ) # only run this when a local toon is playing self.localSetupInterval = Sequence( Func(self.setStatus, TTLocalizer.PartyTugOfWarReady), Func(self.showStatus), Wait(PartyGlobals.TugOfWarReadyDuration), Func(base.playSfx, self.whistleSound), Func(self.setStatus, TTLocalizer.PartyTugOfWarGo), Wait(PartyGlobals.TugOfWarGoDuration), Func(self.enableKeys), Func(self.hideStatus), Func(self.updateIdealRateInterval.start), Func(self.updateKeyPressRateInterval.loop), Func(self.reportToServerInterval.loop), ) # interval for playing the splash sound and showing the splash visual effect self.splashInterval = Sequence( Func(base.playSfx, self.splashSound), Func(self.splash.play), ) def unload(self): DistributedPartyTeamActivity.unload(self) self.arrowKeys.destroy() self.unloadIntervals() self.unloadModels() self.unloadGuiElements() self.unloadSounds() # delete variables if hasattr(self, "toonIds"): del self.toonIds del self.buttons del self.arrowKeys del self.keyTTL del self.idealRate del self.keyRate del self.allOutMode del self.rateMatchAward del self.toonIdsToStartPositions del self.toonIdsToIsPullingFlags del self.toonIdsToRightHands del self.fallenToons del self.fallenPositions del self.unusedFallenPositionsIndices self.toonIdsToAnimIntervals.clear() del self.toonIdsToAnimIntervals def unloadModels(self): self.playArea.removeNode() del self.playArea del self.dockPositions del self.hopOffPositions self.__disableCollisions() while len(self.joinCollision) > 0: collNode = self.joinCollision.pop() del collNode while len(self.joinCollisionNodePaths) > 0: collNodePath = self.joinCollisionNodePaths.pop() collNodePath.removeNode() del collNodePath while len(self.tugRopes) > 0: rope = self.tugRopes.pop() if rope is not None: rope.removeNode() del rope del self.tugRopes self.splash.destroy() del self.splash def unloadGuiElements(self): for arrow in self.arrows: if arrow is not None: arrow.removeNode() del arrow del self.arrows if self.powerMeter is not None: self.powerMeter.cleanup() del self.powerMeter def unloadSounds(self): del self.splashSound del self.whistleSound def unloadIntervals(self): self.updateIdealRateInterval.pause() del self.updateIdealRateInterval self.updateKeyPressRateInterval.pause() del self.updateKeyPressRateInterval self.reportToServerInterval.pause() del self.reportToServerInterval self.setupInterval.pause() del self.setupInterval self.globalSetupInterval.pause() del self.globalSetupInterval self.localSetupInterval.pause() del self.localSetupInterval self.splashInterval.pause() del self.splashInterval def __enableCollisions(self): assert (self.notify.debug("__enableCollisions")) for i in range(len(PartyGlobals.TeamActivityTeams)): self.accept( "enterTugOfWarJoinCollision%d" % i, getattr( self, "_join%s" % PartyGlobals.TeamActivityTeams.getString(i))) def __disableCollisions(self): assert (self.notify.debug("__disableCollisions")) for i in range(len(PartyGlobals.TeamActivityTeams)): self.ignore("enterTugOfWarJoinCollision%d" % i) # FSM transition methods def startWaitForEnough(self): DistributedPartyTeamActivity.startWaitForEnough(self) self.__enableCollisions() def finishWaitForEnough(self): DistributedPartyTeamActivity.finishWaitForEnough(self) self.__disableCollisions() def startWaitToStart(self, waitStartTimestamp): DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp) self.__enableCollisions() def finishWaitToStart(self): DistributedPartyTeamActivity.finishWaitToStart(self) self.__disableCollisions() def startRules(self): DistributedPartyTeamActivity.startRules(self) self.setUpRopes() # display rules to the local toon if we have one if self.isLocalToonPlaying: self.showControls() def finishRules(self): DistributedPartyTeamActivity.finishRules(self) # check for a non-standard transition and do additional cleanup as needed if self.activityFSM.getCurrentOrNextState() == "WaitForEnough": self.hideRopes() self.hideControls() def finishWaitForServer(self): DistributedPartyTeamActivity.finishWaitForServer(self) # check for a non-standard transition and do additional cleanup as needed if self.activityFSM.getCurrentOrNextState() == "WaitForEnough": self.hideRopes() self.hideControls() def startActive(self): DistributedPartyTeamActivity.startActive(self) # reset active variables self.toonIdsToStartPositions.clear() self.toonIdsToIsPullingFlags.clear() for toonId in self.getToonIdsAsList(): self.toonIdsToIsPullingFlags[toonId] = False toon = self.getAvatar(toonId) if toon: self.toonIdsToStartPositions[toonId] = toon.getPos(self.root) else: # what the heck do we do at this point? lets try 0,0,0 self.notify.warning( "couldn't find toon %d assigning 0,0,0 to startPos" % toonId) self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0) self.unusedFallenPositionsIndices = [0, 1, 2, 3] self.setupInterval = Parallel(self.globalSetupInterval) if self.isLocalToonPlaying: self.keyTTL = [] self.idealForce = 0.0 self.keyRate = 0 self.rateMatchAward = 0.0 self.allOutMode = False self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1]) self.setupInterval.append(self.localSetupInterval) self.setupInterval.start() def finishActive(self): DistributedPartyTeamActivity.finishActive(self) self.hideControls() self.disableKeys() self.setupInterval.pause() self.reportToServerInterval.pause() self.updateKeyPressRateInterval.pause() self.updateIdealRateInterval.pause() self.hideRopes() def startConclusion(self, losingTeam): DistributedPartyTeamActivity.startConclusion(self, losingTeam) if self.isLocalToonPlaying: self._rewardFinishedSV.set(False) if losingTeam == PartyGlobals.TeamActivityNeitherTeam: self.setStatus(TTLocalizer.PartyTeamActivityGameTie) else: self.setStatus(TTLocalizer.PartyTugOfWarGameEnd) self.showStatus() if losingTeam == PartyGlobals.TeamActivityNeitherTeam: # tie for toonId in self.getToonIdsAsList(): if self.getAvatar(toonId): self.getAvatar(toonId).loop("neutral") else: # winning and losing team for toonId in self.toonIds[losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop("neutral") for toonId in self.toonIds[1 - losingTeam]: if self.getAvatar(toonId): self.getAvatar(toonId).loop("victory") for ival in self.toonIdsToAnimIntervals.values(): if ival is not None: ival.finish() def finishConclusion(self): DistributedPartyTeamActivity.finishConclusion(self) self.fallenToons = [] def getTitle(self): return TTLocalizer.PartyTugOfWarTitle def getInstructions(self): return TTLocalizer.TugOfWarInstructions def showControls(self): # show the power meter and arrows so player can see them while they # read the rules for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor) # set meter to first stage values self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1]) self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) self.powerMeter.clearTooSlowTooFast() self.powerMeter.show() def hideControls(self): self.powerMeter.hide() def setUpRopes(self): self.notify.debug("setUpRopes") ropeIndex = 0 # setup rope linking the left team to the right team leftToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]: leftToonId = self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][0] rightToonId = -1 if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]: rightToonId = self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][0] if leftToonId in self.toonIdsToRightHands and \ rightToonId in self.toonIdsToRightHands: self.tugRopes[ropeIndex].setup( 3, ( (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.root, (0.0, 0.0, 2.5)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0)), ), [0, 0, 0, 1, 1, 1], ) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 # setup ropes linking toons on the left team if len(self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]) > 1: for i in range( len(self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]) - 1, 0, -1): self.notify.debug( "Connecting rope between toon %d and toon %d of left team." % (i, i - 1)) self.tugRopes[ropeIndex].setup( 3, ( (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][i]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][i]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][i - 1]], (0, 0, 0)), ), [0, 0, 0, 1, 1, 1], ) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 # setup ropes linking toons on the right team if len(self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]) > 1: for i in range( len(self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]) - 1): self.notify.debug( "Connecting rope between toon %d and toon %d of left team." % (i, i + 1)) self.tugRopes[ropeIndex].setup( 3, ( (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][i]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][i]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][i + 1]], (0, 0, 0)), ), [0, 0, 0, 1, 1, 1], ) self.tugRopes[ropeIndex].unstash() ropeIndex += 1 def tightenRopes(self): """ The pulling part has started. Make the rope between the teams taut. """ self.notify.debug("tightenRopes") self.tugRopes[0].setup( 3, ( (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[ PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0)), ), [0, 0, 0, 1, 1, 1], ) def hideRopes(self): self.notify.debug("hideRopes") for rope in self.tugRopes: rope.stash() def handleGameTimerExpired(self): assert (self.notify.debug("game timer expired")) self.disableKeys() # do not allow any more input def setIdealRate(self, idealRate): self.notify.debug("setIdealRate( %d )" % idealRate) self.idealRate = idealRate self.idealForce = self.advantage * (4 + 0.4 * self.idealRate) def updateKeyPressRate(self): # decrement times to live for each key press entry in keyTTL for i in range(len(self.keyTTL)): self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate # remove all key presses that have run out of time to live # I think this only removes at most 1 item from the list, which is not # what we want, but worked for Trolley tug of war so I'm afraid to "fix" it for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0.0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) # if the user has matched the idealRate several times in a row, add # a little bit to their power if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1: self.rateMatchAward += 0.3 else: self.rateMatchAward = 0.0 def reportToServer(self): self.currentForce = self.computeForce(self.keyRate) self.sendUpdate("reportKeyRateForce", [self.keyRate, self.currentForce]) self.setSpeedGauge() self.setAnimState(base.localAvatar.doId, self.keyRate) def computeForce(self, keyRate): # return a force in the range 0-self.idealRate F = 0 # if this is the last stage, make force directly proportional to keyrate if self.allOutMode: F = 0.75 * keyRate # otherwise, make force proportional to how close you are to ideal key rate else: stdDev = 0.25 * self.idealRate F = self.advantage * ( self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow( math.e, -math.pow(keyRate - self.idealRate, 2) / (2.0 * math.pow(stdDev, 2))) return F def setSpeedGauge(self): # update the power meter to show the toon's speed and the target speed self.powerMeter.setPower(self.keyRate) self.powerMeter.setTarget(self.idealRate) # change the color of the power meter to indicate how well the toon is doing # the color should be dark if you are doing badly, and green if you are doing well if not self.allOutMode: # tell the toon if he is pulling too fast or too slow self.powerMeter.updateTooSlowTooFast() index = float(self.currentForce) / self.idealForce bonus = 0.0 if index > 1.0: bonus = max(1.0, index - 1.0) index = 1.0 color = (0, 0.75 * index + 0.25 * bonus, 0.75 * (1 - index), 0.5) self.powerMeter.setBarColor(color) else: self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5)) def updateToonKeyRate(self, toonId, keyRate): # since we set the local toon's pulling animation locally, don't do it # here if toonId != base.localAvatar.doId: self.setAnimState(toonId, keyRate) def setAnimState(self, toonId, keyRate): if self.activityFSM.state != "Active": return toon = self.getAvatar(toonId) if not self.toonIdsToIsPullingFlags.has_key(toonId): if self.getTeam(toonId) == None: self.notify.warning( "setAnimState called with toonId (%d) that wasn't in self.toonIds" % toonId) return else: self.notify.warning( "setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it." % toonId) self.toonIdsToIsPullingFlags[toonId] = False if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]: if toon: toon.loop('tug-o-war') else: self.notify.warning( "toon %d is None, skipping toon.loop(tugowar)" % toonId) self.toonIdsToIsPullingFlags[toonId] = True if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]: if toon: toon.pose('tug-o-war', 3) toon.startLookAround() else: self.notify.warning( "toon %d is None, skipping toon.startLookAround" % toonId) self.toonIdsToIsPullingFlags[toonId] = False def enableKeys(self): self.notify.debug("enableKeys") # Change the order of the press handlers because we are only using 2 keys self.arrowKeys.setPressHandlers([ lambda: self.__pressHandler(2), lambda: self.__pressHandler(3), lambda: self.__pressHandler(1), lambda: self.__pressHandler(0), ]) self.arrowKeys.setReleaseHandlers([ lambda: self.__releaseHandler(2), lambda: self.__releaseHandler(3), lambda: self.__releaseHandler(1), lambda: self.__releaseHandler(0), ]) for arrow in self.arrows: arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor) def disableKeys(self): self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS) self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS) # callbacks for when the buttons are pressed and released def __pressHandler(self, index): if index == self.buttons[0]: self.arrows[index].setColor( PartyGlobals.TugOfWarHilightedArrowColor) self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive) self.buttons.reverse() def __releaseHandler(self, index): if index in self.buttons: self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor) def updateToonPositions(self, offset): # Since the timer expires locally, we may still get a few # messages from the AI that were on the wire when we left # the play state, just ignore it if self.activityFSM.state != "Active": return # adjust the camera angle if self.isLocalToonPlaying: camera.lookAt(self.root, offset, 0.0, PartyGlobals.TugOfWarCameraLookAtHeightOffset) # this client sets the position of all toons playing for toonId in self.getToonIdsAsList(): if hasattr(self,"fallenToons") and \ toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon is not None: origPos = self.toonIdsToStartPositions[toonId] curPos = toon.getPos(self.root) newPos = Point3(origPos[0] + offset, curPos[1], curPos[2]) # finish any existing animation interval if self.toonIdsToAnimIntervals[toonId] != None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() self.checkIfFallen(toonId) if toonId not in self.fallenToons: self.toonIdsToAnimIntervals[toonId] = Sequence( LerpPosInterval( toon, duration=PartyGlobals. TugOfWarKeyPressReportRate, pos=newPos, other=self.root, ), Func(self.checkIfFallen, toonId)) self.toonIdsToAnimIntervals[toonId].start() def checkIfFallen(self, toonId): # check if toon has fallen if hasattr(self,"fallenToons") and \ toonId not in self.fallenToons: toon = self.getAvatar(toonId) if toon: curPos = toon.getPos(self.root) team = self.getTeam(toonId) if ((team == PartyGlobals.TeamActivityTeams.LeftTeam and curPos[0] > -2.0) or (team == PartyGlobals.TeamActivityTeams.RightTeam and curPos[0] < 2.0)): # throw all toons from this side in the water losingTeam = self.getTeam(toonId) self.throwTeamInWater(losingTeam) # tell AI that a team fell in the water self.sendUpdate("reportFallIn", [losingTeam]) def throwTeamInWater(self, losingTeam): self.notify.debug("throwTeamInWater( %s )" % PartyGlobals.TeamActivityTeams.getString(losingTeam)) splashSet = False for toonId in self.toonIds[losingTeam]: # throw toon in water self.fallenToons.append(toonId) toon = self.getAvatar(toonId) # getting a a crash of popping from empty list #fallenPosIndex = self.unusedFallenPositionsIndices.pop(0) fallenPosIndex = self.toonIds[losingTeam].index(toonId) if (fallenPosIndex < 0) or (fallenPosIndex >= 4): fallenPosIndex = 0 newPos = self.fallenPositions[fallenPosIndex] # animate the toons falling into the water if self.toonIdsToAnimIntervals[toonId] is not None: if self.toonIdsToAnimIntervals[toonId].isPlaying(): self.toonIdsToAnimIntervals[toonId].finish() # Fall into water if toon: parallel = Parallel( ActorInterval(actor=toon, animName='slip-forward', duration=2.0), LerpPosInterval(toon, duration=2.0, pos=newPos, other=self.root), ) else: self.notify.warning("toon %d is none, skipping slip-forward" % toonId) parallel = Parallel() # only setup splash for the first toon if not splashSet: splashSet = True parallel.append(self.splashInterval) if toon: self.toonIdsToAnimIntervals[toonId] = Sequence( parallel, Func(toon.loop, 'neutral'), ) else: self.notify.warning( "toon %d is none, skipping toon.loop(neutral)" % toonId) self.toonIdsToAnimIntervals[toonId] = parallel self.toonIdsToAnimIntervals[toonId].start() def setAdvantage(self, advantage): DistributedPartyTeamActivity.setAdvantage(self, advantage) if self.isLocalToonPlaying: self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
class SCTerminal(SCElement): def __init__(self, linkedEmote = None): SCElement.__init__(self) self.setLinkedEmote(linkedEmote) scGui = loader.loadModel(SCMenu.GuiModelName) self.emotionIcon = scGui.find('**/emotionIcon') self.setDisabled(False) self.__numCharges = -1 self._handleWhisperModeSV = StateVar(False) self._handleWhisperModeFC = None return def destroy(self): self._handleWhisperModeSV.set(False) if self._handleWhisperModeFC: self._handleWhisperModeFC.destroy() self._handleWhisperModeSV.destroy() SCElement.destroy(self) def privSetSettingsRef(self, settingsRef): SCElement.privSetSettingsRef(self, settingsRef) if self._handleWhisperModeFC is None: self._handleWhisperModeFC = FunctionCall(self._handleWhisperModeSVChanged, self._handleWhisperModeSV) self._handleWhisperModeFC.pushCurrentState() self._handleWhisperModeSV.set(self.settingsRef is not None and not self.isWhisperable()) return def _handleWhisperModeSVChanged(self, handleWhisperMode): if handleWhisperMode: self._wmcListener = DirectObject() self._wmcListener.accept(self.getEventName(SCWhisperModeChangeEvent), self._handleWhisperModeChange) elif hasattr(self, '_wmcListener'): self._wmcListener.ignoreAll() del self._wmcListener self.invalidate() def _handleWhisperModeChange(self, whisperMode): self.invalidate() def handleSelect(self): messenger.send(self.getEventName(SCTerminalSelectedEvent)) if self.hasLinkedEmote() and self.linkedEmoteEnabled(): messenger.send(self.getEventName(SCTerminalLinkedEmoteEvent), [self.linkedEmote]) def isWhisperable(self): return True def getLinkedEmote(self): return self.linkedEmote def setLinkedEmote(self, linkedEmote): self.linkedEmote = linkedEmote self.invalidate() def hasLinkedEmote(self): return self.linkedEmote is not None def linkedEmoteEnabled(self): if Emote.globalEmote: return Emote.globalEmote.isEnabled(self.linkedEmote) def getCharges(self): return self.__numCharges def setCharges(self, nCharges): self.__numCharges = nCharges if nCharges is 0: self.setDisabled(True) def isDisabled(self): return self.__disabled or self.isWhispering() and not self.isWhisperable() def setDisabled(self, bDisabled): self.__disabled = bDisabled def onMouseClick(self, event): if not self.isDisabled(): SCElement.onMouseClick(self, event) self.handleSelect() def getMinDimensions(self): width, height = SCElement.getMinDimensions(self) if self.hasLinkedEmote(): width += 1.3 return (width, height) def finalize(self, dbArgs = {}): if not self.isDirty(): return args = {} if self.hasLinkedEmote(): self.lastEmoteIconColor = self.getEmoteIconColor() self.emotionIcon.setColorScale(*self.lastEmoteIconColor) args.update({'image': self.emotionIcon, 'image_pos': (self.width - 0.6, 0, -self.height * 0.5)}) if self.isDisabled(): args.update({'rolloverColor': (0, 0, 0, 0), 'pressedColor': (0, 0, 0, 0), 'rolloverSound': None, 'clickSound': None, 'text_fg': self.getColorScheme().getTextDisabledColor() + (1,)}) args.update(dbArgs) SCElement.finalize(self, dbArgs=args) return def getEmoteIconColor(self): if self.linkedEmoteEnabled() and not self.isWhispering(): r, g, b = self.getColorScheme().getEmoteIconColor() else: r, g, b = self.getColorScheme().getEmoteIconDisabledColor() return (r, g, b, 1) def updateEmoteIcon(self): if hasattr(self, 'button'): self.lastEmoteIconColor = self.getEmoteIconColor() for i in xrange(self.button['numStates']): self.button['image%s_image' % i].setColorScale(*self.lastEmoteIconColor) else: self.invalidate() def enterVisible(self): SCElement.enterVisible(self) if hasattr(self, 'lastEmoteIconColor'): if self.getEmoteIconColor() != self.lastEmoteIconColor: self.invalidate() def handleWhisperModeChange(whisperMode, self = self): if self.hasLinkedEmote(): if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() self.accept(self.getEventName(SCWhisperModeChangeEvent), handleWhisperModeChange) def handleEmoteEnableStateChange(self = self): if self.hasLinkedEmote(): if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() if self.hasLinkedEmote(): if Emote.globalEmote: self.accept(Emote.globalEmote.EmoteEnableStateChanged, handleEmoteEnableStateChange) def exitVisible(self): SCElement.exitVisible(self) self.ignore(self.getEventName(SCWhisperModeChangeEvent)) if Emote.globalEmote: self.ignore(Emote.globalEmote.EmoteEnableStateChanged) def getDisplayText(self): if self.getCharges() is not -1: return self.text + ' (%s)' % self.getCharges() else: return self.text
class DistributedPlayerSimpleShip(DistributedSimpleShip): RepairSpotFadeAfter = 2.0 RepairSpotFadeDur = 3.0 def __init__(self, cr): DistributedSimpleShip.__init__(self, cr) self._respawnLocation = None self.checkAnchor = None self.lastAttacked = None self.threatLevel = 0 self.openPort = 0 self.allowCrewState = True self.allowFriendState = True self.allowGuildState = False self.allowPublicState = False self._repairSpotMgr = ShipRepairSpotMgr(self.cr) self._team = PiratesGlobals.PLAYER_TEAM self.badInitTeam = None self.prevLocStack = None def generate(self): DistributedSimpleShip.generate(self) self._repairSpotWoodPile = None self._repairSpotWoodPiles = { } self._repairSpotHole = None self._repairSpotHoleFixed = None self._repairSpotHoles = { } self._repairSpotIvals = { } self._wheelInUse = StateVar(False) def announceGenerate(self): self._respawnLocation = None self._respawnResponseDelayedCall = None DistributedSimpleShip.announceGenerate(self) self._repairSpotMgr.setShipId(self.doId) if self.badInitTeam != None: self._verifyTeam(self.badInitTeam) def disable(self): self._wheelInUse.destroy() if self._respawnResponseDelayedCall: self._respawnResponseDelayedCall.destroy() self._respawnResponseDelayedCall = None if self.checkAnchor: self.checkAnchor.remove() self.checkAnchor = None self._repairSpotMgr.destroy() for ival in self._repairSpotIvals.itervalues(): ival.pause() del self._repairSpotIvals self.prevLocStack = None DistributedSimpleShip.disable(self) def calculateLook(self): team = self.getTeam() if team == PiratesGlobals.PLAYER_TEAM: if self.getSiegeTeam() == 1: self.style = ShipGlobals.Styles.French elif self.getSiegeTeam() == 2: self.style = ShipGlobals.Styles.Spanish def getNPCship(self): return False def setShipClass(self, shipClass): DistributedSimpleShip.setShipClass(self, shipClass) self._repairSpotMgr.updateShipClass(self.shipClass) def setHealthState(self, health): DistributedSimpleShip.setHealthState(self, health) self._repairSpotMgr.updateHealth(self.healthState) def setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast): DistributedSimpleShip.setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast) self._repairSpotMgr.updateSpeed(100.0 * self.Sp / self.maxSp) def setArmorStates(self, rear, left, right): DistributedSimpleShip.setArmorStates(self, rear, left, right) self._repairSpotMgr.updateArmor((rear + left + right) / 3.0) def setWillFullyRepairShip(self, willFullyRepairShip): self._repairSpotMgr.updateWillBeFullHealth(willFullyRepairShip) def setupLocalStats(self): DistributedSimpleShip.setupLocalStats(self) def setOpenPort(self, portId): oldPort = self.openPort self.openPort = portId if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId(): messenger.send('LocalAvatar_Ship_OpenPort_Update', [ portId, oldPort]) def getOpenPort(self): return self.openPort def isAtOpenPort(self): portDoId = localAvatar.getPort() portObj = base.cr.doId2do.get(portDoId, None) if self.threatLevel < EnemyGlobals.SHIP_THREAT_NAVY_HUNTERS: return 1 elif portObj and portObj.uniqueId == EnemyGlobals.OPEN_PORT_DICT.get(self.openPort): return 1 else: return 0 def setThreatLevel(self, threatLevel): if threatLevel != self.threatLevel: self.threatLevel = threatLevel self.updateNametag() if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId(): messenger.send('LocalAvatar_Ship_ThreatLevel_Update', [ threatLevel]) self.checkAbleDropAnchor() def getThreatLevel(self): if base.config.GetBool('want-ship-threat', 1): return self.threatLevel else: return EnemyGlobals.SHIP_THREAT_ATTACK_BACK def getOpenPort(self): return self.openPort def sunkAShipFanfare(self, shipToAttackDoId): if localAvatar.ship and localAvatar.ship == self: if localAvatar.ship.getSiegeTeam(): return None attackMessage = HighSeasGlobals.getShipSunkMessage() if attackMessage: base.localAvatar.guiMgr.queueInstructionMessage(attackMessage[0], attackMessage[1], None, 1.0, messageCategory = MessageGlobals.MSG_CAT_SUNK_SHIP) def setSiegeTeam(self, team): different = team != self.getSiegeTeam() DistributedSimpleShip.setSiegeTeam(self, team) if different: self._doSiegeAndPVPTeamColors() self._repairSpotMgr.updateSiegeTeam(team) minimapObj = self.getMinimapObject() if minimapObj: minimapObj.setSiegeTeam(team) setSiegeTeam = report(types = [ 'args'], dConfigParam = 'shipdeploy')(setSiegeTeam) def _doSiegeAndPVPTeamColors(self): if self.getPVPTeam(): self._doPVPTeamColors() elif self.getSiegeTeam(): pass def _doPVPTeamColors(self): pass def getWheelInUseSV(self): return self._wheelInUse def setWheelInUse(self, wheelInUse): DistributedSimpleShip.setWheelInUse(self, wheelInUse) self._wheelInUse.set(wheelInUse) def canTakeWheel(self, wheel, av): available = True if self.queryGameState() in ('Pinned', 'Sinking', 'Sunk', 'OtherShipBoarded'): base.localAvatar.guiMgr.createWarning(PLocalizer.ShipPinnedWarning, PiratesGuiGlobals.TextFG6) available = False elif self.isFishing and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning(PLocalizer.OnlyCaptainCanUseWarning, PiratesGuiGlobals.TextFG6) available = False elif wheel.getUserId() and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning(PLocalizer.AlreadyInUseWarning, PiratesGuiGlobals.TextFG6) available = False return available def setRespawnLocation(self, parentId, zoneId): self._respawnLocation = (parentId, zoneId) def setLocation(self, parentId, zoneId): DistributedSimpleShip.setLocation(self, parentId, zoneId) if self._respawnLocation is not None and self._respawnLocation == (parentId, zoneId): self._respawnLocation = None if not self._respawnResponseDelayedCall: self._respawnResponseDelayedCall = FrameDelayedCall('PlayerShip-respawnLocation-gridInterestComplete', Functor(base.cr.setAllInterestsCompleteCallback, self._sendRespawnLocationResponse)) def _sendRespawnLocationResponse(self): self.sendUpdate('clientReachedRespawnLocation') self._respawnResponseDelayedCall = None def recoverFromSunk(self): self.lastAttacked = None DistributedSimpleShip.recoverFromSunk(self) def attacked(self): self.lastAttacked = globalClock.getFrameTime() if self.getSiegeTeam() and not (self.checkAnchor): self.checkAbleDropAnchor() def attackTimerRemaining(self): timer = 0 if self.lastAttacked: timer = int(30 - globalClock.getFrameTime() - self.lastAttacked) return timer def _DistributedPlayerSimpleShip__recheckAbleDropAnchor(self, task): self.checkAnchor = None self.checkAbleDropAnchor() def checkAbleDropAnchor(self): PiratesGuiGlobals = PiratesGuiGlobals import pirates.piratesgui if localAvatar.doId == self.steeringAvId: if self.shipStatusDisplay: if localAvatar.getPort(): remaining = self.attackTimerRemaining() if self.getSiegeTeam() and remaining > 0: self.shipStatusDisplay.disableAnchorButton() localAvatar.guiMgr.createWarning(PLocalizer.CannotDockYet % remaining, PiratesGuiGlobals.TextFG6) self.checkAnchor = taskMgr.doMethodLater(remaining, self._DistributedPlayerSimpleShip__recheckAbleDropAnchor, 'checkAnchor') elif self.isAtOpenPort(): self.shipStatusDisplay.enableAnchorButton() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.tellWrongPort() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.hideWrongPort() def _addRepairSpotModels(self): if not self._repairSpotWoodPile: self._repairSpotWoodPile = loader.loadModel('models/props/repair_spot_wood') collFloors = self._repairSpotWoodPile.find('**/collision_floor') if not collFloors.isEmpty(): collideMask = collFloors.getCollideMask() collideMask ^= PiratesGlobals.FloorBitmask collideMask |= PiratesGlobals.ShipFloorBitmask collFloors.setCollideMask(collideMask) for locIndex in PVPGlobals.ShipClass2repairLocators[self.modelClass].getValue(): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] self._repairSpotWoodPiles[locName] = self.getModelRoot().attachNewNode('repairSpotWoodPile-%s' % locName) self._repairSpotWoodPile.instanceTo(self._repairSpotWoodPiles[locName]) locator = self.getLocator(locName) self._repairSpotWoodPiles[locName].setPosHpr(locator.getPos(), locator.getHpr()) def _removeRepairSpotModels(self): for woodPile in self._repairSpotWoodPiles.itervalues(): woodPile.detachNode() self._repairSpotWoodPiles = { } def _placeRepairSpotModel(self, locIndex, model): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] parentNode = self.getModelRoot().attachNewNode('repairSpotHole-%s' % locName) parentNode.setTransparency(1, 100) model.instanceTo(parentNode) locator = self.getLocator(locName) parentNode.setPosHpr(locator.getPos(), locator.getHpr()) self._repairSpotHoles[locIndex] = parentNode def _removeRepairSpotModel(self, locIndex): if locIndex in self._repairSpotHoles: self._repairSpotHoles[locIndex].detachNode() del self._repairSpotHoles[locIndex] def _fadeOutRepairSpotModel(self, locIndex): if locIndex in self._repairSpotIvals: self._repairSpotIvals[locIndex].pause() self._repairSpotHoles[locIndex].setTransparency(1, 100) ival = IG.Sequence(IG.Wait(DistributedPlayerSimpleShip.RepairSpotFadeAfter), IG.LerpColorScaleInterval(self._repairSpotHoles[locIndex], DistributedPlayerSimpleShip.RepairSpotFadeDur, Vec4(1.0, 1.0, 1.0, 0.0), blendType = 'easeInOut')) ival.start() self._repairSpotIvals[locIndex] = ival def _addRepairSpotHoles(self): if not self._repairSpotHole: repairSpotHoleModels = loader.loadModel('models/props/repair_spot_hole') self._repairSpotHole = repairSpotHoleModels.find('**/floor_hole') self._repairSpotHoleFixed = repairSpotHoleModels.find('**/floor_hole_fixed') for locIndex in PVPGlobals.ShipClass2repairLocators[self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) self._placeRepairSpotModel(locIndex, self._repairSpotHole) def _removeRepairSpotHoles(self): for locIndex in PVPGlobals.ShipClass2repairLocators[self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) if self._repairSpotHoleFixed: self._placeRepairSpotModel(locIndex, self._repairSpotHoleFixed) self._fadeOutRepairSpotModel(locIndex) self._repairSpotIvals[locIndex] = IG.Sequence(self._repairSpotIvals[locIndex], IG.Func(self._removeRepairSpotModel, locIndex)) def b_setAllowCrewState(self, state): self.d_setAllowCrewState(state) self.setAllowCrewState(state) def b_setAllowFriendState(self, state): self.d_setAllowFriendState(state) self.setAllowFriendState(state) def b_setAllowGuildState(self, state): self.d_setAllowGuildState(state) self.setAllowGuildState(state) def b_setAllowPublicState(self, state): self.d_setAllowPublicState(state) self.setAllowPublicState(state) def d_setAllowCrewState(self, state): self.sendUpdate('setAllowCrewState', [ state]) def d_setAllowFriendState(self, state): self.sendUpdate('setAllowFriendState', [ state]) def d_setAllowGuildState(self, state): self.sendUpdate('setAllowGuildState', [ state]) def d_setAllowPublicState(self, state): self.sendUpdate('setAllowPublicState', [ state]) def setAllowCrewState(self, state): self.allowCrewState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowCrew(state) def setAllowFriendState(self, state): self.allowFriendState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowFriends(state) def setAllowGuildState(self, state): self.allowGuildState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowGuild(state) def setAllowPublicState(self, state): self.allowPublicState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowPublic(state) def getAllowCrewState(self): return self.allowCrewState def getAllowFriendState(self): return self.allowFriendState def getAllowGuildState(self): return self.allowGuildState def getAllowPublicState(self): return self.allowPublicState def hasSpace(self, avId = 0, bandMgrId = 0, bandId = 0, guildId = 0): if avId == self.ownerId: return True if self.isInCrew(avId): return True if self.isInCrew(self.ownerId) and len(self.crew) >= self.maxCrew: return False if len(self.crew) >= self.maxCrew - 1: return False return True def confirmSameCrewTeleport(self, toFrom, incomingAvId = 0, bandMgrId = 0, bandId = 0, guildId = 0): if toFrom == 'from': return True elif not self.isGenerated(): self.notify.warning('confirmSameCrewTeleport(%s)' % localAvatar.getShipString()) return False if incomingAvId == self.ownerId: return True if bandMgrId and bandId and self.getAllowCrewState() and (bandMgrId, bandId) == self.getBandId(): return True if localAvatar.doId == self.ownerId and self.getAllowFriendState() and self.cr.identifyFriend(incomingAvId): return True if guildId and self.getAllowGuildState() and guildId == self.getGuildId(): return True if self.getAllowPublicState(): return True return False confirmSameCrewTeleport = report(types = [ 'frameCount', 'deltaStamp', 'args'], dConfigParam = 'shipboard')(confirmSameCrewTeleport) def getMinimapObject(self): if not (self.minimapObj) and not self.isDisabled(): self.minimapObj = MinimapPlayerShip(self) return self.minimapObj def setTeam(self, team): if not self._verifyTeam(team): return None DistributedSimpleShip.setTeam(self, team) def _verifyTeam(self, team): if team == PiratesGlobals.INVALID_TEAM: doId = '<no doId>' if hasattr(self, 'doId'): doId = self.doId else: self.badInitTeam = team base.cr.centralLogger.writeClientEvent('bad ship team: %s' % doId) self.notify.warning('bad ship team: %s' % doId) return False return True def d_setLocation(self, parentId, zoneId): theStack = StackTrace(start = 1) if self.prevLocStack and len(theStack.trace) == len(self.prevLocStack.trace) and map(lambda x: x[1], theStack.trace) == map(lambda x: x[1], self.prevLocStack.trace): base.cr.centralLogger.writeClientEvent('bad ship team: %s setLoc' % self.doId) else: base.cr.centralLogger.writeClientEvent('bad ship team: %s' % self.doId + theStack.compact()[1:len(theStack.compact())]) self.prevLocStack = theStack DistributedSimpleShip.d_setLocation(self, parentId, zoneId)
class DistributedCogdoInterior(DistributedObject.DistributedObject): id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_close.ogg') self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0) self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 self.BottomFloor_SuitPositions = [Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0)] self.BottomFloor_SuitHs = [75, 170, -91, -44] self.Cubicle_SuitPositions = [Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0)] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0)] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1) self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loadMusic('phase_7/audio/bgm/encntr_toon_winning_indoor.ogg') self.elevatorMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.ogg') self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game', 'BattleIntro', 'BarrelRoomIntro']), State.State('Game', self.enterGame, self.exitGame, ['Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro', 'Elevator']), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle'])], 'Off', 'Off') self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall(self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall(self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def getFOType(self): return self.FOType def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return name + '%d' % DistributedCogdoInterior.id def generate(self): DistributedObject.DistributedObject.generate(self) self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) self.elevatorModelIn = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left_door') self.rightDoorIn = self.elevatorModelIn.find('**/right_door') self.elevatorModelOut = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevator') self.leftDoorOut = self.elevatorModelOut.find('**/left_door') self.rightDoorOut = self.elevatorModelOut.find('**/right_door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning('No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons') random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): npc = elevatorModel.findAllMatches('**/floor_light_?;+s') for i in xrange(npc.getNumPaths()): np = npc.getPath(i) np.setDepthOffset(120) floor = int(np.getName()[-1:]) - 1 if floor == self.currentFloor: np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors() + (1 if self.FOType != "s" else 0): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find('**/floor_light_%s' % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals['alertElevatorLight'] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval('alertElevatorLight') self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_door.ogg') self.cageLowerSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg') self.sendUpdate('setAvatarJoined', []) def disable(self): self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): return self.layout.hasBossBattle() and (self.layout.getBossBattleFloor() + 0) == floorNum def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] if self.elevatorModelIn != None: self.elevatorModelIn.removeNode() if self.elevatorModelOut != None: self.elevatorModelOut.removeNode() if self.floorModel != None: self.floorModel.removeNode() if self.cage != None: self.cage = None if self.barrelRoom != None: self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected = 0): if self.toons.count(toon) == 1: self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] if interval.isPlaying(): interval.finish() def __cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if toonId != 0: if toonId in self.cr.doId2do: toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if oldtoons.count(toon) == 0: self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if self.toons.count(toon) == 0: self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.suits.append(suit) suit.fsm.request('Battle') suit.buildingSuit = 1 suit.reparentTo(render) if oldsuits.count(suit) == 0: self.joiningReserves.append(suit) if 'Elevator' in repr(self.fsm): # Fix the position. pos, h = BattleBase.BattleBase.suitPoints[len(suitIds) - 1][suitIds.index(suitId)] suit.setPos(pos) suit.setH(h) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] for index in xrange(len(reserveIds)): suitId = reserveIds[index] if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if len(self.joiningReserves) > 0: self.fsm.request('ReservesJoining') def setState(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash = True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() def d_elevatorDone(self): self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): self.sendUpdate('reserveJoinDone', []) def enterOff(self, ts = 0): messenger.send('sellbotFieldOfficeChanged', [False]) return None def exitOff(self): return None def enterWaitForAllToonsInside(self, ts = 0): base.transitions.fadeOut(0) def exitWaitForAllToonsInside(self): return None def enterGame(self, ts = 0): base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) def __playElevator(self, ts, name, callback): SuitHs = [] SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if self.currentFloor == 0: SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): self.notify.info('__playElevator: currentFloor %s is boss' % self.currentFloor) self.barrelRoom.unload() if self.FOType: penthouseName = SUITE_DICT.get(self.FOType) for i in xrange(4): self.floorModel = loader.loadModel('phase_5/models/cogdominium/%s' % penthouseName) self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in xrange(4): paintingModel = loader.loadModel('phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) if not self.floorModel.find('**/trophyCase').isEmpty(): for i in xrange(4): goldEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam') loc = self.floorModel.find('**/gold_0%d' % (i + 1)) goldEmblem.reparentTo(loc) for i in xrange(20): silverEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') loc = self.floorModel.find('**/silver_0%d' % (i + 1)) silverEmblem.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.info('Load boss_suit_office') elevIn = self.floorModel.find(CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find(CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) self.elevatorModelOut.setY(0) else: elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded() and self.currentFloor == 2 and self.FOType == 'l': #i know this is really ugly elevIn = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath) elevOut = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: floorModel = loader.loadModel('phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn self.elevOut = elevOut self._haveEntranceElevator.set(True) for index in xrange(len(self.suits)): if not self.suits[index].isEmpty(): self.suits[index].setPos(SuitPositions[index]) if len(self.suits) > 2: self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH(170) self.suits[index].loop('neutral') for toon in self.toons: toon.reparentTo(self.elevatorModelIn) index = self.toonIds.index(toon.doId) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') self.elevatorModelIn.reparentTo(elevIn) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) base.playMusic(self.elevatorMusic, looping=1, volume=0.8) track = Sequence(Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render)) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts = 0): if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: if self.FOType == 's': self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) def __setupBarrelRoom(self): self.currentFloor += 1 base.transitions.irisOut(0.0) self.elevatorModelOut.setY(-12) self.elevatorModelIn.reparentTo(self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) self.setElevatorLights(self.elevatorModelOut) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts = 0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval() self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) self._movie = CogdoBarrelRoomIntro() self._movie.load() self._movie.play() else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts = 0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) base.localAvatar.questMap.stop() def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task = None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) self.fsm.request('Battle') def enterBarrelRoomReward(self, ts = 0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi(callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts = 0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() def __playCloseElevatorOut(self, name, delay = 0): track = Sequence(Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel(SoundInterval(self.closeSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'))) track.start() self.activeIntervals[name] = track def enterBattle(self, ts = 0): if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): self.elevatorModelOut.reparentTo(self.elevOut) self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def exitBattle(self): if self.elevatorOutOpen == 1: self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 def __playReservesJoining(self, ts, name, callback): index = 0 for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos(self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') track = Sequence(Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0)), Parallel(SoundInterval(self.openSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME), Func(camera.wrtReparentTo, render), Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts = 0): self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) def __handleReserveJoinDone(self): self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) def enterResting(self, ts = 0): self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -22, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() def enterReward(self, ts = 0): if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug('exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None def enterFailed(self, ts = 0): self.exitCogdoBuilding() def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = {'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId} messenger.send('DSIDoneEvent', [request]) def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in xrange(len(self.toons)): goldBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in xrange(numFloors): silverBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') if self.FOType == 'l': speech = TTLocalizer.CogdoExecutiveSuiteToonThankYouLawbot else: speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append(Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel(self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel(self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether(self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed = None): self.shopOwnerNpc.setChatAbsolute(TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel(Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, settings['fov']))) track.start() self.penthouseOutroChatDoneTrack = track
class SCTerminal(SCElement): def __init__(self, linkedEmote = None): SCElement.__init__(self) self.setLinkedEmote(linkedEmote) scGui = loader.loadModel(SCMenu.GuiModelName) self.emotionIcon = scGui.find('**/emotionIcon') self.setDisabled(False) self.__numCharges = -1 self._handleWhisperModeSV = StateVar(False) self._handleWhisperModeFC = None return def destroy(self): self._handleWhisperModeSV.set(False) if self._handleWhisperModeFC: self._handleWhisperModeFC.destroy() self._handleWhisperModeSV.destroy() SCElement.destroy(self) def privSetSettingsRef(self, settingsRef): SCElement.privSetSettingsRef(self, settingsRef) if self._handleWhisperModeFC is None: self._handleWhisperModeFC = FunctionCall(self._handleWhisperModeSVChanged, self._handleWhisperModeSV) self._handleWhisperModeFC.pushCurrentState() self._handleWhisperModeSV.set(self.settingsRef is not None and not self.isWhisperable()) return def _handleWhisperModeSVChanged(self, handleWhisperMode): if handleWhisperMode: self._wmcListener = DirectObject() self._wmcListener.accept(self.getEventName(SCWhisperModeChangeEvent), self._handleWhisperModeChange) elif hasattr(self, '_wmcListener'): self._wmcListener.ignoreAll() del self._wmcListener self.invalidate() def _handleWhisperModeChange(self, whisperMode): self.invalidate() def handleSelect(self): messenger.send(self.getEventName(SCTerminalSelectedEvent)) if self.hasLinkedEmote() and self.linkedEmoteEnabled(): messenger.send(self.getEventName(SCTerminalLinkedEmoteEvent), [self.linkedEmote]) def isWhisperable(self): return True def getLinkedEmote(self): return self.linkedEmote def setLinkedEmote(self, linkedEmote): self.linkedEmote = linkedEmote self.invalidate() def hasLinkedEmote(self): return self.linkedEmote is not None def linkedEmoteEnabled(self): if Emote.globalEmote: return Emote.globalEmote.isEnabled(self.linkedEmote) def getCharges(self): return self.__numCharges def setCharges(self, nCharges): self.__numCharges = nCharges if nCharges is 0: self.setDisabled(True) def isDisabled(self): return self.__disabled or self.isWhispering() and not self.isWhisperable() def setDisabled(self, bDisabled): self.__disabled = bDisabled def onMouseClick(self, event): if not self.isDisabled(): SCElement.onMouseClick(self, event) self.handleSelect() def getMinDimensions(self): width, height = SCElement.getMinDimensions(self) if self.hasLinkedEmote(): width += 1.3 return (width, height) def finalize(self, dbArgs = {}): if not self.isDirty(): return args = {} if self.hasLinkedEmote(): self.lastEmoteIconColor = self.getEmoteIconColor() self.emotionIcon.setColorScale(*self.lastEmoteIconColor) args.update({'image': self.emotionIcon, 'image_pos': (self.width - 0.6, 0, -self.height * 0.5)}) if self.isDisabled(): args.update({'rolloverColor': (0, 0, 0, 0), 'pressedColor': (0, 0, 0, 0), 'rolloverSound': None, 'clickSound': None, 'text_fg': self.getColorScheme().getTextDisabledColor() + (1,)}) args.update(dbArgs) SCElement.finalize(self, dbArgs=args) return def getEmoteIconColor(self): if self.linkedEmoteEnabled() and not self.isWhispering(): r, g, b = self.getColorScheme().getEmoteIconColor() else: r, g, b = self.getColorScheme().getEmoteIconDisabledColor() return (r, g, b, 1) def updateEmoteIcon(self): if hasattr(self, 'button'): self.lastEmoteIconColor = self.getEmoteIconColor() for i in range(self.button['numStates']): self.button['image%s_image' % i].setColorScale(*self.lastEmoteIconColor) else: self.invalidate() def enterVisible(self): SCElement.enterVisible(self) if hasattr(self, 'lastEmoteIconColor'): if self.getEmoteIconColor() != self.lastEmoteIconColor: self.invalidate() def handleWhisperModeChange(whisperMode, self = self): if self.hasLinkedEmote(): if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() self.accept(self.getEventName(SCWhisperModeChangeEvent), handleWhisperModeChange) def handleEmoteEnableStateChange(self = self): if self.hasLinkedEmote(): if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() if self.hasLinkedEmote(): if Emote.globalEmote: self.accept(Emote.globalEmote.EmoteEnableStateChanged, handleEmoteEnableStateChange) def exitVisible(self): SCElement.exitVisible(self) self.ignore(self.getEventName(SCWhisperModeChangeEvent)) if Emote.globalEmote: self.ignore(Emote.globalEmote.EmoteEnableStateChanged) def getDisplayText(self): if self.getCharges() is not -1: return self.text + ' (%s)' % self.getCharges() else: return self.text
class DistributedPlayerSimpleShip(DistributedSimpleShip): RepairSpotFadeAfter = 2.0 RepairSpotFadeDur = 3.0 def __init__(self, cr): DistributedSimpleShip.__init__(self, cr) self._respawnLocation = None self.checkAnchor = None self.lastAttacked = None self.threatLevel = 0 self.openPort = 0 self.allowCrewState = True self.allowFriendState = True self.allowGuildState = False self.allowPublicState = False self._repairSpotMgr = ShipRepairSpotMgr(self.cr) self._team = PiratesGlobals.PLAYER_TEAM self.badInitTeam = None self.prevLocStack = None self.customHull = 0 self.customRigging = 0 self.customSailPattern = 0 self.customSailLogo = 0 self.customProw = 0 self.customCannon = 0 self.boardingPanel = None def generate(self): DistributedSimpleShip.generate(self) self._repairSpotWoodPile = None self._repairSpotWoodPiles = {} self._repairSpotHole = None self._repairSpotHoleFixed = None self._repairSpotHoles = {} self._repairSpotIvals = {} self._wheelInUse = StateVar(False) def announceGenerate(self): self._respawnLocation = None self._respawnResponseDelayedCall = None DistributedSimpleShip.announceGenerate(self) self._repairSpotMgr.setShipId(self.doId) if self.badInitTeam != None: self._verifyTeam(self.badInitTeam) def disable(self): if self.boardingPanel: self.boardingPanel.destroy() self.boardingPanel = None self._wheelInUse.destroy() if self._respawnResponseDelayedCall: self._respawnResponseDelayedCall.destroy() self._respawnResponseDelayedCall = None if self.checkAnchor: self.checkAnchor.remove() self.checkAnchor = None self._repairSpotMgr.destroy() for ival in self._repairSpotIvals.itervalues(): ival.pause() self._repairSpotIvals = None self.prevLocStack = None self.prevLocStack = None DistributedSimpleShip.disable(self) def calculateLook(self): team = self.getTeam() if team == PiratesGlobals.PLAYER_TEAM: if self.getSiegeTeam() == 1: self.style = ShipGlobals.Styles.French elif self.getSiegeTeam() == 2: self.style = ShipGlobals.Styles.Spanish def loadStats(self): DistributedSimpleShip.loadStats(self) speedUpgrade = 1.0 turningUpgrade = 1.0 if self.customHull: speedUpgrade = ShipUpgradeGlobals.HULL_TYPES[ self.customHull]['Speed'] turningUpgrade = ShipUpgradeGlobals.HULL_TYPES[ self.customHull]['Turning'] self.setSpeedMods(baseMod=None, speedUpgradeMod=speedUpgrade, turnUpgradeMod=turningUpgrade) def setShipUpfitList(self, dataList): counter = 0 while dataList: newData = dataList[0] dataList = dataList[1:] if counter == 0: self.customHull = newData elif counter == 1: self.customRigging = newData elif counter == 2: self.customSailPattern = newData elif counter == 3: self.customSailLogo = newData counter += 1 self.setupLocalStats() messenger.send('ShipChanged-%s' % self.doId) def getSkillBoost(self, skillId): if self.customRigging: riggingInfo = ShipUpgradeGlobals.RIGGING_TYPES.get( self.customRigging) boostLevel = ShipUpgradeGlobals.RIGGING_TYPES.get( self.customRigging, {}).get('SkillBoosts', {}).get(skillId, 0) return boostLevel return 0 def buildShip(self): hullMaterial = None sailMaterial = None sailPattern = None invertLogo = False logo = ShipGlobals.Logos.Undefined if self.customHull: hullType = ShipUpgradeGlobals.HULL_TYPES.get(self.customHull) if hullType: hullMaterial = hullType['StyleIndex'] if self.customRigging: riggingType = ShipUpgradeGlobals.RIGGING_TYPES.get( self.customRigging) if riggingType: sailMaterial = riggingType['StyleIndex'] if self.customSailPattern: patternType = ShipUpgradeGlobals.SAILCOLOR_TYPES.get( self.customSailPattern) if patternType: sailPattern = patternType['StyleIndex'] logo = self.getLogo() if self.customSailLogo: logoType = ShipUpgradeGlobals.LOGO_TYPES.get(self.customSailLogo) if logoType: logo = logoType['StyleIndex'] invertLogo = logoType['Invert'] team = self.getTeam() if team == PiratesGlobals.PLAYER_TEAM: if self.getSiegeTeam() == 1: sailPattern = ShipGlobals.Styles.French elif self.getSiegeTeam() == 2: sailPattern = ShipGlobals.Styles.Spanish self.model = base.shipFactory.getShip( self.shipClass, self.getStyle(), detailLevel=base.options.terrain_detail_level, hullMaterial=hullMaterial, sailMaterial=sailMaterial, sailPattern=sailPattern, logo=logo, invertLogo=invertLogo) def getNPCship(self): return False def setShipClass(self, shipClass): DistributedSimpleShip.setShipClass(self, shipClass) self._repairSpotMgr.updateShipClass(self.shipClass) def setHealthState(self, health): DistributedSimpleShip.setHealthState(self, health) self._repairSpotMgr.updateHealth(self.healthState) def setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast): DistributedSimpleShip.setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast) self._repairSpotMgr.updateSpeed(100.0 * self.Sp / self.maxSp) def setArmorStates(self, rear, left, right): DistributedSimpleShip.setArmorStates(self, rear, left, right) self._repairSpotMgr.updateArmor((rear + left + right) / 3.0) def setWillFullyRepairShip(self, willFullyRepairShip): self._repairSpotMgr.updateWillBeFullHealth(willFullyRepairShip) def setupLocalStats(self): DistributedSimpleShip.setupLocalStats(self) if self.customHull: tempArmorState = [ 100.0 * self.armor[0] / self.maxArmor[0], 100.0 * self.armor[1] / self.maxArmor[1], 100.0 * self.armor[2] / self.maxArmor[2] ] tempHealthState = 100.0 * self.Hp / self.maxHp tempMastState = [] for mastIndex in range(len(self.maxMastHealth)): if self.maxMastHealth[mastIndex] > 0.0: tempMastState.append(100.0 * self.mastHealth[mastIndex] / self.maxMastHealth[mastIndex]) continue tempMastState.append(0.0) armorUpgrade = ShipUpgradeGlobals.HULL_TYPES[ self.customHull]['Armor'] self.maxHp *= armorUpgrade self.Hp *= armorUpgrade newArmor = [] for entry in self.maxArmor: newArmor.append(entry * armorUpgrade) self.maxArmor = newArmor newMastHealth = [] for entry in self.maxMastHealth: newMastHealth.append(entry * armorUpgrade) self.maxMastHealth = newMastHealth self.maxSp *= armorUpgrade cargoUpgrade = ShipUpgradeGlobals.HULL_TYPES[ self.customHull]['Cargo'] self.setMaxCargo(int(cargoUpgrade * self.maxCargo)) def setOpenPort(self, portId): oldPort = self.openPort self.openPort = portId if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId(): messenger.send('LocalAvatar_Ship_OpenPort_Update', [portId, oldPort]) def getOpenPort(self): return self.openPort def isAtOpenPort(self): portDoId = localAvatar.getPort() portObj = base.cr.doId2do.get(portDoId, None) if self.threatLevel < EnemyGlobals.SHIP_THREAT_NAVY_HUNTERS: return 1 elif portObj and portObj.uniqueId == EnemyGlobals.OPEN_PORT_DICT.get( self.openPort): return 1 else: return 0 def setThreatLevel(self, threatLevel): if threatLevel != self.threatLevel: self.threatLevel = threatLevel self.updateNametag() if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId( ): messenger.send('LocalAvatar_Ship_ThreatLevel_Update', [threatLevel]) self.checkAbleDropAnchor() def getThreatLevel(self): if base.config.GetBool('want-ship-threat', 1): return self.threatLevel else: return EnemyGlobals.SHIP_THREAT_ATTACK_BACK def getOpenPort(self): return self.openPort def sunkAShipFanfare(self, shipToAttackDoId): if localAvatar.ship and localAvatar.ship == self: if localAvatar.ship.getSiegeTeam(): return None attackMessage = HighSeasGlobals.getShipSunkMessage() if attackMessage: base.localAvatar.guiMgr.queueInstructionMessage( attackMessage[0], attackMessage[1], None, 1.0, messageCategory=MessageGlobals.MSG_CAT_SUNK_SHIP) def setSiegeTeam(self, team): different = team != self.getSiegeTeam() DistributedSimpleShip.setSiegeTeam(self, team) if different: self._doSiegeAndPVPTeamColors() self._repairSpotMgr.updateSiegeTeam(team) minimapObj = self.getMinimapObject() if minimapObj: minimapObj.setSiegeTeam(team) setSiegeTeam = report(types=['args'], dConfigParam='shipdeploy')(setSiegeTeam) def _doSiegeAndPVPTeamColors(self): if self.getPVPTeam(): self._doPVPTeamColors() elif self.getSiegeTeam(): pass def _doPVPTeamColors(self): pass def getWheelInUseSV(self): return self._wheelInUse def setWheelInUse(self, wheelInUse): DistributedSimpleShip.setWheelInUse(self, wheelInUse) self._wheelInUse.set(wheelInUse) def canTakeWheel(self, wheel, av): available = True if self.queryGameState() in ('Pinned', 'Sinking', 'Sunk', 'OtherShipBoarded'): base.localAvatar.guiMgr.createWarning(PLocalizer.ShipPinnedWarning, PiratesGuiGlobals.TextFG6) available = False elif self.isFishing and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning( PLocalizer.OnlyCaptainCanUseWarning, PiratesGuiGlobals.TextFG6) available = False elif wheel.getUserId() and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning( PLocalizer.AlreadyInUseWarning, PiratesGuiGlobals.TextFG6) available = False return available def setRespawnLocation(self, parentId, zoneId): self._respawnLocation = (parentId, zoneId) def setLocation(self, parentId, zoneId): DistributedSimpleShip.setLocation(self, parentId, zoneId) if self._respawnLocation is not None and self._respawnLocation == ( parentId, zoneId): self.updateCurrentZone() self._respawnLocation = None if not self._respawnResponseDelayedCall: self._respawnResponseDelayedCall = FrameDelayedCall( 'PlayerShip-respawnLocation-gridInterestComplete', Functor(base.cr.setAllInterestsCompleteCallback, self._sendRespawnLocationResponse)) def _sendRespawnLocationResponse(self): self.sendUpdate('clientReachedRespawnLocation') self._respawnResponseDelayedCall = None def recoverFromSunk(self): self.lastAttacked = None DistributedSimpleShip.recoverFromSunk(self) def attacked(self): self.lastAttacked = globalClock.getFrameTime() if self.getSiegeTeam() and not (self.checkAnchor): self.checkAbleDropAnchor() def attackTimerRemaining(self): timer = 0 if self.lastAttacked: timer = int(30 - globalClock.getFrameTime() - self.lastAttacked) return timer def _DistributedPlayerSimpleShip__recheckAbleDropAnchor(self, task): self.checkAnchor = None self.checkAbleDropAnchor() def checkAbleDropAnchor(self): PiratesGuiGlobals = PiratesGuiGlobals import pirates.piratesgui if localAvatar.doId == self.steeringAvId: if self.shipStatusDisplay: if localAvatar.getPort(): remaining = self.attackTimerRemaining() if self.getSiegeTeam() and remaining > 0: self.shipStatusDisplay.disableAnchorButton() localAvatar.guiMgr.createWarning( PLocalizer.CannotDockYet % remaining, PiratesGuiGlobals.TextFG6) self.checkAnchor = taskMgr.doMethodLater( remaining, self. _DistributedPlayerSimpleShip__recheckAbleDropAnchor, 'checkAnchor') elif self.isAtOpenPort(): self.shipStatusDisplay.enableAnchorButton() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.tellWrongPort() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.hideWrongPort() def _addRepairSpotModels(self): if not self._repairSpotWoodPile: self._repairSpotWoodPile = loader.loadModel( 'models/props/repair_spot_wood') collFloors = self._repairSpotWoodPile.find('**/collision_floor') if not collFloors.isEmpty(): collideMask = collFloors.getCollideMask() collideMask ^= PiratesGlobals.FloorBitmask collideMask |= PiratesGlobals.ShipFloorBitmask collFloors.setCollideMask(collideMask) for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] self._repairSpotWoodPiles[locName] = self.getModelRoot( ).attachNewNode('repairSpotWoodPile-%s' % locName) self._repairSpotWoodPile.instanceTo( self._repairSpotWoodPiles[locName]) locator = self.getLocator(locName) self._repairSpotWoodPiles[locName].setPosHpr( locator.getPos(), locator.getHpr()) def _removeRepairSpotModels(self): for woodPile in self._repairSpotWoodPiles.itervalues(): woodPile.detachNode() self._repairSpotWoodPiles = {} def _placeRepairSpotModel(self, locIndex, model): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] parentNode = self.getModelRoot().attachNewNode('repairSpotHole-%s' % locName) parentNode.setTransparency(1, 100) model.instanceTo(parentNode) locator = self.getLocator(locName) parentNode.setPosHpr(locator.getPos(), locator.getHpr()) self._repairSpotHoles[locIndex] = parentNode def _removeRepairSpotModel(self, locIndex): if locIndex in self._repairSpotHoles: self._repairSpotHoles[locIndex].detachNode() del self._repairSpotHoles[locIndex] def _fadeOutRepairSpotModel(self, locIndex): if locIndex in self._repairSpotIvals: self._repairSpotIvals[locIndex].pause() self._repairSpotHoles[locIndex].setTransparency(1, 100) ival = IG.Sequence( IG.Wait(DistributedPlayerSimpleShip.RepairSpotFadeAfter), IG.LerpColorScaleInterval( self._repairSpotHoles[locIndex], DistributedPlayerSimpleShip.RepairSpotFadeDur, Vec4(1.0, 1.0, 1.0, 0.0), blendType='easeInOut')) ival.start() self._repairSpotIvals[locIndex] = ival def _addRepairSpotHoles(self): if not self._repairSpotHole: repairSpotHoleModels = loader.loadModel( 'models/props/repair_spot_hole') self._repairSpotHole = repairSpotHoleModels.find('**/floor_hole') self._repairSpotHoleFixed = repairSpotHoleModels.find( '**/floor_hole_fixed') for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) self._placeRepairSpotModel(locIndex, self._repairSpotHole) def _removeRepairSpotHoles(self): for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) if self._repairSpotHoleFixed: self._placeRepairSpotModel(locIndex, self._repairSpotHoleFixed) self._fadeOutRepairSpotModel(locIndex) self._repairSpotIvals[locIndex] = IG.Sequence( self._repairSpotIvals[locIndex], IG.Func(self._removeRepairSpotModel, locIndex)) continue def b_setAllowCrewState(self, state): self.d_setAllowCrewState(state) self.setAllowCrewState(state) def b_setAllowFriendState(self, state): self.d_setAllowFriendState(state) self.setAllowFriendState(state) def b_setAllowGuildState(self, state): self.d_setAllowGuildState(state) self.setAllowGuildState(state) def b_setAllowPublicState(self, state): self.d_setAllowPublicState(state) self.setAllowPublicState(state) def d_setAllowCrewState(self, state): self.sendUpdate('setAllowCrewState', [state]) def d_setAllowFriendState(self, state): self.sendUpdate('setAllowFriendState', [state]) def d_setAllowGuildState(self, state): self.sendUpdate('setAllowGuildState', [state]) def d_setAllowPublicState(self, state): self.sendUpdate('setAllowPublicState', [state]) def setAllowCrewState(self, state): self.allowCrewState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowCrew(state) def setAllowFriendState(self, state): self.allowFriendState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowFriends(state) def setAllowGuildState(self, state): self.allowGuildState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowGuild(state) def setAllowPublicState(self, state): self.allowPublicState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowPublic(state) def getAllowCrewState(self): return self.allowCrewState def getAllowFriendState(self): return self.allowFriendState def getAllowGuildState(self): return self.allowGuildState def getAllowPublicState(self): return self.allowPublicState def hasSpace(self, avId=0, bandMgrId=0, bandId=0, guildId=0): if avId == self.ownerId: return True if self.isInCrew(avId): return True if self.isInCrew(self.ownerId) and len(self.crew) >= self.maxCrew: return False if len(self.crew) >= self.maxCrew - 1: return False return True def confirmSameCrewTeleport(self, toFrom, incomingAvId=0, bandMgrId=0, bandId=0, guildId=0): if toFrom == 'from': return True elif not self.isGenerated(): self.notify.warning('confirmSameCrewTeleport(%s)' % localAvatar.getShipString()) return False if incomingAvId == self.ownerId: return True if bandMgrId and bandId and self.getAllowCrewState() and ( bandMgrId, bandId) == self.getBandId(): return True if localAvatar.doId == self.ownerId and self.getAllowFriendState( ) and self.cr.identifyFriend(incomingAvId): return True if guildId and self.getAllowGuildState( ) and guildId == self.getGuildId(): return True if self.getAllowPublicState(): return True return False confirmSameCrewTeleport = report( types=['frameCount', 'deltaStamp', 'args'], dConfigParam='shipboard')(confirmSameCrewTeleport) def localPirateArrived(self, av): DistributedSimpleShip.localPirateArrived(self, av) self.enableOnDeckInteractions() mapObj = self.getMinimapObject() if mapObj: mapObj.setAsLocalAvShip(av.getCrewShipId() == self.doId) def showBoardingChoice(self, shipToBoard): if not self.boardingPanel: shipInfo = shipToBoard.getShipInfo() globalClockDelta = globalClockDelta import direct.distributed.ClockDelta dt = globalClockDelta.localElapsedTime(shipToBoard.sinkTimestamp) time = shipToBoard.sinkTime - dt self.boardingPanel = ShipFrameBoard.ShipFrameBoard( shipName=shipInfo[1], shipClass=shipInfo[2], mastInfo=shipInfo[3], parent=base.a2dTopCenter, pos=(-0.45000000000000001, 0, -0.5), time=time, command=self._DistributedPlayerSimpleShip__handleBoardingChoice ) self._boardingTimer = taskMgr.doMethodLater( time, self._boardingChoiceTimeout, 'boardingTimer') self.boardingPanel.show() def _boardingChoiceTimeout(self, task): self.removeBoardingChoice() def hideBoardingChoice(self): if self.boardingPanel: self.boardingPanel.hide() def removeBoardingChoice(self): if self.boardingPanel: self.boardingPanel.destroy() self.boardingPanel = None if self._boardingTimer: self._boardingTimer.remove() self._boardingTimer = None def _DistributedPlayerSimpleShip__handleBoardingChoice(self, wishToBoard): self.removeBoardingChoice() self.d_setBoardingChoice(int(wishToBoard)) def d_setBoardingChoice(self, choice): self.sendUpdate('setBoardingChoice', [choice]) def getMinimapObject(self): if not (self.minimapObj) and not self.isDisabled(): self.minimapObj = MinimapPlayerShip(self) return self.minimapObj def setTeam(self, team): if not self._verifyTeam(team): return None DistributedSimpleShip.setTeam(self, team) def _verifyTeam(self, team): if team == PiratesGlobals.INVALID_TEAM: doId = '<no doId>' if hasattr(self, 'doId'): doId = self.doId else: self.badInitTeam = team base.cr.centralLogger.writeClientEvent('bad ship team: %s' % doId) self.notify.warning('bad ship team: %s' % doId) return False return True def d_setLocation(self, parentId, zoneId): theStack = StackTrace(start=1) if self.prevLocStack and len( theStack.trace) == len(self.prevLocStack.trace) and map( lambda x: x[1], theStack.trace) == map( lambda x: x[1], self.prevLocStack.trace): base.cr.centralLogger.writeClientEvent('bad ship team: %s setLoc' % self.doId) else: base.cr.centralLogger.writeClientEvent( 'bad ship team: %s' % self.doId + theStack.compact()[1:len(theStack.compact())]) self.prevLocStack = theStack DistributedSimpleShip.d_setLocation(self, parentId, zoneId)
class SCTerminal(SCElement): """ SCTerminal is the base class for all 'terminal' speedchat entities """ def __init__(self, linkedEmote=None): SCElement.__init__(self) self.setLinkedEmote(linkedEmote) scGui = loader.loadModel(SCMenu.GuiModelName) self.emotionIcon = scGui.find('**/emotionIcon') self.setDisabled(False) self.__numCharges = -1 # should we listen for whisper mode changes? self._handleWhisperModeSV = StateVar(False) # can't set this up until we're ready to have the handler func called self._handleWhisperModeFC = None def destroy(self): self._handleWhisperModeSV.set(False) if self._handleWhisperModeFC: self._handleWhisperModeFC.destroy() self._handleWhisperModeSV.destroy() SCElement.destroy(self) def privSetSettingsRef(self, settingsRef): SCElement.privSetSettingsRef(self, settingsRef) if self._handleWhisperModeFC is None: self._handleWhisperModeFC = FunctionCall(self._handleWhisperModeSVChanged, self._handleWhisperModeSV) self._handleWhisperModeFC.pushCurrentState() # if this terminal is not whisperable, we need to listen for whisper mode changes self._handleWhisperModeSV.set((self.settingsRef is not None) and (not self.isWhisperable())) def _handleWhisperModeSVChanged(self, handleWhisperMode): if handleWhisperMode: # this terminal can't be whispered. we need to reconstruct # our GUI element when the whisper mode changes # listen for that mode change # create a DirectObject to avoid conflicts with other parts of this # object that are listening for this event self._wmcListener = DirectObject() self._wmcListener.accept(self.getEventName(SCWhisperModeChangeEvent), self._handleWhisperModeChange) else: if hasattr(self, '_wmcListener'): # we no longer need to listen for whisper mode changes self._wmcListener.ignoreAll() del self._wmcListener # make sure our GUI element is appropriate self.invalidate() def _handleWhisperModeChange(self, whisperMode): # whisper mode changed, we need to change our GUI element self.invalidate() # the meat of SCTerminal; inheritors should override this # and perform the appropriate action def handleSelect(self): """ called when the user selects this node """ # send the generic 'something was selected' event messenger.send(self.getEventName(SCTerminalSelectedEvent)) # if we have a linked emote, and it isn't disabled, generate a msg if self.hasLinkedEmote() and self.linkedEmoteEnabled(): messenger.send(self.getEventName(SCTerminalLinkedEmoteEvent), [self.linkedEmote]) def isWhisperable(self): # can this terminal be sent as a whisper message? return True # Some terminal nodes have an emote associated with them, which # should be invoked when the node is selected. def getLinkedEmote(self): return self.linkedEmote def setLinkedEmote(self, linkedEmote): self.linkedEmote = linkedEmote # TODO: we should make sure we're listening for emote # enable state changes if this is set while we're visible self.invalidate() def hasLinkedEmote(self): return (self.linkedEmote is not None) def linkedEmoteEnabled(self): if Emote.globalEmote: return Emote.globalEmote.isEnabled(self.linkedEmote) def getCharges(self): return self.__numCharges def setCharges(self, nCharges): self.__numCharges = nCharges if (nCharges is 0): self.setDisabled(True) # support for disabled terminals def isDisabled(self): return self.__disabled or (self.isWhispering() and not self.isWhisperable()) def setDisabled(self, bDisabled): # make the button 'unclickable' self.__disabled = bDisabled # from SCElement def onMouseClick(self, event): if not self.isDisabled(): SCElement.onMouseClick(self, event) self.handleSelect() def getMinDimensions(self): width, height = SCElement.getMinDimensions(self) if self.hasLinkedEmote(): # add space for the emotion icon width += 1.3 return width, height def finalize(self, dbArgs={}): """ catch this call and influence the appearance of our button """ if not self.isDirty(): return args = {} if self.hasLinkedEmote(): self.lastEmoteIconColor = self.getEmoteIconColor() self.emotionIcon.setColorScale(*self.lastEmoteIconColor) args.update({ 'image': self.emotionIcon, 'image_pos': (self.width-.6,0,-self.height*.5), }) if self.isDisabled(): args.update({ 'rolloverColor': (0,0,0,0), 'pressedColor': (0,0,0,0), 'rolloverSound': None, 'clickSound': None, 'text_fg': self.getColorScheme().getTextDisabledColor()+(1,), }) args.update(dbArgs) SCElement.finalize(self, dbArgs=args) def getEmoteIconColor(self): if self.linkedEmoteEnabled() and (not self.isWhispering()): r,g,b = self.getColorScheme().getEmoteIconColor() else: r,g,b = self.getColorScheme().getEmoteIconDisabledColor() return (r,g,b,1) def updateEmoteIcon(self): if hasattr(self, 'button'): self.lastEmoteIconColor = self.getEmoteIconColor() for i in range(self.button['numStates']): self.button['image%s_image' % i].setColorScale( *self.lastEmoteIconColor) else: self.invalidate() # from SCObject def enterVisible(self): SCElement.enterVisible(self) # Check if the emote state has changed since the last time # we were finalized, and invalidate if it's different. if hasattr(self, 'lastEmoteIconColor'): if self.getEmoteIconColor() != self.lastEmoteIconColor: self.invalidate() # listen for whisper-mode changes def handleWhisperModeChange(whisperMode, self=self): if self.hasLinkedEmote(): # we are leaving or entering whisper mode; # the appearance of our emote icon needs to change # (no linked emotes on whispers) if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() self.accept(self.getEventName(SCWhisperModeChangeEvent), handleWhisperModeChange) # listen for emote-enable state changes def handleEmoteEnableStateChange(self=self): if self.hasLinkedEmote(): # emotions have just become enabled/disabled # update our emote icon # (no emotes when whispering) if self.isVisible() and not self.isWhispering(): self.updateEmoteIcon() if self.hasLinkedEmote(): if Emote.globalEmote: self.accept(Emote.globalEmote.EmoteEnableStateChanged, handleEmoteEnableStateChange) def exitVisible(self): SCElement.exitVisible(self) self.ignore(self.getEventName(SCWhisperModeChangeEvent)) if Emote.globalEmote: self.ignore(Emote.globalEmote.EmoteEnableStateChanged) def getDisplayText(self): if self.getCharges() is not -1: return self.text + " (%s)" % self.getCharges() else: return self.text
class DistributedPlayerSimpleShip(DistributedSimpleShip): RepairSpotFadeAfter = 2.0 RepairSpotFadeDur = 3.0 def __init__(self, cr): DistributedSimpleShip.__init__(self, cr) self._respawnLocation = None self.checkAnchor = None self.lastAttacked = None self.threatLevel = 0 self.openPort = 0 self.allowCrewState = True self.allowFriendState = True self.allowGuildState = False self.allowPublicState = False self._repairSpotMgr = ShipRepairSpotMgr(self.cr) self._team = PiratesGlobals.PLAYER_TEAM self.badInitTeam = None self.prevLocStack = None def generate(self): DistributedSimpleShip.generate(self) self._repairSpotWoodPile = None self._repairSpotWoodPiles = {} self._repairSpotHole = None self._repairSpotHoleFixed = None self._repairSpotHoles = {} self._repairSpotIvals = {} self._wheelInUse = StateVar(False) def announceGenerate(self): self._respawnLocation = None self._respawnResponseDelayedCall = None DistributedSimpleShip.announceGenerate(self) self._repairSpotMgr.setShipId(self.doId) if self.badInitTeam != None: self._verifyTeam(self.badInitTeam) def disable(self): self._wheelInUse.destroy() if self._respawnResponseDelayedCall: self._respawnResponseDelayedCall.destroy() self._respawnResponseDelayedCall = None if self.checkAnchor: self.checkAnchor.remove() self.checkAnchor = None self._repairSpotMgr.destroy() for ival in self._repairSpotIvals.itervalues(): ival.pause() del self._repairSpotIvals self.prevLocStack = None DistributedSimpleShip.disable(self) def calculateLook(self): team = self.getTeam() if team == PiratesGlobals.PLAYER_TEAM: if self.getSiegeTeam() == 1: self.style = ShipGlobals.Styles.French elif self.getSiegeTeam() == 2: self.style = ShipGlobals.Styles.Spanish def getNPCship(self): return False def setShipClass(self, shipClass): DistributedSimpleShip.setShipClass(self, shipClass) self._repairSpotMgr.updateShipClass(self.shipClass) def setHealthState(self, health): DistributedSimpleShip.setHealthState(self, health) self._repairSpotMgr.updateHealth(self.healthState) def setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast): DistributedSimpleShip.setMastStates(self, mainMast1, mainMast2, mainMast3, aftMast, foreMast) self._repairSpotMgr.updateSpeed(100.0 * self.Sp / self.maxSp) def setArmorStates(self, rear, left, right): DistributedSimpleShip.setArmorStates(self, rear, left, right) self._repairSpotMgr.updateArmor((rear + left + right) / 3.0) def setWillFullyRepairShip(self, willFullyRepairShip): self._repairSpotMgr.updateWillBeFullHealth(willFullyRepairShip) def setupLocalStats(self): DistributedSimpleShip.setupLocalStats(self) def setOpenPort(self, portId): oldPort = self.openPort self.openPort = portId if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId(): messenger.send('LocalAvatar_Ship_OpenPort_Update', [portId, oldPort]) def getOpenPort(self): return self.openPort def isAtOpenPort(self): portDoId = localAvatar.getPort() portObj = base.cr.doId2do.get(portDoId, None) if self.threatLevel < EnemyGlobals.SHIP_THREAT_NAVY_HUNTERS: return 1 elif portObj and portObj.uniqueId == EnemyGlobals.OPEN_PORT_DICT.get( self.openPort): return 1 else: return 0 def setThreatLevel(self, threatLevel): if threatLevel != self.threatLevel: self.threatLevel = threatLevel self.updateNametag() if localAvatar.ship and localAvatar.ship.getDoId() == self.getDoId( ): messenger.send('LocalAvatar_Ship_ThreatLevel_Update', [threatLevel]) self.checkAbleDropAnchor() def getThreatLevel(self): if base.config.GetBool('want-ship-threat', 1): return self.threatLevel else: return EnemyGlobals.SHIP_THREAT_ATTACK_BACK def getOpenPort(self): return self.openPort def sunkAShipFanfare(self, shipToAttackDoId): if localAvatar.ship and localAvatar.ship == self: if localAvatar.ship.getSiegeTeam(): return None attackMessage = HighSeasGlobals.getShipSunkMessage() if attackMessage: base.localAvatar.guiMgr.queueInstructionMessage( attackMessage[0], attackMessage[1], None, 1.0, messageCategory=MessageGlobals.MSG_CAT_SUNK_SHIP) def setSiegeTeam(self, team): different = team != self.getSiegeTeam() DistributedSimpleShip.setSiegeTeam(self, team) if different: self._doSiegeAndPVPTeamColors() self._repairSpotMgr.updateSiegeTeam(team) minimapObj = self.getMinimapObject() if minimapObj: minimapObj.setSiegeTeam(team) setSiegeTeam = report(types=['args'], dConfigParam='shipdeploy')(setSiegeTeam) def _doSiegeAndPVPTeamColors(self): if self.getPVPTeam(): self._doPVPTeamColors() elif self.getSiegeTeam(): pass def _doPVPTeamColors(self): pass def getWheelInUseSV(self): return self._wheelInUse def setWheelInUse(self, wheelInUse): DistributedSimpleShip.setWheelInUse(self, wheelInUse) self._wheelInUse.set(wheelInUse) def canTakeWheel(self, wheel, av): available = True if self.queryGameState() in ('Pinned', 'Sinking', 'Sunk', 'OtherShipBoarded'): base.localAvatar.guiMgr.createWarning(PLocalizer.ShipPinnedWarning, PiratesGuiGlobals.TextFG6) available = False elif self.isFishing and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning( PLocalizer.OnlyCaptainCanUseWarning, PiratesGuiGlobals.TextFG6) available = False elif wheel.getUserId() and base.localAvatar.getDoId() != self.ownerId: base.localAvatar.guiMgr.createWarning( PLocalizer.AlreadyInUseWarning, PiratesGuiGlobals.TextFG6) available = False return available def setRespawnLocation(self, parentId, zoneId): self._respawnLocation = (parentId, zoneId) def setLocation(self, parentId, zoneId): DistributedSimpleShip.setLocation(self, parentId, zoneId) if self._respawnLocation is not None and self._respawnLocation == ( parentId, zoneId): self._respawnLocation = None if not self._respawnResponseDelayedCall: self._respawnResponseDelayedCall = FrameDelayedCall( 'PlayerShip-respawnLocation-gridInterestComplete', Functor(base.cr.setAllInterestsCompleteCallback, self._sendRespawnLocationResponse)) def _sendRespawnLocationResponse(self): self.sendUpdate('clientReachedRespawnLocation') self._respawnResponseDelayedCall = None def recoverFromSunk(self): self.lastAttacked = None DistributedSimpleShip.recoverFromSunk(self) def attacked(self): self.lastAttacked = globalClock.getFrameTime() if self.getSiegeTeam() and not (self.checkAnchor): self.checkAbleDropAnchor() def attackTimerRemaining(self): timer = 0 if self.lastAttacked: timer = int(30 - globalClock.getFrameTime() - self.lastAttacked) return timer def _DistributedPlayerSimpleShip__recheckAbleDropAnchor(self, task): self.checkAnchor = None self.checkAbleDropAnchor() def checkAbleDropAnchor(self): PiratesGuiGlobals = PiratesGuiGlobals import pirates.piratesgui if localAvatar.doId == self.steeringAvId: if self.shipStatusDisplay: if localAvatar.getPort(): remaining = self.attackTimerRemaining() if self.getSiegeTeam() and remaining > 0: self.shipStatusDisplay.disableAnchorButton() localAvatar.guiMgr.createWarning( PLocalizer.CannotDockYet % remaining, PiratesGuiGlobals.TextFG6) self.checkAnchor = taskMgr.doMethodLater( remaining, self. _DistributedPlayerSimpleShip__recheckAbleDropAnchor, 'checkAnchor') elif self.isAtOpenPort(): self.shipStatusDisplay.enableAnchorButton() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.tellWrongPort() else: self.shipStatusDisplay.disableAnchorButton() self.shipStatusDisplay.hideWrongPort() def _addRepairSpotModels(self): if not self._repairSpotWoodPile: self._repairSpotWoodPile = loader.loadModel( 'models/props/repair_spot_wood') collFloors = self._repairSpotWoodPile.find('**/collision_floor') if not collFloors.isEmpty(): collideMask = collFloors.getCollideMask() collideMask ^= PiratesGlobals.FloorBitmask collideMask |= PiratesGlobals.ShipFloorBitmask collFloors.setCollideMask(collideMask) for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] self._repairSpotWoodPiles[locName] = self.getModelRoot( ).attachNewNode('repairSpotWoodPile-%s' % locName) self._repairSpotWoodPile.instanceTo( self._repairSpotWoodPiles[locName]) locator = self.getLocator(locName) self._repairSpotWoodPiles[locName].setPosHpr( locator.getPos(), locator.getHpr()) def _removeRepairSpotModels(self): for woodPile in self._repairSpotWoodPiles.itervalues(): woodPile.detachNode() self._repairSpotWoodPiles = {} def _placeRepairSpotModel(self, locIndex, model): locName = PVPGlobals.RepairSpotLocatorNames[locIndex] parentNode = self.getModelRoot().attachNewNode('repairSpotHole-%s' % locName) parentNode.setTransparency(1, 100) model.instanceTo(parentNode) locator = self.getLocator(locName) parentNode.setPosHpr(locator.getPos(), locator.getHpr()) self._repairSpotHoles[locIndex] = parentNode def _removeRepairSpotModel(self, locIndex): if locIndex in self._repairSpotHoles: self._repairSpotHoles[locIndex].detachNode() del self._repairSpotHoles[locIndex] def _fadeOutRepairSpotModel(self, locIndex): if locIndex in self._repairSpotIvals: self._repairSpotIvals[locIndex].pause() self._repairSpotHoles[locIndex].setTransparency(1, 100) ival = IG.Sequence( IG.Wait(DistributedPlayerSimpleShip.RepairSpotFadeAfter), IG.LerpColorScaleInterval( self._repairSpotHoles[locIndex], DistributedPlayerSimpleShip.RepairSpotFadeDur, Vec4(1.0, 1.0, 1.0, 0.0), blendType='easeInOut')) ival.start() self._repairSpotIvals[locIndex] = ival def _addRepairSpotHoles(self): if not self._repairSpotHole: repairSpotHoleModels = loader.loadModel( 'models/props/repair_spot_hole') self._repairSpotHole = repairSpotHoleModels.find('**/floor_hole') self._repairSpotHoleFixed = repairSpotHoleModels.find( '**/floor_hole_fixed') for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) self._placeRepairSpotModel(locIndex, self._repairSpotHole) def _removeRepairSpotHoles(self): for locIndex in PVPGlobals.ShipClass2repairLocators[ self.modelClass].getValue(): self._removeRepairSpotModel(locIndex) if self._repairSpotHoleFixed: self._placeRepairSpotModel(locIndex, self._repairSpotHoleFixed) self._fadeOutRepairSpotModel(locIndex) self._repairSpotIvals[locIndex] = IG.Sequence( self._repairSpotIvals[locIndex], IG.Func(self._removeRepairSpotModel, locIndex)) def b_setAllowCrewState(self, state): self.d_setAllowCrewState(state) self.setAllowCrewState(state) def b_setAllowFriendState(self, state): self.d_setAllowFriendState(state) self.setAllowFriendState(state) def b_setAllowGuildState(self, state): self.d_setAllowGuildState(state) self.setAllowGuildState(state) def b_setAllowPublicState(self, state): self.d_setAllowPublicState(state) self.setAllowPublicState(state) def d_setAllowCrewState(self, state): self.sendUpdate('setAllowCrewState', [state]) def d_setAllowFriendState(self, state): self.sendUpdate('setAllowFriendState', [state]) def d_setAllowGuildState(self, state): self.sendUpdate('setAllowGuildState', [state]) def d_setAllowPublicState(self, state): self.sendUpdate('setAllowPublicState', [state]) def setAllowCrewState(self, state): self.allowCrewState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowCrew(state) def setAllowFriendState(self, state): self.allowFriendState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowFriends(state) def setAllowGuildState(self, state): self.allowGuildState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowGuild(state) def setAllowPublicState(self, state): self.allowPublicState = state if self.shipStatusDisplay: self.shipStatusDisplay.setAllowPublic(state) def getAllowCrewState(self): return self.allowCrewState def getAllowFriendState(self): return self.allowFriendState def getAllowGuildState(self): return self.allowGuildState def getAllowPublicState(self): return self.allowPublicState def hasSpace(self, avId=0, bandMgrId=0, bandId=0, guildId=0): if avId == self.ownerId: return True if self.isInCrew(avId): return True if self.isInCrew(self.ownerId) and len(self.crew) >= self.maxCrew: return False if len(self.crew) >= self.maxCrew - 1: return False return True def confirmSameCrewTeleport(self, toFrom, incomingAvId=0, bandMgrId=0, bandId=0, guildId=0): if toFrom == 'from': return True elif not self.isGenerated(): self.notify.warning('confirmSameCrewTeleport(%s)' % localAvatar.getShipString()) return False if incomingAvId == self.ownerId: return True if bandMgrId and bandId and self.getAllowCrewState() and ( bandMgrId, bandId) == self.getBandId(): return True if localAvatar.doId == self.ownerId and self.getAllowFriendState( ) and self.cr.identifyFriend(incomingAvId): return True if guildId and self.getAllowGuildState( ) and guildId == self.getGuildId(): return True if self.getAllowPublicState(): return True return False confirmSameCrewTeleport = report( types=['frameCount', 'deltaStamp', 'args'], dConfigParam='shipboard')(confirmSameCrewTeleport) def getMinimapObject(self): if not (self.minimapObj) and not self.isDisabled(): self.minimapObj = MinimapPlayerShip(self) return self.minimapObj def setTeam(self, team): if not self._verifyTeam(team): return None DistributedSimpleShip.setTeam(self, team) def _verifyTeam(self, team): if team == PiratesGlobals.INVALID_TEAM: doId = '<no doId>' if hasattr(self, 'doId'): doId = self.doId else: self.badInitTeam = team base.cr.centralLogger.writeClientEvent('bad ship team: %s' % doId) self.notify.warning('bad ship team: %s' % doId) return False return True def d_setLocation(self, parentId, zoneId): theStack = StackTrace(start=1) if self.prevLocStack and len( theStack.trace) == len(self.prevLocStack.trace) and map( lambda x: x[1], theStack.trace) == map( lambda x: x[1], self.prevLocStack.trace): base.cr.centralLogger.writeClientEvent('bad ship team: %s setLoc' % self.doId) else: base.cr.centralLogger.writeClientEvent( 'bad ship team: %s' % self.doId + theStack.compact()[1:len(theStack.compact())]) self.prevLocStack = theStack DistributedSimpleShip.d_setLocation(self, parentId, zoneId)
class DistributedCogdoInterior(DistributedObject.DistributedObject): """ """ if __debug__: notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedCogdoInterior') id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loader.loadSfx( "phase_5/audio/sfx/elevator_door_open.mp3") self.closeSfx = base.loader.loadSfx( "phase_5/audio/sfx/elevator_door_close.mp3") self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = ConfigVariableBool('cogdo-game-repeat', 0).getValue() # we increment this each time we come out of an elevator: self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 # initial cog positions vary based on the cog office model self.BottomFloor_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0) ] self.BottomFloor_SuitHs = [75, 170, -91, -44] # Heading angles self.Cubicle_SuitPositions = [ Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0) ] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0), ] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = ConfigVariableBool('cogdo-want-barrel-room', 0).getValue() self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loader.loadMusic( 'phase_7/audio/bgm/encntr_toon_winning_indoor.mid') self.elevatorMusic = base.loader.loadMusic( 'phase_7/audio/bgm/tt_elevator.mid') self.fsm = ClassicFSM.ClassicFSM( 'DistributedCogdoInterior', [ State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game']), State.State('Game', self.enterGame, self.exitGame, ['Resting', 'Failed', 'BattleIntro']), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State( 'BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle']), ], # Initial State 'Off', # Final State 'Off', ) # make sure we're in the initial state self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall( self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall( self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return (name + '%d' % DistributedCogdoInterior.id) def generate(self): """generate(self) This method is called when the DistributedObject is reintroduced to the world, either for the first time or from the cache. """ assert (self.notify.debug("generate()")) DistributedObject.DistributedObject.generate(self) # listen for the generate event, which will be thrown after the # required fields are filled in self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) # Load the elevator model self.elevatorModelIn = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left-door') self.rightDoorIn = self.elevatorModelIn.find('**/right-door') self.elevatorModelOut = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorOut = self.elevatorModelOut.find('**/left-door') self.rightDoorOut = self.elevatorModelOut.find('**/right-door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning( "No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons" ) random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): """ Sets up the lights on the interior elevators to represent the number of floors in the building, and to light up the current floor number. """ npc = elevatorModel.findAllMatches("**/floor_light_?;+s") for i in range(npc.getNumPaths()): np = npc.getPath(i) # Get the last character, and make it zero based: floor = int(np.getName()[-1:]) - 1 if (floor == self.currentFloor): np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors(): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find("**/floor_light_%s" % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals["alertElevatorLight"] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval("alertElevatorLight") self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): """ handleAnnounceGenerate is called after all of the required fields are filled in 'obj' is another copy of self """ self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_door.mp3') self.cageLowerSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_lower.mp3') assert (self.notify.debug('joining DistributedCogdoInterior')) # Update the minigame AI to join our local toon doId self.sendUpdate('setAvatarJoined', []) def disable(self): assert (self.notify.debug('disable()')) self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): assert (self.notify.debug('delete()')) self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm # No more battle multiplier base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): if self.layout.hasBossBattle(): if self.layout.getBossBattleFloor() == floorNum: return True return False def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] # Clean up elevator models if (self.elevatorModelIn != None): self.elevatorModelIn.removeNode() if (self.elevatorModelOut != None): self.elevatorModelOut.removeNode() # Clean up current floor if (self.floorModel != None): self.floorModel.removeNode() # Clean up current cage if (self.cage != None): self.cage = None # Clean up current barrel room if (self.barrelRoom != None): self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): assert (self.notify.debug('addToon(%d)' % toon.doId)) self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected=0): assert (self.notify.debug('removeToon() - toon: %d' % toon.doId)) if (self.toons.count(toon) == 1): self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): """ Force the specified interval to jump to the end """ if (name in self.activeIntervals): interval = self.activeIntervals[name] if (interval.isPlaying()): assert(self.notify.debug('finishInterval(): %s' % \ interval.getName())) interval.finish() def __cleanupIntervals(self): for interval in list(self.activeIntervals.values()): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) ##### Messages from the server ##### def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): assert (self.notify.debug('setToons(): %s' % toonIds)) self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if (toonId != 0): if (toonId in self.cr.doId2do): toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if (oldtoons.count(toon) == 0): assert(self.notify.debug('setToons() - new toon: %d' % \ toon.doId)) self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if (self.toons.count(toon) == 0): self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): assert(self.notify.debug('setSuits(): active %s reserve %s values %s' \ % (suitIds, reserveIds, values))) oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if (suitId in self.cr.doId2do): suit = self.cr.doId2do[suitId] self.suits.append(suit) # Set this on the client suit.fsm.request('Battle') # This will allow client to respond to setState() from the # server from here on out suit.buildingSuit = 1 suit.reparentTo(render) if (oldsuits.count(suit) == 0): assert(self.notify.debug('setSuits() suit: %d joining' % \ suit.doId)) self.joiningReserves.append(suit) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] assert (len(reserveIds) == len(values)) for index in range(len(reserveIds)): suitId = reserveIds[index] if (suitId in self.cr.doId2do): suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if (len(self.joiningReserves) > 0): assert (self.notify.debug('setSuits() reserves joining')) self.fsm.request('ReservesJoining') def setState(self, state, timestamp): assert(self.notify.debug("setState(%s, %d)" % \ (state, timestamp))) self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash=True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() ##### Messages to the server ##### def d_elevatorDone(self): assert (self.notify.debug('network:elevatorDone(%d)' % base.localAvatar.doId)) self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): assert (self.notify.debug('network:reserveJoinDone(%d)' % base.localAvatar.doId)) self.sendUpdate('reserveJoinDone', []) # Specific State Functions ##### Off state ##### def enterOff(self, ts=0): assert (self.notify.debug('enterOff()')) messenger.send('sellbotFieldOfficeChanged', [False]) return None def exitOff(self): return None ##### WaitForAllToonsInside state ##### def enterWaitForAllToonsInside(self, ts=0): assert (self.notify.debug('enterWaitForAllToonsInside()')) base.transitions.fadeOut(0) return None def exitWaitForAllToonsInside(self): return None def enterGame(self, ts=0): assert (self.notify.debug('enterElevator()')) base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) ##### Elevator state ##### def __playElevator(self, ts, name, callback): # Load the floor model SuitHs = [] # Heading angles SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if (self.currentFloor == 0): # bottom floor SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): # Top floor self.barrelRoom.unload() self.floorModel = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_penthouse') self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in range(4): paintingModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() # middle floor SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.debug('Load boss_suit_office') elevIn = self.floorModel.find( CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find( CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) else: # We need to name this something more useful (and we'll need the # location of the opposite elevator as well) elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded(): elevIn = self.barrelRoom.dummyElevInNode elevOut = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: # TODO: TEMP floorModel = loader.loadModel( 'phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn # store elevOut until it's needed self.elevOut = elevOut self._haveEntranceElevator.set(True) # Position the suits assert (len(self.suits) <= 4) for index in range(len(self.suits)): assert(self.notify.debug('setting suit: %d to pos: %s' % \ (self.suits[index].doId, SuitPositions[index]))) self.suits[index].setPos(SuitPositions[index]) if (len(self.suits) > 2): self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH( 170 ) # if there's 2 or 1 suits, make them face fwd since there's no other suits they would be to be talking to self.suits[index].loop('neutral') # Position the toons for toon in self.toons: toon.reparentTo(self.elevatorModelIn) assert (self.toonIds.count(toon.doId) == 1) index = self.toonIds.index(toon.doId) assert (index >= 0 and index <= 3) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') # Show the elevator and position it in the correct place for the floor self.elevatorModelIn.reparentTo(elevIn) # Start with the doors in closed position self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) # Position the camera behind the toons camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) # Play elevator music base.playMusic(self.elevatorMusic, looping=1, volume=0.8) # Ride the elevator, then open the doors. track = Sequence( Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render), ) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts=0): # Load model for the current floor and the suit models for the floor assert (self.notify.debug('enterElevator()')) if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) # hide elevator from previous floor (if any) # unless it's the top floor, in that case leave it where it is if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) # Get the floor multiplier mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) # Now set the inventory battleCreditMult base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): assert (self.notify.debug('handleElevatorDone()')) self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) return None def __setupBarrelRoom(self): base.cr.playGame.getPlace().fsm.request('stopped') base.transitions.irisOut(0.0) self.elevatorModelIn.detachNode() self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval( ) self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None return def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task=None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) def setBarrelRoomReward(self, avIds, laffs): self.brResults = [avIds, laffs] self.barrelRoom.setRewardResults(self.brResults) def enterBarrelRoomReward(self, ts=0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi( self.brResults, callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts=0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() ##### Battle state ##### def __playCloseElevatorOut(self, name, delay=0): # Close the elevator doors track = Sequence( Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel( SoundInterval(self.closeSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut')), ) track.start() self.activeIntervals[name] = track def enterBattle(self, ts=0): assert (self.notify.debug('enterBattle()')) if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): # now that we're in the barrel room, show the exit elevator # Show the elevator and position it in the correct place for the floor self.elevatorModelOut.reparentTo(self.elevOut) # Start with the doors in closed position self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not (self._wantBarrelRoom and self.elevatorOutOpen == 1): self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) # Watch reserve suits as they walk from the elevator camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) return None def exitBattle(self): if (self.elevatorOutOpen == 1): self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 return None ##### ReservesJoining state ##### def __playReservesJoining(self, ts, name, callback): # Position the joining suits index = 0 assert (len(self.joiningReserves) <= 4) for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos( self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') if len(self.suits) == len(self.joiningReserves): camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, Point3(0, 5, 5)), Func(camera.headsUp, self.elevatorModelOut)) else: camSequence = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0))) # Aim the camera at the far elevator track = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0)), # Open the elevator doors Parallel( SoundInterval(self.openSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), ), # Hold the camera angle for a couple of beats Wait(SUIT_HOLD_ELEVATOR_TIME), # Reparent the camera to render (enterWaitForInput will # position it properly again by the battle) Func(camera.wrtReparentTo, render), Func(callback), ) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts=0): assert (self.notify.debug('enterReservesJoining()')) self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) return None def __handleReserveJoinDone(self): assert (self.notify.debug('handleReserveJoinDone()')) self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) return None ##### Resting state ##### def enterResting(self, ts=0): assert (self.notify.debug('enterResting()')) self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) return def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -10, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() return ##### Reward state ##### def enterReward(self, ts=0): assert (self.notify.debug('enterReward()')) if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() return None def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug( 'exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None return ##### Failed state ##### def enterFailed(self, ts=0): self.exitCogdoBuilding() return None def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() return None def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = { 'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId } messenger.send('DSIDoneEvent', [request]) return def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in range(len(self.toons)): goldBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in range(numFloors): silverBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) ##### Outro state ##### def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append( Sequence( Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel( self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel( self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether( self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed=None): self.shopOwnerNpc.setChatAbsolute( TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel( Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence( Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setMinFov, ToontownGlobals.DefaultCameraFov), ), ) track.start() self.penthouseOutroChatDoneTrack = track