def doSpray(self, scaleUp, scaleDown, hold): base.audio3d.attachSoundToObject(self.spraySfx, self.gag) self.spraySfx.play() spraySequence = Sequence(Func(self.getSprayTrack(self.origin, self.sprayRange, scaleUp, hold, scaleDown).start)) sprayParallel = Parallel() sprayParallel.append(Func(spraySequence.start)) sprayParallel.start()
def movementTask( self, task ): # show and hide depending on distance to camera if (base.camera.getPos( render ) - self.getPos()).length() > 100.0: self.pandaActor.hide() else: self.pandaActor.show() try: # calculate time passed / we cant use task.time in a doMethodLater deltaT = time.time() - self.oldTaskTime # save current time self.oldTaskTime = time.time() except: # save current time self.oldTaskTime = time.time() deltaT = 0.0 # get future rotation and position rot = self.getRotation( UPDATETIME, random.randint( -10, 10) ) pos = self.getForwardPos( UPDATETIME * (random.random()/2.0+1.0) ) posZ = self.getHeight( (pos.getX(), pos.getY()) ) pos.setZ( posZ ) # create movement and rotation intervals myInterval1=self.posInterval(UPDATETIME*1.25,pos) myInterval2=self.hprInterval(UPDATETIME*1.25,rot) # myInterval1=self.globalPandaNode.posInterval(UPDATETIME*1.25,pos) # myInterval2=self.globalPandaNode.hprInterval(UPDATETIME*1.25,rot) myParallel=Parallel(myInterval1,myInterval2) myParallel.start() return Task.again
class JugglingBalls(ToonUpGag): def __init__(self): ToonUpGag.__init__(self, CIGlobals.JugglingBalls, 'phase_5/models/props/cubes-mod.bam', 90, 120, 100, GagGlobals.JUGGLE_SFX, 1, anim='phase_5/models/props/cubes-chan.bam') self.setImage('phase_3.5/maps/juggling-cubes.png') self.track = None self.soundInterval = None return def start(self): super(JugglingBalls, self).start() self.setupHips() self.build() self.placeProp(self.hips, self.gag) self.soundInterval = self.getSoundTrack(0.7, self.gag, 7.7) propInterval = Sequence() propInterval.append(ActorInterval(self.gag, 'chan')) if self.avatar == base.localAvatar: propInterval.append(Func(self.setHealAmount)) propInterval.append(Func(self.healNearbyAvatars, 25)) propInterval.append(Func(self.cleanupGag)) propInterval.append(Func(self.reset)) self.track = Parallel(ActorInterval(self.avatar, 'juggle'), propInterval, Func(self.soundInterval.start)) self.track.start() def equip(self): super(JugglingBalls, self).equip() def unEquip(self): if self.track: self.soundInterval.finish() self.track.finish() self.track = None self.reset() return
def startEntity(self, cog): if not cog: self.completeSquirt() return scaleUpPoint = Point3(1.5, 1.5, 1.5) rainDelay = 1 effectDelay = 0.3 cloudHold = 4.7 tContact = 2.4 if cog.isDead(): cloudHold = 1.7 cloud01, trickleFx, rainEffects, entity = self.buildEntity() cloud01.setZ(cog.suitPlan.getNametagZ() + 2) cloud01.reparentTo(cog) cloud02 = Actor(self.model, {'chan': GagGlobals.getProp(4, 'stormcloud-chan')}) cloud02.reparentTo(cloud01) def damageCog(): if self.isLocal(): self.avatar.sendUpdate('suitHitByPie', [cog.doId, self.getID()]) def __getCloudTrack(cloud, useEffect = 1): track = Sequence(Func(cloud.pose, 'chan', 0), LerpScaleInterval(cloud, 1.5, scaleUpPoint, startScale=GagGlobals.PNT3NEAR0), Wait(rainDelay)) if useEffect == 1: pTrack = Parallel() delay = trickleDuration = cloudHold * 0.25 trickleTrack = ParticleInterval(trickleFx, cloud, worldRelative=0, duration=trickleDuration, cleanup=True) track.append(trickleTrack) for i in range(0, 3): dur = cloudHold - 2 * trickleDuration pTrack.append(Sequence(Wait(delay), ParticleInterval(rainEffects[i], cloud, worldRelative=0, duration=dur, cleanup=True))) delay += effectDelay pTrack.append(Sequence(Wait(3 * effectDelay), ActorInterval(cloud, 'chan', startTime=1, duration=cloudHold))) damageTrack = Sequence() if cog.getHealth() - self.getDamage() <= 0: damageTrack.append(Func(cog.d_disableMovement, wantRay=True)) damageTrack.append(Func(damageCog)) else: damageTrack.append(Wait(tContact)) damageTrack.append(Func(damageCog)) pTrack.append(damageTrack) track.append(pTrack) else: track.append(ActorInterval(cloud, 'chan', startTime=1, duration=cloudHold)) track.append(LerpScaleInterval(cloud, 0.5, GagGlobals.PNT3NEAR0)) track.append(Func(GagUtils.destroyProp, cloud)) return track tracks = Parallel() soundTrack01 = self.getSoundTrack(1.3, self.avatar) soundTrack02 = self.getSoundTrack(3.4, self.avatar) tracks.append(soundTrack01) tracks.append(soundTrack02) cloud01Track = __getCloudTrack(cloud01) cloud02Track = __getCloudTrack(cloud02, useEffect=0) tracks.append(cloud01Track) tracks.append(cloud02Track) tracks.append(Func(self.destroyEntity, entity)) tracks.start()
def start(self): SoundGag.start(self) tracks = Parallel() delayTime = 2.45 delayUntilAppearSound = 1.0 INSTRUMENT_SCALE_MODIFIER = 0.5 instrMin = Vec3(0.001, 0.001, 0.001) instrMax1 = Vec3(0.1, 0.1, 0.1) instrMax1 *= INSTRUMENT_SCALE_MODIFIER instrMax2 = Vec3(0.3, 0.3, 0.3) instrMax2 *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.4, 0.4, 0.4) instrStretch *= INSTRUMENT_SCALE_MODIFIER def setInstrumentStats(): self.gag.setPos(-0.8, -0.9, 0.2) self.gag.setHpr(145, 0, 0) self.gag.setScale(instrMin) megaphoneSh = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow = self.getScaleIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax1) instrumentAppear = Parallel(grow) stretchInstr = self.getScaleBlendIntervals(self.gag, duration=0.3, startScale=instrMax2, endScale=instrStretch, blendType='easeOut') backInstr = self.getScaleBlendIntervals(self.gag, duration=1.0, startScale=instrStretch, endScale=instrMin, blendType='easeIn') spinInstr = LerpHprInterval(self.gag, duration=1.5, startHpr=Vec3(145, 0, 0), hpr=Vec3(145, 0, 90), blendType='easeInOut') attackTrack = Parallel(Sequence(Wait(0.2), spinInstr), Sequence(stretchInstr, Wait(0.5), backInstr)) megaphoneTrack = Sequence(megaphoneSh, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), Wait(delayTime + 1.0), instrumentAppear) tracks.append(megaphoneTrack) tracks.append(ActorInterval(self.avatar, 'sound')) soundTrack = Sequence(Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Func(self.damageCogsNearby), Wait(0.4), Func(self.finish))) tracks.append(soundTrack) tracks.start()
def append(self,text,width,height,spacing = 0, fadein = 0, fadeinType = 0): '''Add a NodePath that contains a generated text geom This method is called by SogalText ''' self.__lock.acquire() self.items.append(text) text.reparentTo(self) textPos = self.currentPtr text.setPos(textPos) if fadein: interval = Parallel() if fadeinType == 0 or fadeinType == 'normal': interval.append(LerpFunc(_modifyAlphaScale,fadein,0,1,blendType = 'easeOut',extraArgs = [text])) if fadeinType == 1 or fadeinType == 'flyin': interval.append(LerpFunc(_modifyAlphaScale,fadein,0,1,blendType = 'easeOut',extraArgs = [text])) interval.append(LerpPosInterval(text,fadein, self.currentPtr, (self.currentPtr[0],self.currentPtr[1],self.currentPtr[2] -0.3), blendType = 'easeOut')) interval.start() self.__lerpIntervals.append(interval) self.lineWidth = self.currentPtr[0] + width self.lineHeight = max(height, self.lineHeight) self.currentPtr = (self.lineWidth + spacing, 0, 0) self.__lock.release()
def start(self): SoundGag.start(self) tracks = Parallel() delay = 2.45 INSTRUMENT_SCALE_MODIFIER = 0.5 instrMin = Vec3(0.001, 0.001, 0.001) instrMax1 = Vec3(1.7, 1.7, 1.7) instrMax1 *= INSTRUMENT_SCALE_MODIFIER instrMax2 = Vec3(2.2, 2.2, 2.2) instrMax2 *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.4, 0.4, 0.4) instrStretch *= INSTRUMENT_SCALE_MODIFIER head = self.gag.find('**/opera_singer') head.setPos(0, 0, 0) def setInstrumentStats(): newPos = Vec3(-0.8, -0.9, 0.2) newPos *= 1.3 self.gag.setPos(newPos[0], newPos[1], newPos[2]) self.gag.setHpr(145, 0, 90) self.gag.setScale(instrMin) megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow1 = self.getScaleBlendIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax1, blendType='easeOut') grow2 = self.getScaleBlendIntervals(self.gag, duration=1.1, startScale=instrMax1, endScale=instrMax2, blendType='easeIn') shrink2 = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax2, endScale=instrMin) instrumentAppear = Parallel(Sequence(grow1, grow2, Wait(6.0), shrink2, Wait(0.4), Func(self.finish)), SoundInterval(self.appearSfx, node=self.avatar)) delayTime = delay megaphoneTrack = Sequence(megaphoneShow, Wait(delayTime + 1.0), instrumentAppear) tracks.append(megaphoneTrack) toonTrack = self.__createToonInterval(0) tracks.append(toonTrack) soundTrack = Sequence(Wait(delayTime), Parallel(SoundInterval(self.soundSfx, node=self.avatar), Func(self.damageCogsNearby))) tracks.append(soundTrack) tracks.start()
def start(self): SoundGag.start(self) INSTRUMENT_SCALE_MODIFIER = 0.5 delayTime = 2.45 delayUntilAppearSound = 1.0 tracks = Parallel() instrMin = Vec3(0.001, 0.001, 0.001) instrMax = Vec3(0.2, 0.2, 0.2) instrMax *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.25, 0.25, 0.25) instrStretch *= INSTRUMENT_SCALE_MODIFIER def setInstrumentStats(): self.gag.setPos(-1.2, -1.3, 0.1) self.gag.setHpr(145, 0, 85) self.gag.setScale(instrMin) megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow = self.getScaleIntervals(self.gag, duration=0.2, startScale=instrMin, endScale=instrMax) instrumentAppear = grow stretchInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrMax, endScale=instrStretch, blendType='easeOut') backInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrStretch, endScale=instrMax, blendType='easeIn') attackTrack = Sequence(stretchInstr, backInstr) megaphoneTrack = Sequence(megaphoneShow, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), instrumentAppear) tracks.append(megaphoneTrack) tracks.append(ActorInterval(self.avatar, 'sound')) instrumentshrink = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax, endScale=instrMin) soundTrack = Sequence(Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Wait(0.2), instrumentshrink, Func(self.damageCogsNearby), Wait(0.4), Func(self.finish))) tracks.append(soundTrack) tracks.start()
def handleMatch(self, cardA, cardB, withBonus): self.notify.debug('we got a match %d %d' % (cardA, cardB)) self.matches += 1 if cardA in self.faceUpList: self.faceUpList.remove(cardA) if cardB in self.faceUpList: self.faceUpList.remove(cardB) self.inactiveList.append(cardA) self.inactiveList.append(cardB) matchIval = Parallel() for card in [ cardA, cardB]: self.cards[card].setTransparency(1) cardSeq = Sequence(LerpColorScaleInterval(self.cards[card], duration = 1, colorScale = Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.cards[card].hide)) matchIval.append(cardSeq) if withBonus: matchIval.append(SoundInterval(self.matchWithBonusSfx, node = self.cards[card], listenerNode = base.localAvatar, cutOff = 240)) else: matchIval.append(SoundInterval(self.matchSfx, node = self.cards[card], listenerNode = base.localAvatar, cutOff = 240)) matchIval.start() if len(self.inactiveList) == len(self.cards): self.sendUpdate('reportDone')
def AnimateIn(self, blade): x, y, z = blade.getPos() ending_position = (self.originals[blade]) position1 = blade.posInterval(1, ending_position, (x, y, z)) rotate1 = blade.hprInterval(1, (0, 0, 0), blade.getHpr()) scale1 = blade.scaleInterval(1, (1, 1, 1), blade.getScale()) move = Parallel(position1, rotate1, scale1, name="move") move.start() blade.setTag('state', 'in')
def AnimateOut(self, blade): x, y, z = blade.getPos() self.originals[blade] = (x, y, z) ending_position = (40 + random.uniform(0,120), y-(random.uniform(20,100)), z + random.uniform(-10,50)) position1 = blade.posInterval(1, ending_position, (x, y, z)) rotate1 = blade.hprInterval(1, (90, 0, 0), blade.getHpr()) scale1 = blade.scaleInterval(1, (2, 2, 2), blade.getScale()) move = Parallel(position1, rotate1, scale1, name="move") move.start() blade.setTag('state', 'out')
class Megaphone(ToonUpGag): def __init__(self): ToonUpGag.__init__(self, CIGlobals.Megaphone, 'phase_5/models/props/megaphone.bam', 10, 20, 100, GagGlobals.TELLJOKE_SFX, 1) self.setImage('phase_3.5/maps/megaphone.png') self.track = None self.soundInterval = None return def start(self): super(Megaphone, self).start() if not self.gag: self.build() if self.avatar == base.localAvatar: question, answer = random.choice(CIGlobals.ToonHealJokes) self.setupHandJoints() self.placeProp(self.handJoint, self.gag) self.soundInterval = self.getSoundTrack(self.avatar.getDuration('shout', fromFrame=0, toFrame=18), self.gag, 5.5) propInterval = Sequence() propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=0, toFrame=25))) if self.avatar == base.localAvatar: propInterval.append(Func(base.localAvatar.b_setChat, question)) propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=26, toFrame=75))) if self.avatar == base.localAvatar: propInterval.append(Func(base.localAvatar.b_setChat, answer)) propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=76, toFrame=118))) if self.avatar == base.localAvatar: propInterval.append(Func(self.setHealAmount)) propInterval.append(Func(self.healNearbyAvatars, 20)) propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=118))) propInterval.append(Func(self.cleanupGag)) propInterval.append(Func(self.reset)) self.track = Parallel(propInterval, ActorInterval(self.avatar, 'shout'), self.soundInterval) self.track.start() def equip(self): super(Megaphone, self).equip() self.build() def unEquip(self): if self.track: self.track.finish() self.track = None self.soundInterval = None self.cleanupGag() self.reset() return def cleanupGag(self): if self.gag: self.gag.removeNode() self.gag = None return
class PickPocketAttack(Attack): notify = directNotify.newCategory('PickPocketAttack') attack = 'pickpocket' def __init__(self, attacksClass, suit): Attack.__init__(self, attacksClass, suit) self.dollar = None self.pickSfx = None return def doAttack(self, ts = 0): self.dollar = loader.loadModel('phase_5/models/props/1dollar-bill-mod.bam') self.dollar.setY(0.22) self.dollar.setHpr(289.18, 252.75, 0.0) if hasattr(self.suit, 'uniqueName'): name = self.suit.uniqueName('doPickPocketAttack') else: name = 'doPickPocketAttack' self.suitTrack = Parallel(ActorInterval(self.suit, 'pickpocket'), Sequence(Wait(0.4), Func(self.attemptDamage)), name=name) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.finishedAttack) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self.suit, name) self.suitTrack.start(ts) def attemptDamage(self): shouldDamage = False suitH = self.suit.getH(render) % 360 myH = base.localAvatar.getH(render) % 360 if not -90.0 <= suitH - myH <= 90.0: if base.localAvatar.getDistance(self.suit) <= 15.0: shouldDamage = True if shouldDamage: self.playWeaponSound() self.dollar.reparentTo(self.suit.find('**/joint_Rhold')) self.suit.sendUpdate('toonHitByWeapon', [self.getAttackId(self.attack), base.localAvatar.doId]) base.localAvatar.b_handleSuitAttack(self.getAttackId(self.attack), self.suit.doId) def playWeaponSound(self): self.pickSfx = base.audio3d.loadSfx('phase_5/audio/sfx/SA_pick_pocket.mp3') base.audio3d.attachSoundToObject(self.pickSfx, self.suit) self.pickSfx.play() def cleanup(self): Attack.cleanup(self) if self.pickSfx: self.pickSfx.stop() self.pickSfx = None if self.dollar: self.dollar.removeNode() self.dollar = None return
class CogdoMazeSplattable: def __init__(self, object, name, collisionRadius): self.object = object self.splat = CogdoUtil.loadMazeModel('splash') self.splat.setBillboardPointEye() self.splat.setBin('fixed', 40) self.splat.setDepthTest(False) self.splat.setDepthWrite(False) self.splatTrack = None self._splatSfxIval = base.cogdoGameAudioMgr.createSfxIval('splat') self.initGagCollision(name, collisionRadius) return def destroy(self): self.disableGagCollision() if self._splatSfxIval.isPlaying(): self._splatSfxIval.finish() del self._splatSfxIval def initGagCollision(self, name, radius): self.gagCollisionName = name collision = CollisionTube(0, 0, 0, 0, 0, 4, radius) collision.setTangible(1) self.gagCollNode = CollisionNode(self.gagCollisionName) self.gagCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.gagCollNode.addSolid(collision) self.gagCollNodePath = self.object.attachNewNode(self.gagCollNode) def disableGagCollision(self): self.gagCollNodePath.removeNode() def doSplat(self): if self.splatTrack and self.splatTrack.isPlaying(): self.splatTrack.finish() self.splat.reparentTo(render) self.splat.setPos(self.object, 0, 0, 3.0) self.splat.setY(self.splat.getY() - 1.0) self._splatSfxIval.node = self.splat self.splatTrack = Parallel( self._splatSfxIval, Sequence( Func(self.splat.showThrough), LerpScaleInterval( self.splat, duration=0.5, scale=6, startScale=1, blendType='easeOut'), Func(self.splat.hide))) self.splatTrack.start()
def showToonThrowingGag(self, heading, pos): gag = self.equippedGag if gag is None: return self.removeGag() tossTrack, flyTrack, object = self.getThrowInterval(gag, pos[0], pos[1], pos[2], heading, 0, 0) def matchRunningAnim(toon = self.toon): toon.playingAnim = None toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed) newTossTrack = Sequence(tossTrack, Func(matchRunningAnim)) throwTrack = Parallel(newTossTrack, flyTrack) throwTrack.start(0) return object
def showVisibleSquares(self, dt="default"): visibles = defaultdict(lambda: False) for p in [(x,y) for (x,y) in self.pieces if 0 <= x < 8 and 0 <= y < 8]: if self.pieces[p]: if self.pieces[p].color == self.player: for s in self.pieces[p].visibleSquares(self.pieces): visibles[s] = True par = Parallel() for s in self.squares: if visibles[s]: par.append(self.showSquare(s, dt)) else: par.append(self.hideSquare(s, dt)) par.start() return par
def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find('**/tray') if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel(SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval(food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc)), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0))) intervalName = 'serveFood-%d-%d' % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval
def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Dead") diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find("**/chair_%d" % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence( Func(self.notify.debug, "before actorinterval sit-lose"), ActorInterval(diner, "sit-lose"), Func(self.notify.debug, "before deathSuit.setHpr"), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, "before diner.hide"), Func(diner.hide), Func(self.notify.debug, "before deathSuit.reparentTo"), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, "befor ActorInterval lose"), ActorInterval(deathSuit, "lose", duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, "before remove deathsuit"), Func(removeDeathSuit, diner, deathSuit, name="remove-death-suit-%d-%d" % (chairIndex, self.index)), Func(self.notify.debug, "diner.stash"), Func(diner.stash), ) spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.mp3") deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.mp3") deathSoundTrack = Sequence( Wait(0.80000000000000004), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.20000000000000001, node=deathSuit), SoundInterval( spinningSound, duration=3.0, startTime=0.59999999999999998, volume=0.80000000000000004, node=deathSuit ), SoundInterval(deathSound, volume=0.32000000000000001, node=deathSuit), ) intervalName = "dinerDie-%d-%d" % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval
def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos = Point3(0, 0, 0), endPos = Point3(0, dist, 0), duration = time) relVel = proj.startVel def getVelocity(root = self.root, relVel = relVel): return render.getRelativeVector(root, relVel) fly = Sequence(Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel = getVelocity, duration = 3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node = self.root), name = 'flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound
def showToonThrowingPie(self, avId, timestamp, heading, pos): toon = self.getAvatar(avId) if toon: (tossTrack, pieTrack, flyPie) = self.getTossPieInterval(toon, pos[0], pos[1], pos[2], heading, 0, 0, 0) def removePieFromTraverser(flyPie = flyPie): if base.cTrav: if flyPie: base.cTrav.removeCollider(flyPie) if avId == self.localAvId: flyPie.setTag('throwerId', str(avId)) collSphere = CollisionSphere(0, 0, 0, 0.5) collSphere.setTangible(0) name = 'PieSphere-%d' % avId collSphereName = self.uniqueName(name) collNode = CollisionNode(collSphereName) collNode.setFromCollideMask(ToontownGlobals.PieBitmask) collNode.addSolid(collSphere) colNp = flyPie.attachNewNode(collNode) colNp.show() base.cTrav.addCollider(colNp, self.pieHandler) self.accept('pieHit-' + collSphereName, self.handlePieHitting) def matchRunningAnim(toon = toon): toon.playingAnim = None toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed) newTossTrack = Sequence(tossTrack, Func(matchRunningAnim)) pieTrack = Parallel(newTossTrack, pieTrack) elapsedTime = globalClockDelta.localElapsedTime(timestamp) if elapsedTime < 16.0 / 24.0: elapsedTime = 16.0 / 24.0 pieTrack.start(elapsedTime) self.toonPieTracks[avId] = pieTrack
def doLipstick(self, target): dScale = 0.5 tLips = 2.5 animDuration = base.localAvatar.getDuration(self.avAnim) tThrow = 115.0 / base.localAvatar.getFrameRate(self.avAnim) def doHeal(): if self.isLocal(): self.setHealAmount() self.healAvatar(target, 'conked') base.localAvatar.sendUpdate('gagRelease', [self.getID()]) else: ActorInterval(target, 'conked').start() self.placeProp(self.handJoint, self.gag, Point3(-0.27, -0.24, -0.95), Point3(-118, -10.6, -25.9)) stickScaleUp = self.getScaleTrack([self.gag], dScale, GagGlobals.PNT3NEAR0, GagGlobals.PNT3NORMAL) stickScaleDn = self.getScaleTrack([self.gag], dScale, GagGlobals.PNT3NORMAL, GagGlobals.PNT3NEAR0) stickTrack = Sequence(stickScaleUp, Wait(animDuration - 2.0 * dScale), stickScaleDn) lipsTrack = Sequence(Wait(tLips), Func(self.avatar.pose, self.avAnim, 57), Func(self.avatar.update, 0), Func(self.placeProp, render, self.lips, self.gag.getPos(render)), Func(self.lips.setBillboardPointWorld), LerpScaleInterval(self.lips, dScale, Point3(3, 3, 3), startScale=GagGlobals.PNT3NEAR0), Wait(tThrow - tLips - dScale), LerpPosInterval(self.lips, dScale, Point3(target.getPos()), startPos=self.gag.getPos(render)), Sequence(Func(doHeal)), Func(self.cleanupLips)) delay = tThrow + dScale mainTrack = Parallel(stickTrack, lipsTrack, self.getSoundTrack(delay, self.avatar, 2), Sequence(ActorInterval(self.avatar, self.avAnim))) mainTrack.start()
def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Dead') diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence(Func(self.notify.debug, 'before actorinterval sit-lose'), ActorInterval(diner, 'sit-lose'), Func(self.notify.debug, 'before deathSuit.setHpr'), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, 'before diner.hide'), Func(diner.hide), Func(self.notify.debug, 'before deathSuit.reparentTo'), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, 'befor ActorInterval lose'), ActorInterval(deathSuit, 'lose', duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, 'before remove deathsuit'), Func(removeDeathSuit, diner, deathSuit, name='remove-death-suit-%d-%d' % (chairIndex, self.index)), Func(self.notify.debug, 'diner.stash'), Func(diner.stash)) spinningSound = base.loadSfx('phase_3.5/audio/sfx/Cog_Death.ogg') deathSound = base.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart_%s.ogg' % random.randint(1, 6)) deathSoundTrack = Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.2, node=deathSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=0.8, node=deathSuit), SoundInterval(deathSound, volume=0.32, node=deathSuit)) intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval
def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Dead') diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence(Func(self.notify.debug, 'before actorinterval sit-lose'), ActorInterval(diner, 'sit-lose'), Func(self.notify.debug, 'before deathSuit.setHpr'), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, 'before diner.hide'), Func(diner.hide), Func(self.notify.debug, 'before deathSuit.reparentTo'), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, 'befor ActorInterval lose'), ActorInterval(deathSuit, 'lose', duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, 'before remove deathsuit'), Func(removeDeathSuit, diner, deathSuit, name='remove-death-suit-%d-%d' % (chairIndex, self.index)), Func(self.notify.debug, 'diner.stash'), Func(diner.stash)) spinningSound = base.loader.loadSfx('phase_3.5/audio/sfx/Cog_Death.ogg') deathSound = base.loader.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.ogg') deathSoundTrack = Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.2, node=deathSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=0.8, node=deathSuit), SoundInterval(deathSound, volume=0.32, node=deathSuit)) intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval
def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(root = self.root, relVel = relVel): return render.getRelativeVector(root, relVel) fly = Sequence(Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound return
def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find('**/tray') if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel( SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval(food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc)), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0))) intervalName = 'serveFood-%d-%d' % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval
def start(self): SoundGag.start(self) tracks = Parallel() INSTRUMENT_SCALE_MODIFIER = 0.5 instrMin = Vec3(0.001, 0.001, 0.001) instrMax1 = Vec3(0.3, 0.4, 0.2) instrMax1 *= INSTRUMENT_SCALE_MODIFIER instrMax2 = Vec3(0.3, 0.3, 0.3) instrMax2 *= INSTRUMENT_SCALE_MODIFIER instrStretch1 = Vec3(0.3, 0.5, 0.25) instrStretch1 *= INSTRUMENT_SCALE_MODIFIER instrStretch2 = Vec3(0.3, 0.7, 0.3) instrStretch2 *= INSTRUMENT_SCALE_MODIFIER def setInstrumentStats(): self.gag.setPos(-0.6, -0.9, 0.15) self.gag.setHpr(145, 0, 85) self.gag.setScale(instrMin) megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow1 = self.getScaleIntervals(self.gag, duration=0.3, startScale=instrMin, endScale=instrMax1) grow2 = self.getScaleIntervals(self.gag, duration=0.3, startScale=instrMax1, endScale=instrMax2) instrumentAppear = Parallel(Sequence(grow1, grow2)) stretchInstr1 = self.getScaleBlendIntervals(self.gag, duration=0.1, startScale=instrMax2, endScale=instrStretch1, blendType='easeOut') stretchInstr2 = self.getScaleBlendIntervals(self.gag, duration=0.1, startScale=instrStretch1, endScale=instrStretch2, blendType='easeOut') stretchInstr = Sequence(stretchInstr1, stretchInstr2) backInstr = self.getScaleBlendIntervals(self.gag, duration=0.1, startScale=instrStretch2, endScale=instrMax2, blendType='easeOut') attackTrack = Sequence(stretchInstr, Wait(1), backInstr) delayTime = 2.45 delayUntilAppearSound = 1.0 megaphoneTrack = Sequence(megaphoneShow, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), Wait(delayTime + 1.0), instrumentAppear) tracks.append(megaphoneTrack) tracks.append(ActorInterval(self.avatar, 'sound')) instrumentshrink = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax2, endScale=instrMin) soundTrack = Sequence(Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Sequence(Wait(1.5), instrumentshrink), Func(self.damageCogsNearby), Wait(0.4), Func(self.finish))) tracks.append(soundTrack) tracks.start()
def start(self): SoundGag.start(self) INSTRUMENT_SCALE_MODIFIER = 0.5 tracks = Parallel() instrMin = Vec3(0.001, 0.001, 0.001) instrMax = Vec3(0.4, 0.4, 0.4) instrMax *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.5, 0.5, 0.5) instrStretch *= INSTRUMENT_SCALE_MODIFIER def setInstrumentStats(): self.gag.setPos(-1.3, -1.4, 0.1) self.gag.setHpr(145, 0, 85) self.gag.setScale(instrMin) def longshake(models, num): inShake = self.getScaleBlendIntervals(models, duration=0.2, startScale=instrMax, endScale=instrStretch, blendType='easeInOut') outShake = self.getScaleBlendIntervals(models, duration=0.2, startScale=instrStretch, endScale=instrMax, blendType='easeInOut') i = 1 seq = Sequence() while i < num: if i % 2 == 0: seq.append(inShake) else: seq.append(outShake) i += 1 seq.start() megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow = self.getScaleBlendIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax, blendType='easeInOut') instrumentshrink = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax, endScale=instrMin) instrumentAppear = Sequence(grow, Wait(0), Func(longshake, self.gag, 5)) megaphoneTrack = Parallel(Sequence(Wait(1.7), SoundInterval(self.soundSfx, node=self.avatar)), Sequence(megaphoneShow, Wait(1.7), instrumentAppear, Wait(1), Func(self.damageCogsNearby), instrumentshrink, Wait(0.4), Func(self.finish))) tracks.append(megaphoneTrack) tracks.append(ActorInterval(self.avatar, 'sound')) tracks.start()
def showToonThrowingPie(self, avId, timestamp, heading, pos): toon = self.getAvatar(avId) if toon: tossTrack, pieTrack, flyPie = self.getTossPieInterval( toon, pos[0], pos[1], pos[2], heading, 0, 0, 0) def removePieFromTraverser(flyPie=flyPie): if base.cTrav: if flyPie: base.cTrav.removeCollider(flyPie) if avId == self.localAvId: flyPie.setTag('throwerId', str(avId)) collSphere = CollisionSphere(0, 0, 0, 0.5) collSphere.setTangible(0) name = 'PieSphere-%d' % avId collSphereName = self.uniqueName(name) collNode = CollisionNode(collSphereName) collNode.setFromCollideMask(ToontownGlobals.PieBitmask) collNode.addSolid(collSphere) colNp = flyPie.attachNewNode(collNode) colNp.show() base.cTrav.addCollider(colNp, self.pieHandler) self.accept('pieHit-' + collSphereName, self.handlePieHitting) def matchRunningAnim(toon=toon): toon.playingAnim = None toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed) return newTossTrack = Sequence(tossTrack, Func(matchRunningAnim)) pieTrack = Parallel(newTossTrack, pieTrack) elapsedTime = globalClockDelta.localElapsedTime(timestamp) if elapsedTime < 16.0 / 24.0: elapsedTime = 16.0 / 24.0 pieTrack.start(elapsedTime) self.toonPieTracks[avId] = pieTrack
def start(self): SoundGag.start(self) tracks = Parallel() delay = 2.45 INSTRUMENT_SCALE_MODIFIER = 0.5 instrMin = Vec3(0.001, 0.001, 0.001) instrMax1 = Vec3(1.7, 1.7, 1.7) instrMax1 *= INSTRUMENT_SCALE_MODIFIER instrMax2 = Vec3(2.2, 2.2, 2.2) instrMax2 *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.4, 0.4, 0.4) instrStretch *= INSTRUMENT_SCALE_MODIFIER head = self.gag.find('**/opera_singer') head.setPos(0, 0, 0) def setInstrumentStats(): newPos = Vec3(-0.8, -0.9, 0.2) newPos *= 1.3 self.gag.setPos(newPos[0], newPos[1], newPos[2]) self.gag.setHpr(145, 0, 90) self.gag.setScale(instrMin) megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow1 = self.getScaleBlendIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax1, blendType='easeOut') grow2 = self.getScaleBlendIntervals(self.gag, duration=1.1, startScale=instrMax1, endScale=instrMax2, blendType='easeIn') shrink2 = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax2, endScale=instrMin) instrumentAppear = Parallel(Sequence(grow1, grow2, Wait(6.0), shrink2, Wait(0.4), Func(self.finish)), SoundInterval(self.appearSfx, node=self.avatar)) delayTime = delay megaphoneTrack = Sequence(megaphoneShow, Wait(delayTime + 1.0), instrumentAppear) tracks.append(megaphoneTrack) toonTrack = self.__createToonInterval(0) tracks.append(toonTrack) soundTrack = Sequence(Wait(delayTime), Parallel(SoundInterval(self.soundSfx, node=self.avatar), Func(self.damageCogsNearby))) tracks.append(soundTrack) tracks.start() self.tracks = tracks
def makeDeltaTextEffect(delta, parent, pos): from direct.gui.DirectGui import OnscreenText text = OnscreenText(text = "", font = getMickeyFont()) if delta > 0: text['fg'] = (0, 1, 0, 1) textstr = "+" else: text['fg'] = (1, 0, 0, 1) textstr = "" textstr += str(delta) text['text'] = textstr text.reparentTo(parent) text.setPos(pos[0], pos[2]) text.setTransparency(True, 1) from panda3d.core import Point3 from direct.interval.IntervalGlobal import Sequence, LerpPosInterval, LerpColorScaleInterval, Wait, Parallel seq = Parallel() seq.append(LerpPosInterval(text, 1.0, Point3(pos) + (0, 0, 0.1), pos)) seq.append(Sequence(LerpColorScaleInterval(text, 0.25, (1, 1, 1, 1), (1, 1, 1, 0)), Wait(0.5), LerpColorScaleInterval(text, 0.25, (1, 1, 1, 0), (1, 1, 1, 1)), Func(text.destroy))) seq.start()
class DistributedBoat(DistributedObject): notify = directNotify.newCategory("DistributedBoat") def __init__(self, cr): DistributedObject.__init__(self, cr) self.fsm = ClassicFSM('DistributedBoat', [ State('off', self.enterOff, self.exitOff), State('eastToWest', self.enterEastToWest, self.exitEastToWest), State('westToEast', self.enterWestToEast, self.exitWestToEast) ], 'off', 'off') self.boat = None self.eastPier = None self.eastPierPath = 'east_pier' self.westPier = None self.westPierPath = 'west_pier' self.pierUpP = 0.0 self.pierDownP = -45.0 self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.ogg' self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.ogg' self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.ogg' self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.ogg' self.eastWest = 'phase_6/paths/dd-e-w.bam' self.westEast = 'phase_6/paths/dd-w-e.bam' self.boatPath = '*donalds_boat*' self.track = None self.state = None def __handleOnBoat(self, entry): base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat) base.playSfx(self.soundWaterLap, looping=1) def __handleOffBoat(self, entry): base.localAvatar.b_setParent(CIGlobals.SPRender) self.soundWaterLap.stop() def __pollBoat(self, task): try: self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath) except: return task.cont self.generated() return task.done def generate(self): DistributedObject.generate(self) self.soundFogHorn = base.loadSfx(self.fogHorn) self.soundShipBell = base.loadSfx(self.shipBell) self.soundWaterLap = base.loadSfx(self.waterLap) self.soundDockCreak = base.loadSfx(self.dockCreak) #try: # self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath) #except: # base.taskMgr.add(self.__pollBoat, self.uniqueName('__pollBoat')) # return self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath) self.generated() def generated(self): self.eastPier = self.cr.playGame.hood.loader.geom.find( '**/' + self.eastPierPath) self.westPier = self.cr.playGame.hood.loader.geom.find( '**/' + self.westPierPath) base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boat) self.accept('enterdonalds_boat_floor', self.__handleOnBoat) self.accept('exitdonalds_boat_floor', self.__handleOffBoat) self.d_requestCurrentStateAndTimestamp() self.fsm.enterInitialState() def disable(self): base.taskMgr.remove(self.uniqueName('__pollBoat')) base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat) self.ignore('enterdonalds_boat_floor') self.ignore('exitdonalds_boat_floor') self.fsm.requestFinalState() del self.fsm del self.soundFogHorn del self.soundShipBell del self.soundWaterLap del self.soundDockCreak self.fogHorn = None self.shipBell = None self.waterLap = None self.dockCreak = None self.boat = None self.track = None self.pierDownP = None self.pierUpP = None self.eastPier = None self.eastPierPath = None self.westPier = None self.westPierPath = None self.boatPath = None self.westEast = None self.eastWest = None DistributedObject.disable(self) def currentStateAndTimestamp(self, state, timestamp): self.setState(state, timestamp) def d_requestCurrentStateAndTimestamp(self): self.sendUpdate('requestCurrentStateAndTimestamp', []) def setState(self, state, timestamp=None): if timestamp == None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) self.state = state if self.boat: self.fsm.request(state, [ts]) def enterEastToWest(self, ts=0): moPath = Mopath.Mopath() moPath.loadFile(self.eastWest) moIval = MopathInterval(moPath, self.boat) self.track = Parallel( SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.eastPier), moIval, LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierDownP, 0), startHpr=(90, self.pierUpP, 0)), Sequence( Wait(15.0), Parallel( LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierUpP, 0), startHpr=(-90, self.pierDownP, 0)), Sequence( Wait(2.0), SoundInterval(self.soundDockCreak, node=self.westPier))), SoundInterval(self.soundFogHorn, node=self.boat))) self.track.start(ts) def exitEastToWest(self): if self.track: self.track.finish() self.track = None def enterWestToEast(self, ts=0): moPath = Mopath.Mopath() moPath.loadFile(self.westEast) moIval = MopathInterval(moPath, self.boat) self.track = Parallel( SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.westPier), moIval, LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierDownP, 0), startHpr=(-90, self.pierUpP, 0)), Sequence( Wait(15.0), Parallel( LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierUpP, 0), startHpr=(90, self.pierDownP, 0)), Sequence( Wait(2.0), SoundInterval(self.soundDockCreak, node=self.eastPier))), SoundInterval(self.soundFogHorn, node=self.boat))) self.track.start(ts) def exitWestToEast(self): if self.track: self.track.finish() self.track = None def enterOff(self): pass def exitOff(self): pass
class CogThief(DirectObject): notify = directNotify.newCategory('CogThief') DefaultSpeedWalkAnim = 4.0 CollisionRadius = 1.25 MaxFriendsVisible = 4 Infinity = 100000.0 SeparationDistance = 6.0 MinUrgency = 0.5 MaxUrgency = 0.75 def __init__(self, cogIndex, suitType, game, cogSpeed): self.cogIndex = cogIndex self.suitType = suitType self.game = game self.cogSpeed = cogSpeed suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitType) suit.setDNA(d) suit.pose('walk', 0) self.suit = suit self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId self.lastLocalTimeStampFromAI = 0 self.lastPosFromAI = Point3(0, 0, 0) self.lastThinkTime = 0 self.doneAdjust = False self.barrel = CTGG.NoBarrelCarried self.signalledAtReturnPos = False self.defaultPlayRate = 1.0 self.netTimeSentToStartByHit = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) self.bodyLength = self.CollisionRadius * 2 self.cruiseDistance = 2 * self.bodyLength self.maxVelocity = self.cogSpeed self.maxAcceleration = 5.0 self.perceptionRange = 6 self.notify.debug('cogSpeed=%s' % self.cogSpeed) self.kaboomSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() self.kaboom.hide() self.kaboomTrack = None splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') def destroy(self): self.ignoreAll() self.suit.delete() self.game = None def uniqueName(self, baseStr): return baseStr + '-' + str(self.game.doId) def handleEnterSphere(self, collEntry): intoNp = collEntry.getIntoNodePath() self.notify.debug('handleEnterSphere suit %d hit %s' % (self.cogIndex, intoNp)) if self.game: self.game.handleEnterSphere(collEntry) def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollisions() self.startWalkAnim() def gameEnd(self): self.moveIval.pause() del self.moveIval self.shutdownCollisions() self.suit.loop('neutral') def initCollisions(self): self.collSphere = CollisionSphere(0, 0, 0, 1.25) self.collSphere.setTangible(1) name = 'CogThiefSphere-%d' % self.cogIndex self.collSphereName = self.uniqueName(name) self.collNode = CollisionNode(self.collSphereName) self.collNode.setIntoCollideMask(CTGG.BarrelBitmask | ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) self.accept('enter' + self.collSphereName, self.handleEnterSphere) self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4, self.CollisionRadius) self.pieCollSphere.setTangible(1) name = 'CogThiefPieSphere-%d' % self.cogIndex self.pieCollSphereName = self.uniqueName(name) self.pieCollNode = CollisionNode(self.pieCollSphereName) self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.pieCollNode.addSolid(self.pieCollSphere) self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode) def shutdownCollisions(self): self.ignore(self.uniqueName('enter' + self.collSphereName)) del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId, pos): self.notify.debug('self.netTimeSentToStartByHit =%s' % self.netTimeSentToStartByHit) if not self.game: self.notify.debug('updateGoal self.game is None, just returning') return None if not self.suit: self.notify.debug('updateGoal self.suit is None, just returning') return None if self.goal == CTGG.NoGoal: self.startWalkAnim() if goalType == CTGG.NoGoal: self.notify.debug('updateGoal setting position to %s' % pos) self.suit.setPos(pos) self.lastThinkTime = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) if goalType == CTGG.RunAwayGoal: pass 1 if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal and goalType == CTGG.RunAwayGoal: self.notify.warning( 'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s' % (CTGG.GoalStr[goalType], self.cogIndex, inResponseClientStamp, self.netTimeSentToStartByHit)) else: self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime( timestamp, bits=32) self.goal = goalType self.goalId = goalId self.lastPosFromAI = pos self.doneAdjust = False self.signalledAtReturnPos = False def startWalkAnim(self): if self.suit: self.suit.loop('walk') speed = self.cogSpeed self.defaultPlayRate = float(self.cogSpeed / self.DefaultSpeedWalkAnim) self.suit.setPlayRate(self.defaultPlayRate, 'walk') def think(self): if self.goal == CTGG.ToonGoal: self.thinkAboutCatchingToon() elif self.goal == CTGG.BarrelGoal: self.thinkAboutGettingBarrel() elif self.goal == CTGG.RunAwayGoal: self.thinkAboutRunAway() def thinkAboutCatchingToon(self): if not self.game: return None av = self.game.getAvatar(self.goalId) if av: if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime avPos = av.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutCatchingToon not doneAdjust setting pos %s' % myPos) self.doneAdjust = True self.suit.setPos(myPos) if self.game.isToonPlayingHitTrack(self.goalId): self.suit.headsUp(av) self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) else: self.commonMove() newPos = self.suit.getPos() self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def convertNetworkStampToGameTime(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) gameTime = self.game.local2GameTime(localStamp) return gameTime def respondToToonHit(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showKaboom() startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToToonHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearGoal(self): self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId def thinkAboutGettingBarrel(self): if not self.game: return None if not hasattr(self.game, 'barrels'): return None if self.goalId not in xrange(len(self.game.barrels)): return None if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime barrel = self.game.barrels[self.goalId] barrelPos = barrel.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutGettingBarrel not doneAdjust setting position to %s' % myPos) self.suit.setPos(myPos) self.doneAdjust = True displacement = barrelPos - myPos distanceToToon = displacement.length() self.suit.headsUp(barrel) lengthTravelled = diffTime * self.cogSpeed if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def stopWalking(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if localStamp > self.lastLocalTimeStampFromAI: self.suit.loop('neutral') self.clearGoal() def thinkAboutRunAway(self): if not self.game: return None if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime returnPos = CTGG.CogReturnPositions[self.goalId] myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.suit.setPos(myPos) self.doneAdjust = True displacement = returnPos - myPos distanceToToon = displacement.length() tempNp = render.attachNewNode('tempRet') tempNp.setPos(returnPos) self.suit.headsUp(tempNp) tempNp.removeNode() lengthTravelled = diffTime * self.cogSpeed if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) if (self.suit.getPos() - returnPos).length() < 0.0001: if not (self.signalledAtReturnPos) and self.barrel >= 0: self.game.sendCogAtReturnPos(self.cogIndex, self.barrel) self.signalledAtReturnPos = True self.lastThinkTime = globalClock.getFrameTime() def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, cogPos): if not self.game: return None localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) self.lastLocalTimeStampFromAI = localTimeStamp inResponseGameTime = self.convertNetworkStampToGameTime( inResponseClientStamp) self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' % (inResponseGameTime, self.netTimeSentToStartByHit)) if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal: self.notify.warning('ignoring makeCogCarrybarrel') else: barrelModel.setPos(0, -1.0, 1.5) barrelModel.reparentTo(self.suit) self.suit.setPos(cogPos) self.barrel = barrelIndex def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, barrelPos): localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) self.lastLocalTimeStampFromAI = localTimeStamp barrelModel.reparentTo(render) barrelModel.setPos(barrelPos) self.barrel = CTGG.NoBarrelCarried def respondToPieHit(self, timestamp): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showSplat() startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def cleanup(self): self.clearGoal() self.ignoreAll() self.suit.delete() if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.suit = None self.game = None def adjustPlayRate(self, newPos, oldPos, diffTime): lengthTravelled = (newPos - oldPos).length() if diffTime: speed = lengthTravelled / diffTime else: speed = self.cogSpeed rateMult = speed / self.cogSpeed newRate = rateMult * self.defaultPlayRate self.suit.setPlayRate(newRate, 'walk') def commonMove(self): if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() dt = globalClock.getFrameTime() - self.lastThinkTime self.oldpos = self.suit.getPos() pos = self.suit.getPos() pos += self.velocity * dt self.suit.setPos(pos) self.seeFriends() acc = Vec3(0, 0, 0) self.accumulate(acc, self.getTargetVector()) if self.numFlockmatesSeen > 0: keepDistanceVector = self.keepDistance() oldAcc = Vec3(acc) self.accumulate(acc, keepDistanceVector) if self.cogIndex == 0: pass if acc.length() > self.maxAcceleration: acc.normalize() acc *= self.maxAcceleration self.oldVelocity = self.velocity self.velocity += acc if self.velocity.length() > self.maxVelocity: self.velocity.normalize() self.velocity *= self.maxVelocity forwardVec = Vec3(1, 0, 0) heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0])) heading -= 90 self.suit.setH(heading) def getTargetVector(self): targetPos = Point3(0, 0, 0) if self.goal == CTGG.ToonGoal: av = self.game.getAvatar(self.goalId) if av: targetPos = av.getPos() elif self.goal == CTGG.BarrelGoal: barrel = self.game.barrels[self.goalId] targetPos = barrel.getPos() elif self.goal == CTGG.RunAwayGoal: targetPos = CTGG.CogReturnPositions[self.goalId] targetPos.setZ(0) myPos = self.suit.getPos() diff = targetPos - myPos if diff.length() > 1.0: diff.normalize() diff *= 1.0 return diff def accumulate(self, accumulator, valueToAdd): accumulator += valueToAdd return accumulator.length() def seeFriends(self): self.clearVisibleList() for cogIndex in self.game.cogInfo.keys(): if cogIndex == self.cogIndex: continue if self.sameGoal(cogIndex): dist = self.canISee(cogIndex) if dist != self.Infinity: self.addToVisibleList(cogIndex) if dist < self.distToNearestFlockmate: self.nearestFlockmate = cogIndex self.distToNearestFlockmate = dist dist != self.Infinity return self.numFlockmatesSeen def clearVisibleList(self): self.visibleFriendsList = [] self.numFlockmatesSeen = 0 self.nearestFlockmate = None self.distToNearestFlockmate = self.Infinity def addToVisibleList(self, cogIndex): if self.numFlockmatesSeen < self.MaxFriendsVisible: self.visibleFriendsList.append(cogIndex) self.numFlockmatesSeen += 1 if self.cogIndex == 0: pass def canISee(self, cogIndex): if self.cogIndex == cogIndex: return self.Infinity cogThief = self.game.getCogThief(cogIndex) distance = self.suit.getDistance(cogThief.suit) if distance < self.perceptionRange: return distance return self.Infinity def sameGoal(self, cogIndex): cogThief = self.game.getCogThief(cogIndex) if cogThief.goalId == self.goalId: pass result = cogThief.goal == self.goal return result def keepDistance(self): ratio = self.distToNearestFlockmate / self.SeparationDistance nearestThief = self.game.getCogThief(self.nearestFlockmate) change = nearestThief.suit.getPos() - self.suit.getPos() if ratio < self.MinUrgency: ratio = self.MinUrgency if ratio > self.MaxUrgency: ratio = self.MaxUrgency if self.distToNearestFlockmate < self.SeparationDistance: change.normalize() change *= -(1 - ratio) elif self.distToNearestFlockmate > self.SeparationDistance: change.normalize() change *= ratio else: change = Vec3(0, 0, 0) return change def showKaboom(self): if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboom.reparentTo(render) self.kaboom.setPos(self.suit.getPos()) self.kaboom.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.kaboomSound, volume=0.5), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), startScale=Point3(1, 1, 1), blendType='easeOut'), Func(self.kaboom.hide))) self.kaboomTrack.start() def showSplat(self): if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.splat.reparentTo(render) self.splat.setPos(self.suit.getPos()) self.splat.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0), Sequence( Func(self.splat.showThrough), LerpScaleInterval(self.splat, duration=0.5, scale=1.75, startScale=Point3(0.10000000000000001, 0.10000000000000001, 0.10000000000000001), blendType='easeOut'), Func(self.splat.hide))) self.kaboomTrack.start()
class DistributedDodgeballGame(DistributedToonFPSGame, TeamMinigame): """The winter dodgeball minigame (client side)""" notify = directNotify.newCategory("DistributedDodgeballGame") TreeData = [['prop_snow_tree_small_ur', Point3(23.23, 66.52, 7.46)], ['prop_snow_tree_small_ul', Point3(-34.03, 88.02, 24.17)], ['prop_snow_tree_small_ur', Point3(-54.80, 0, 4.19)], ['prop_snow_tree_small_ul', Point3(54.80, -5, 4.19)], ['prop_snow_tree_small_ur', Point3(62.71, 62.66, 16.80)], ['prop_snow_tree_small_ul', Point3(-23.23, -66.52, 6)], ['prop_snow_tree_small_ur', Point3(34.03, -88.02, 23)], ['prop_snow_tree_small_ul', Point3(-62.71, -62.66, 16)]] SnowballData = [ Point3(30, 0, 0.75), Point3(22.5, 0, 0.75), Point3(15, 0, 0.75), Point3(7.5, 0, 0.75), Point3(0, 0, 0.75), Point3(-7.5, 0, 0.75), Point3(-15, 0, 0.75), Point3(-22.5, 0, 0.75), Point3(-30, 0, 0.75) ] GameSong = "phase_4/audio/bgm/MG_Dodgeball.ogg" GameDesc = ( "Welcome to the north! You have been invited to play dodgeball with the penguins!\n\n" "How To Play\nWASD to Move and use the mouse to aim.\nLeft click to Throw!\nThrow a " "snowball at a teammate to unfreeze them!\n\nThe team with the most points after {0} rounds wins!" .format(MaxRounds)) InitCamTrans = [Point3(25, 45, 19.5317), Vec3(154.001, -15, 0)] SnowBallDmg = 25 GetSnowBalls = "Pick up a snowball from the center!" Team2OtherBarrier = {BLUE: "red_barrier_coll", RED: "blue_barrier_coll"} def __init__(self, cr): try: self.DistributedDodgeballGame_initialized return except: self.DistributedDodgeballGame_initialized = 1 DistributedToonFPSGame.__init__(self, cr) TeamMinigame.__init__( self, "BlueSnow", ('phase_4/maps/db_blue_neutral.png', 'phase_4/maps/db_blue_hover.png', 'phase_4/maps/db_blue_hover.png'), "RedIce", ('phase_4/maps/db_red_neutral.png', 'phase_4/maps/db_red_hover.png', 'phase_4/maps/db_red_hover.png')) self.fsm.addState( State('chooseTeam', self.enterChooseTeam, self.exitChooseTeam, ['waitForOthers'])) self.fsm.addState( State('scrollBy', self.enterScrollBy, self.exitScrollBy, ['countdown'])) self.fsm.addState( State('countdown', self.enterCountdown, self.exitCountdown, ['play'])) self.fsm.addState( State('announceGameOver', self.enterAnnGameOver, self.exitAnnGameOver, ['displayWinners', 'countdown'])) self.fsm.addState( State('displayWinners', self.enterDisplayWinners, self.exitDisplayWinners, ['gameOver'])) self.fsm.getStateNamed('waitForOthers').addTransition('chooseTeam') self.fsm.getStateNamed('waitForOthers').addTransition('scrollBy') self.fsm.getStateNamed('play').addTransition('announceGameOver') self.firstPerson = DodgeballFirstPerson(self) self.scrollBySeq = None self.infoText = None self.redScoreLbl = None self.blueScoreLbl = None self.barrierIsStashed = False self.mySpawnPoint = 0 self.infoText = getAlertText() self.spawnPointsByTeam = { BLUE: [[Point3(5, 15, 0), Vec3(180, 0, 0)], [Point3(15, 15, 0), Vec3(180, 0, 0)], [Point3(-5, 15, 0), Vec3(180, 0, 0)], [Point3(-15, 15, 0), Vec3(180, 0, 0)]], RED: [[Point3(5, -15, 0), Vec3(0, 0, 0)], [Point3(15, -15, 0), Vec3(0, 0, 0)], [Point3(-5, -15, 0), Vec3(0, 0, 0)], [Point3(-15, -15, 0), Vec3(0, 0, 0)]] } self.winnerMusic = base.loadMusic( 'phase_9/audio/bgm/encntr_hall_of_fame.ogg') self.loserMusic = base.loadMusic( 'phase_9/audio/bgm/encntr_sting_announce.ogg') self.danceSound = base.loadSfx('phase_3.5/audio/sfx/ENC_Win.ogg') # Environment vars self.arena = None self.olc = None self.trees = [] self.snowballs = [] def snowballPickupResp(self, flag, idx): self.firstPerson.snowballPickupResp(flag, idx) def roundOver(self, time=0): teams = [BLUE, RED] teams.sort(key=lambda team: self.scoreByTeam[team], reverse=True) self.winnerTeam = teams[0] base.localAvatar.disableAvatarControls() self.firstPerson.end() self.deleteTimer() self.fsm.request('announceGameOver', [time]) def getTeamDNAColor(self, team): if team == TEAM1: return ToonDNA.colorDNA2color['18'] elif team == TEAM2: return ToonDNA.colorDNA2color['02'] def enterDisplayWinners(self): base.localAvatar.stopLookAround() base.localAvatar.resetHeadHpr() base.localAvatar.getGeomNode().show() camera.reparentTo(render) camera.setPos((-2.5, 12, 3.5)) camera.setHpr((-175.074, -5.47218, 0)) base.transitions.fadeIn() base.playSfx(self.danceSound, looping=1) if self.winnerTeam == self.team: base.playMusic(self.winnerMusic) else: base.playMusic(self.loserMusic) winnerPositions = [(-2, 0, 0), (2, 0, 0), (6, 0, 0), (-6, 0, 0)] loserPositions = [(-3.5, -10, 0), (-1.5, -15, 0), (3.0, -8, 0), (5.5, -12, 0)] for team in [RED, BLUE]: for avId in self.playerListByTeam[team]: av = self.cr.doId2do.get(avId) if av: av.stopSmooth() av.setHpr(0, 0, 0) if team == self.winnerTeam: posList = winnerPositions av.setAnimState("off") av.stop() if not self.getRemoteAvatar(avId).isFrozen: av.loop("win") else: posList = loserPositions av.setAnimState('off') av.stop() if not self.getRemoteAvatar(avId).isFrozen: av.loop("pout") pos = random.choice(posList) posList.remove(pos) av.setPos(pos) if self.winnerTeam == self.team: text = "YOU WIN!" else: text = "YOU LOSE!" self.gameOverLbl.setText(text) self.track = Sequence(Wait(2.0), Func(self.gameOverLbl.setScale, 0.01), Func(self.gameOverLbl.show), getAlertPulse(self.gameOverLbl, 0.27, 0.25)) self.track.start() base.localAvatar.collisionsOff() def exitDisplayWinners(self): base.localAvatar.collisionsOn() base.transitions.noTransitions() self.danceSound.stop() if hasattr(self, 'track'): self.track.finish() self.track = None self.gameOverLbl.hide() def __prepareForNextRound(self): for av in self.remoteAvatars: av.unFreeze() pos, hpr = self.spawnPointsByTeam[self.team][self.mySpawnPoint] base.localAvatar.setPos(pos) base.localAvatar.setHpr(hpr) self.playMinigameMusic() self.fsm.request('countdown') def enterAnnGameOver(self, timeRanOut=0): self.firstPerson.vModel.hide() text = getGameText() text.setBin('gui-popup', 60) ival = Sequence() if timeRanOut: ival.append(Func(text.setText, "Time's Up!")) ival.append(getRoundIval(text)) ival.append( Func(text.setText, "Round {0} Over!".format(self.getRound()))) ival.append(getRoundIval(text)) team = "Red" if self.winnerTeam == BLUE: team = "Blue" if self.round != MaxRounds: if self.scoreByTeam[RED] == self.scoreByTeam[BLUE]: ival.append(Func(text.setText, "The scores are tied!")) else: ival.append( Func(text.setText, "{0} is in the lead!".format(team))) else: ival.append(Func(text.setText, "{0} wins!".format(team))) ival.append(getRoundIval(text)) ival.setDoneEvent(self.uniqueName('annGameOverDone')) self.acceptOnce(ival.getDoneEvent(), self.__annGameOverTask) self.ival = ival self.ival.start() self.text = text base.transitions.fadeScreen() def __annGameOverTask(self): if self.round == MaxRounds: nextState = Func(self.fsm.request, "displayWinners") else: nextState = Func(self.__prepareForNextRound) self.ival = Sequence(base.transitions.getFadeOutIval(), nextState) self.ival.start() def exitAnnGameOver(self): if hasattr(self, 'ival'): self.ignore(self.ival.getDoneEvent()) self.ival.finish() del self.ival if hasattr(self, 'text'): self.text.destroy() del self.text def teamWon(self, team, time=0): TeamMinigame.teamWon(self, team, time) base.localAvatar.disableAvatarControls() self.firstPerson.end() self.deleteTimer() self.fsm.request('announceGameOver', [time]) def incrementTeamScore(self, team): TeamMinigame.incrementTeamScore(self, team) if team == BLUE: self.blueScoreLbl.setText("BLUE: " + str(self.scoreByTeam[team])) ToontownIntervals.start( ToontownIntervals.getPulseLargerIval(self.blueScoreLbl, 'blueScorePulse')) elif team == RED: self.redScoreLbl.setText("RED: " + str(self.scoreByTeam[team])) ToontownIntervals.start( ToontownIntervals.getPulseLargerIval(self.redScoreLbl, 'redScorePulse')) def getWinterDodgeballScoreText(self, color): text = OnscreenText(fg=color, font=CIGlobals.getMinnieFont(), scale=0.15, shadow=(0, 0, 0, 1)) return text def snowballHitWall(self, snowballIndex): snowball = self.snowballs[snowballIndex] snowball.handleHitWallOrPlayer() base.playSfx(snowball.impactSound, node=snowball, volume=1.5) def snowballHitGround(self, snowballIndex): snowball = self.snowballs[snowballIndex] snowball.handleHitGround() base.playSfx(snowball.impactSound, node=snowball, volume=1.5) def snowballHitPlayer(self, damagedPlayer, throwerTeam, snowballIndex): av = self.getRemoteAvatar(damagedPlayer) if av: if throwerTeam == av.team: # Someone on my team hit me. Unfreeze me if I am frozen. if av.unFreeze(): if damagedPlayer == base.localAvatar.doId: self.showAlert("A team member has unfroze you!") self.firstPerson.camFSM.request('unfrozen') self.sendUpdate('teamMateUnfrozeMe', [self.team]) else: # An enemy hit me. Become frozen if I am not already. if av.freeze(): if damagedPlayer == base.localAvatar.doId: self.showAlert("You've been frozen by an enemy!") self.firstPerson.camFSM.request('frozen') self.sendUpdate('enemyFrozeMe', [self.team, throwerTeam]) snowball = self.snowballs[snowballIndex] snowball.handleHitWallOrPlayer() base.playSfx(snowball.impactSound, node=snowball, volume=1.5) def playerCaughtSnowball(self, snowballIndex, catcherId): av = self.getRemoteAvatar(catcherId) if av: snowball = self.snowballs[snowballIndex] snowball.pauseThrowIval() snowball.pickup(av) def setupRemoteAvatar(self, avId): av = RemoteDodgeballAvatar(self, self.cr, avId) if avId == self.cr.localAvId: self.myRemoteAvatar = av self.remoteAvatars.append(av) def __getSnowTree(self, path): trees = loader.loadModel('phase_8/models/props/snow_trees.bam') tree = trees.find('**/' + path) tree.find('**/*shadow*').removeNode() return tree def load(self): self.setMinigameMusic(DistributedDodgeballGame.GameSong) self.setDescription(DistributedDodgeballGame.GameDesc) self.setWinnerPrize(200) self.setLoserPrize(0) self.createWorld() self.blueScoreLbl = self.getWinterDodgeballScoreText(VBase4( 0, 0, 1, 1)) self.blueScoreLbl.reparentTo(base.a2dTopLeft) self.blueScoreLbl['align'] = TextNode.ALeft self.blueScoreLbl.setText('Blue: 0') self.blueScoreLbl.setZ(-0.17) self.blueScoreLbl.setX(0.05) self.blueScoreLbl.hide() self.redScoreLbl = self.getWinterDodgeballScoreText(VBase4(1, 0, 0, 1)) self.redScoreLbl.reparentTo(base.a2dTopLeft) self.redScoreLbl['align'] = TextNode.ALeft self.redScoreLbl.setText('Red: 0') self.redScoreLbl.setZ(-0.35) self.redScoreLbl.setX(0.05) self.redScoreLbl.hide() trans = DistributedDodgeballGame.InitCamTrans camera.setPos(trans[0]) camera.setHpr(trans[1]) DistributedToonFPSGame.load(self) def createWorld(self): self.deleteWorld() self.arena = loader.loadModel( "phase_4/models/minigames/dodgeball_arena.egg") self.arena.reparentTo(render) self.arena.setScale(0.75) self.arena.find('**/team_divider').setBin('ground', 18) self.arena.find('**/floor').setBin('ground', 18) self.arena.find('**/team_divider_coll').setCollideMask( CIGlobals.FloorBitmask) for data in DistributedDodgeballGame.TreeData: code = data[0] pos = data[1] tree = self.__getSnowTree(code) tree.reparentTo(self.arena) tree.setPos(pos) self.trees.append(tree) for i in xrange(len(DistributedDodgeballGame.SnowballData)): snowdata = DistributedDodgeballGame.SnowballData[i] snowball = Snowball(self, i) snowball.load() snowball.reparentTo(render) snowball.setPos(snowdata) self.snowballs.append(snowball) self.olc = ZoneUtil.getOutdoorLightingConfig(ZoneUtil.TheBrrrgh) self.olc.setupAndApply() def throw(self, snowballIndex, p): snowball = self.snowballs[snowballIndex] snowball.throw(p) def snowballPickup(self, snowballIndex, pickerUpperAvId): remoteAv = self.getRemoteAvatar(pickerUpperAvId) if remoteAv: snowball = self.snowballs[snowballIndex] snowball.pickup(remoteAv) def deleteWorld(self): if self.redScoreLbl: self.redScoreLbl.destroy() self.redScoreLbl = None if self.blueScoreLbl: self.blueScoreLbl.destroy() self.blueScoreLbl = None for snowball in self.snowballs: snowball.removeNode() self.snowballs = [] for tree in self.trees: tree.removeNode() self.trees = [] if self.olc: self.olc.cleanup() self.olc = None if self.arena: self.arena.removeNode() self.arena = None render.clearFog() def enterPlay(self): self.createTimer() self.redScoreLbl.show() self.blueScoreLbl.show() self.firstPerson.camFSM.request('unfrozen') # Stash the other team's barrier. if not self.barrierIsStashed: self.arena.find('**/' + self.Team2OtherBarrier[self.team]).stash() self.barrierIsStashed = True def exitPlay(self): self.firstPerson.crosshair.destroy() self.firstPerson.crosshair = None self.firstPerson.camFSM.request('off') DistributedToonFPSGame.exitPlay(self) def enterCountdown(self): base.transitions.noTransitions() self.firstPerson.start() self.firstPerson.disableMouse() self.setRound(self.getRound() + 1) self.infoText.setText(DistributedDodgeballGame.GetSnowBalls) self.countdownText = getGameText() self.countdownIval = Parallel(Sequence( Func(self.countdownText.setText, "Round {0}".format(self.getRound())), getRoundIval(self.countdownText), Func(self.countdownText.setText, "5"), getCountdownIval(self.countdownText), Func(self.countdownText.setText, "4"), getCountdownIval(self.countdownText), Func(self.countdownText.setText, "3"), getCountdownIval(self.countdownText), Func(self.countdownText.setText, "2"), getCountdownIval(self.countdownText), Func(self.countdownText.setText, "1"), getCountdownIval(self.countdownText)), getAlertPulse(self.infoText), name="COUNTDOWNIVAL") self.countdownIval.setDoneEvent(self.countdownIval.getName()) self.acceptOnce(self.countdownIval.getDoneEvent(), self.__handleCountdownDone) self.countdownIval.start() def __handleCountdownDone(self): self.fsm.request('play') def exitCountdown(self): if hasattr(self, 'countdownIval'): self.ignore(self.countdownIval.getDoneEvent()) self.countdownIval.finish() del self.countdownIval if hasattr(self, 'countdownText'): self.countdownText.destroy() del self.countdownText def enterScrollBy(self): BLUE_START_POS = Point3(-20, 0, 4) BLUE_END_POS = Point3(20, 0, 4) BLUE_HPR = Vec3(0, 0, 0) RED_START_POS = Point3(20, 0, 4) RED_END_POS = Point3(-20, 0, 4) RED_HPR = Vec3(180, 0, 0) self.playMinigameMusic() self.scrollBySeq = Sequence(Func(camera.setHpr, BLUE_HPR), LerpPosInterval(camera, duration=5.0, pos=BLUE_END_POS, startPos=BLUE_START_POS, blendType='easeOut'), Func(base.transitions.fadeOut, 0.4), Wait(0.5), Func(base.transitions.fadeIn, 0.4), Func(camera.setHpr, RED_HPR), LerpPosInterval(camera, duration=5.0, pos=RED_END_POS, startPos=RED_START_POS, blendType='easeOut'), name="SCROLLBYSEQ") self.scrollBySeq.setDoneEvent(self.scrollBySeq.getName()) self.acceptOnce(self.scrollBySeq.getDoneEvent(), self.__handleScrollByDone) self.scrollBySeq.start() def __handleScrollByDone(self): self.fsm.request('countdown') def exitScrollBy(self): if self.scrollBySeq: self.ignore(self.scrollBySeq.getDoneEvent()) self.scrollBySeq.finish() self.scrollBySeq = None def allPlayersReady(self): self.fsm.request('scrollBy') def chooseUrTeam(self): # The AI has told us it's time to choose our team. self.fsm.request('chooseTeam') def enterChooseTeam(self): self.makeSelectionGUI() def acceptedIntoTeam(self, spawnPoint): TeamMinigame.acceptedIntoTeam(self) self.sendUpdate('readyToStart') self.fsm.request('waitForOthers') self.mySpawnPoint = spawnPoint pos, hpr = self.spawnPointsByTeam[self.team][spawnPoint] base.localAvatar.setPos(pos) base.localAvatar.setHpr(hpr) def exitChooseTeam(self): self.destroySelectionGUI() def announceGenerate(self): DistributedToonFPSGame.announceGenerate(self) base.camLens.setMinFov(CIGlobals.GunGameFOV / (4. / 3.)) self.load() def disable(self): base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4. / 3.)) self.fsm.requestFinalState() self.deleteWorld() self.trees = None self.snowballs = None self.spawnPointsByTeam = None if self.firstPerson: self.firstPerson.reallyEnd() self.firstPerson.cleanup() self.firstPerson = None self.scrollBySeq = None self.winnerMusic = None self.loserMusic = None self.danceSound = None self.infoText = None base.localAvatar.setWalkSpeedNormal() DistributedToonFPSGame.disable(self)
class Connect4: def __init__(self, p_base): self.base = p_base self.render = p_base.render # Keyboard inputs map self.keyMap = {"left": False, "right": False, "down": False, "drop": False} # Global parameters self.player = 1 self.speed = 15 self.movement_V = False self.movement_H = False self.axes_H = [-3.6, -2.4, -1.2, 0, 1.2, 2.4, 3.6] self.axes_V = [0.25, -1.0, -2.25, -3.5, -4.75, -6] self.column = 3 self.line = 5 self.quit_game_bool = False self.round = 0 # Initialization of audio coin self.audio_coin = self.base.loader.loadMusic("connect4/audio/coin.ogg") # Initialization of the table self.table = self.base.loader.loadModel("connect4/models/table") self.table.reparentTo(self.render) self.table.setScale(2, 2, 2) self.table.setHpr(90, 0, 0) self.table_anim_start = self.table.posInterval(3, Point3(0, 30, -8), startPos=Point3(0, 0, -8)) self.table_anim_end = self.table.posInterval(3, Point3(0, 0, -8), startPos=Point3(0, 30, -8)) # Initialization of the grid self.grid = self.base.loader.loadModel("connect4/models/grid") self.grid.reparentTo(self.render) self.grid.setColor(0.1, 0.2, 0.8, 1.0) self.grid.setHpr(90, 0, 0) self.grid.setScale(0.6, 0.6, 0.625) self.grid_anim_start = self.grid.posInterval(3, Point3(3.6, 30, -6), startPos=Point3(3.6, 30, 0)) self.grid_anim_end = self.grid.posInterval(3, Point3(3.6, 30, 0), startPos=Point3(3.6, 30, -6)) self.gridContent = np.zeros(6 * 7) # Initialization of the discs self.discs = [] self.nb_discs = 44 for i in range(0, self.nb_discs): disc = self.base.loader.loadModel("connect4/models/disc") disc.reparentTo(self.render) if i % 2 == 0: color_disc = Disc(i, disc, 1.0, 0.0, 0.0) else: color_disc = Disc(i, disc, 1.0, 1.0, 0.0) self.discs.append(color_disc) self.first_disc_anim = self.discs[self.round].disc.posInterval(3, Point3(0, 30, 1.5), startPos=Point3(0, 0, 8)) # Initialization of start sequences self.init_sequence = Parallel(self.table_anim_start, self.grid_anim_start, self.first_disc_anim, name="p_start") self.init_sequence.start() # Initialization of keys self.base.accept("arrow_left", self.updateKeyMap, ["left", True]) self.base.accept("arrow_left-up", self.updateKeyMap, ["left", False]) self.base.accept("arrow_right", self.updateKeyMap, ["right", True]) self.base.accept("arrow_right-up", self.updateKeyMap, ["right", False]) self.base.accept("arrow_down", self.updateKeyMap, ["down", True]) self.base.accept("arrow_down-up", self.updateKeyMap, ["down", False]) self.base.accept("space", self.updateKeyMap, ["drop", True]) self.base.accept("space-up", self.updateKeyMap, ["drop", False]) # Initialization of winning cases self.results = [] with open("connect4/csv/cases.csv") as csvfile: reader = csv.reader(csvfile, quoting=csv.QUOTE_NONNUMERIC) for row in reader: self.results.append(row) # Initialization of fonts self.font = self.base.loader.loadFont("connect4/font/Roboto-Medium.ttf") self.font.setPixelsPerUnit(60) # Initialization of the victory text self.text_victory = OnscreenText(text='', pos=(1.4, -0.8), scale=0.1) self.text_victory.setFg((0, 0, 0, 1)) self.text_victory.setBg((1, 1, 1, 0)) self.text_victory.setShadow((0.5, 0.5, 0.5, 1)) # Initialization of buttons self.load_game_button = DirectButton(text="Load", pos=(-1.5, 0, 0.75), frameSize=(-3, 3, -0.5, 1), scale=.1, text_scale=0.9, command=self.load_game) self.new_game_button = DirectButton(text="New game", pos=(-1.5, 0, 0.9), frameSize=(-3, 3, -0.5, 1), scale=.1, text_scale=0.9, command=self.new_game) self.button_changed = False self.save_game_button = DirectButton(text="Save", pos=(-1.5, 0, 0.6), frameSize=(-3, 3, -0.5, 1), scale=.1, text_scale=0.9, command=self.save_game) self.quit_game_button = DirectButton(text="Quit", pos=(-1.5, 0, -0.95), frameSize=(-3, 3, -0.5, 1), scale=.1, text_scale=0.9, command=self.quit_game) self.hand_control_button = DirectButton(text="Activer le contrôle \n visuel", pos=(1.5, 0, -0.9), frameSize=(-3, 3, -1, 0.8), scale=.1, text_scale=0.5, command=self.activate_hand_control) # Mode # (mode 0 : default mode) # (mode 1 : hand control mode) self.mode = 0 self.disc_caught = -1 self.disc_dropped = -1 # Initialization of the right hand self.right_hand = self.base.loader.loadModel("connect4/models/hand") self.right_hand.reparentTo(self.render) self.right_hand.setPos(3.6, -20, 0) self.right_hand.setColor(0.88, 0.67, 0.41, 1.0) self.right_hand.setHpr(90, -90, 0) self.right_hand.setScale(0.2, 0.2, 0.2) # self.left_hand = self.base.loader.loadModel("connect4/models/hand") # self.left_hand.reparentTo(self.render) # self.left_hand.setPos(-3.6, -20, 0) # self.left_hand.setColor(0.88, 0.67, 0.41, 1.0) # self.left_hand.setHpr(90, -90, 180) # self.left_hand.setScale(0.2, 0.2, 0.2) def activate_hand_control(self): if self.mode == 0: self.mode = 1 self.hand_control_button.setText("Désactiver le contrôle \n visuel") self.right_hand.setPos(3.6, 30, 0) self.new_game() # self.left_hand.setPos(-3.6, 20, 0) else: self.mode = 0 self.hand_control_button.setText("Activer le contrôle \n visuel") self.right_hand.setPos(3.6, -20, 0) self.new_game() # self.left_hand.setPos(-3.6, -20, 0) def updateKeyMap(self, key, state): """ Function that updates the input map """ self.keyMap[key] = state def load_game(self): """ Load game functions used for load game button """ print("Connect 4 > Load a game") f1 = open("connect4/safeguard/safeguard.txt", "r") last_line = f1.readlines()[-1] f1.close() last_line_list = last_line.split(',') k = 0 p = 1 round = 0 for i in range(0, 42): col = i % 7 line = i // 7 if last_line_list[i] == '1': self.discs[k].disc.setPos(self.axes_H[col], 30, self.axes_V[line]) k += 2 round += 1 elif last_line_list[i] == '2': self.discs[p].disc.setPos(self.axes_H[col], 30, self.axes_V[line]) p += 2 round += 1 self.round = round self.discs[self.round].disc.setPos(0, 30, 1.5) self.gridContent = [int(j) for j in last_line_list] def new_game(self): """ New game functions used for new game button """ print("Connect 4 > New game") self.gridContent = np.zeros(6 * 7) self.round = 0 self.text_victory.setText('') if self.mode == 0: for i in range(0, 42): self.discs[i].disc.setPos(100, 100, 100) self.discs[self.round].disc.setPos(0, 30, 1.5) elif self.mode == 1: pos_xr = [-8.4, -7.2, -6.0, -12, -10.8, -9.6, -8.4, -7.2, -6.0, -12, -10.8, -9.6, -8.4, -7.2, -6.0, -12, -10.8, -9.6, -8.4, -7.2, -6.0] pos_xy = [8.4, 7.2, 6.0, 12, 10.8, 9.6, 8.4, 7.2, 6.0, 12, 10.8, 9.6, 8.4, 7.2, 6.0, 12, 10.8, 9.6, 8.4, 7.2, 6.0] pos_z = [-6.4, -6.4, -6.4, -5.2, -5.2, -5.2, -5.2, -5.2, -5.2, -4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -2.8, -2.8, -2.8, -2.8, -2.8, -2.8] n = 0 p = 0 for i in range(0, 42): if i % 2 == 0: self.discs[i].disc.setPos(pos_xr[n], 30, pos_z[n]) n += 1 else: self.discs[i].disc.setPos(pos_xy[p], 30, pos_z[p]) p += 1 def save_game(self): """ Save game functions used for save game button """ print("Connect 4 > Save the game") grid = [int(j) for j in self.gridContent] grid_content_str = ','.join([str(elem) for elem in grid]) f = open("connect4/safeguard/safeguard.txt", "a") f.write(grid_content_str + "\n") f.close() def quit_game(self): """ Quit game functions used for quit game button """ print("Connect 4 > Quit the game") for i in range(0, self.nb_discs): self.discs[i].disc.removeNode() self.grid.removeNode() self.table.removeNode() self.new_game_button.destroy() self.save_game_button.destroy() self.load_game_button.destroy() self.quit_game_button.destroy() self.quit_game_bool = True def check_victory(self): """ Function that check if there is a victory case @return 1 if red wins and 2 if yellow wins """ if self.mode == 0: num_disc = self.round elif self.mode == 1: num_disc = self.disc_dropped if num_disc % 2 == 0: disc_type = 1 else: disc_type = 2 self.gridContent[7 * self.line + self.column] = disc_type for i in range(69): for j in range(4): if self.results[i][j] == 7 * self.line + self.column: if (self.gridContent[int(self.results[i][0])] == disc_type) and ( self.gridContent[int(self.results[i][1])] == disc_type) and ( self.gridContent[int(self.results[i][2])] == disc_type) and ( self.gridContent[int(self.results[i][3])] == disc_type): return disc_type return 0 def mainloop(self): """ Main loop of the connect 4 game """ # If quit_button is clicked if self.quit_game_bool: return 0 # Get the clock dt = globalClock.getDt() # Change the button "New game" to "Restart" for the first round if self.round == 1 and self.button_changed == False: self.new_game_button["text"] = "Restart" self.button_changed = True print("Connect 4 > Main loop") # Default mode if self.mode == 0: # Get the position of the current disc pos = self.discs[self.round].disc.getPos() # Left click if self.keyMap["left"] and self.column != 0 and not self.movement_V: self.keyMap["left"] = False self.column -= 1 self.movement_H = True # Right click if self.keyMap["right"] and self.column != 6 and not self.movement_V: self.keyMap["right"] = False self.column += 1 self.movement_H = True # down clic if self.keyMap["down"] and self.gridContent[self.column] == 0 and not self.movement_V: # To have only one click self.keyMap["down"] = False # Find the final disc line line_fixed = 0 self.line = 5 while line_fixed == 0 and self.line >= 0: if self.gridContent[7 * self.line + self.column] != 0: self.line -= 1 else: line_fixed = 1 self.movement_V = True # check if there is a victory or not victory = self.check_victory() if victory == 1: self.text_victory.setText('Red wins') if victory == 2: self.text_victory.setText('Yellow wins') # Progressive vertical movement if self.movement_V and pos.z >= self.axes_V[self.line]: pos.z -= self.speed * dt self.discs[self.round].disc.setPos(pos) # Set the disc position / Prepare next disc if self.movement_V and pos.z <= self.axes_V[self.line]: pos.z = self.axes_V[self.line] self.discs[self.round].disc.setPos(pos) self.audio_coin.play() self.movement_V = False self.line = 0 self.column = 3 self.round += 1 if self.round < 42 and self.mode == 0: self.discs[self.round].disc.setPos(0, 30, 1.5) # Horizontal movement if self.mode == 0 and self.movement_H: pos.x = self.axes_H[self.column] self.discs[self.round].disc.setPos(pos) self.movement_H = False # Handplay mode if self.mode == 1: # Detect hand position if cap.isOpened(): success, image = cap.read() image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB) image.flags.writeable = False results = hands.process(image) # Draw the hand annotations on the image. image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # If a hand is detected if results.multi_hand_landmarks: for hand_landmarks in results.multi_hand_landmarks: for idx, landmark in enumerate(hand_landmarks.landmark): if idx == 9: x = 24 * landmark.x - 12 z = - 14 * landmark.y + 7 self.right_hand.setPos(x, 30, z) # If a is caught if self.disc_caught != -1: self.discs[self.disc_caught].disc.setPos(self.right_hand.getPos().x - 0.5, 30, self.right_hand.getPos().z + 0.5) else: for i in range(0, 42): if (abs(self.right_hand.getPos().x - 0.5 - self.discs[i].disc.getPos().x) < 0.5) \ and abs(self.right_hand.getPos().z - self.discs[i].disc.getPos().z) < 0.5: self.disc_caught = self.discs[i].id print("Connect 4 > Disc n°", self.disc_caught, " is caught") self.discs[self.disc_caught].disc.setPos(x - 0.5, 30, z + 0.5) # If space touch is pressed if self.keyMap["drop"]: print("Connect 4 > Disc n°", self.disc_caught, " is dropped") self.keyMap["drop"] = False pos_x = self.discs[self.disc_caught].disc.getPos().x min = 10 for i in range(len(self.axes_H)): if abs(self.axes_H[i] - pos_x) < min: self.column = i min = abs(self.axes_H[i] - pos_x) # Find the final disc line line_fixed = 0 self.line = 5 while line_fixed == 0 and self.line >= 0: if self.gridContent[7 * self.line + self.column] != 0: self.line -= 1 else: line_fixed = 1 self.movement_V = True self.discs[self.disc_caught].disc.setPos(self.axes_H[self.column], 30, self.axes_V[0]) self.disc_dropped = self.disc_caught self.disc_caught = -1 # check if there is a victory or not victory = self.check_victory() if victory == 1: self.text_victory.setText('Red wins') if victory == 2: self.text_victory.setText('Yellow wins') # Progressive vertical movement pos = self.discs[self.disc_dropped].disc.getPos() if self.movement_V and pos.z >= self.axes_V[self.line]: pos.z -= self.speed * dt self.discs[self.disc_dropped].disc.setPos(pos) # Set the disc position if self.movement_V and pos.z <= self.axes_V[self.line]: pos.z = self.axes_V[self.line] self.discs[self.disc_dropped].disc.setPos(pos) self.audio_coin.play() self.movement_V = False self.line = 0 self.column = 3 self.round += 1 return 1
class PairingGameCard(PlayingCardNodePath): DoIntervalDefault = True FlipTime = 0.25 UseDifferentCardColors = True CardColors = [(0.933594, 0.265625, 0.28125, 1.0), (0.550781, 0.824219, 0.324219, 1.0), (0.347656, 0.820312, 0.953125, 1.0), (0.460938, 0.378906, 0.824219, 1.0), (0.710938, 0.234375, 0.4375, 1.0), (0.285156, 0.328125, 0.726562, 1.0), (0.242188, 0.742188, 0.515625, 1.0), (0.96875, 0.691406, 0.699219, 1.0), (0.996094, 0.957031, 0.597656, 1.0), (0.992188, 0.480469, 0.167969, 1.0)] def __init__(self, value): style = PlayingCardGlobals.Styles[0] PlayingCardNodePath.__init__(self, style, value) self.enterCallback = None self.exitCallback = None return def load(self): oneCard = loader.loadModel('phase_4/models/minigames/garden_sign_memory') prop = self.attachNewNode('prop') PlayingCardGlobals.getImage(self.style, self.suit, self.rank).copyTo(prop) prop.setScale(7) oneCard.find('**/glow').removeNode() cs = oneCard.find('**/collision') for solidIndex in xrange(cs.node().getNumSolids()): cs.node().modifySolid(solidIndex).setTangible(False) cs.node().setName('cardCollision-%d' % self.value) sign = oneCard.find('**/sign1') if self.UseDifferentCardColors: index = self.rank % len(self.CardColors) color = self.CardColors[index] sign.setColorScale(*color) prop.setPos(0.0, 0.0, 0.08) prop.setP(-90) prop.reparentTo(oneCard) oneCard.reparentTo(self) cardBack = oneCard.find('**/sign2') cardBack.setColorScale(0.12, 0.35, 0.5, 1.0) cardModel = loader.loadModel('phase_3.5/models/gui/playingCard') logo = cardModel.find('**/logo') logo.reparentTo(self) logo.setScale(0.45) logo.setP(90) logo.setZ(0.025) logo.setX(-0.05) logo.setH(180) cardModel.removeNode() self.setR(0) self.setScale(2.5) self.flipIval = None self.turnUpSound = base.loader.loadSfx('phase_4/audio/sfx/MG_pairing_card_flip_face_up.ogg') self.turnDownSound = base.loader.loadSfx('phase_4/audio/sfx/MG_pairing_card_flip_face_down.ogg') return def unload(self): self.clearFlipIval() self.removeNode() del self.turnUpSound del self.turnDownSound def turnUp(self, doInterval = DoIntervalDefault): self.faceUp = 1 if doInterval: self.clearFlipIval() self.flipIval = Parallel(LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 0)), SoundInterval(self.turnUpSound, node=self, listenerNode=base.localAvatar, cutOff=240)) self.flipIval.start() else: self.setR(0) def clearFlipIval(self): if self.flipIval: self.flipIval.finish() self.flipIval = None return def turnDown(self, doInterval = DoIntervalDefault): self.faceUp = 0 if doInterval: self.clearFlipIval() self.flipIval = Parallel(LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 180)), SoundInterval(self.turnDownSound, node=self, listenerNode=base.localAvatar, cutOff=240)) self.flipIval.start() else: self.setR(180)
class HangUpAttack(Attack): notify = directNotify.newCategory('HangUpAttack') attack = 'hangup' def __init__(self, attacksClass, suit): Attack.__init__(self, attacksClass, suit) self.phone = None self.receiver = None self.collNP = None self.phoneSfx = None self.hangupSfx = None self.shootIval = None self.cord = None self.receiverOutCord = None self.phoneOutCord = None return def loadAttack(self): self.phone = loader.loadModel('phase_3.5/models/props/phone.bam') self.phone.setHpr(0, 0, 180) if self.suit.type == 'B': self.phone.setPos(0.7, 0.15, 0) elif self.suit.type == 'C': self.phone.setPos(0.25, 0, 0) self.receiver = loader.loadModel('phase_3.5/models/props/receiver.bam') self.receiver.reparentTo(self.phone) self.cord = Rope() self.cord.ropeNode.setUseVertexColor(1) self.cord.ropeNode.setUseVertexThickness(1) self.cord.setup(3, ({'node': self.phone, 'point': (0.8, 0, 0.2), 'color': (0, 0, 0, 1), 'thickness': 1000}, {'node': self.phone, 'point': (2, 0, 0), 'color': (0, 0, 0, 1), 'thickness': 1000}, {'node': self.receiver, 'point': (1.1, 0.25, 0.5), 'color': (0, 0, 0, 1), 'thickness': 1000}), []) self.cord.setH(180) self.phoneSfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/SA_hangup.mp3') base.audio3d.attachSoundToObject(self.phoneSfx, self.phone) self.hangupSfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/SA_hangup_place_down.mp3') base.audio3d.attachSoundToObject(self.hangupSfx, self.phone) collSphere = CollisionSphere(0, 0, 0, 2) collSphere.setTangible(0) collNode = CollisionNode('phone_shootout') collNode.addSolid(collSphere) collNode.setCollideMask(CIGlobals.WallBitmask) self.collNP = self.phone.attachNewNode(collNode) def doAttack(self, ts = 0): self.loadAttack() if hasattr(self.suit, 'uniqueName'): name = self.suit.uniqueName('doHangupAttack') else: name = 'doHangupAttack' if self.suit.type == 'A': delay2playSound = 1.0 delayAfterSoundToPlaceDownReceiver = 0.2 delayAfterShootToIgnoreCollisions = 1.0 delay2PickUpReceiver = 1.0 receiverInHandPos = Point3(-0.5, 0.5, -1) elif self.suit.type == 'B': delay2playSound = 1.5 delayAfterSoundToPlaceDownReceiver = 0.7 delayAfterShootToIgnoreCollisions = 1.0 delay2PickUpReceiver = 1.5 receiverInHandPos = Point3(-0.3, 0.5, -0.8) elif self.suit.type == 'C': delay2playSound = 1.0 delayAfterSoundToPlaceDownReceiver = 1.15 delayAfterShootToIgnoreCollisions = 1.0 delay2PickUpReceiver = 1.5 receiverInHandPos = Point3(-0.3, 0.5, -0.8) self.suitTrack = Parallel(name=name) self.suitTrack.append(ActorInterval(self.suit, 'phone')) self.suitTrack.append(Sequence(Wait(delay2playSound), SoundInterval(self.phoneSfx, duration=2.1), Wait(delayAfterSoundToPlaceDownReceiver), Func(self.receiver.setPos, 0, 0, 0), Func(self.receiver.setH, 0.0), Func(self.receiver.reparentTo, self.phone), Func(self.acceptOnce, 'enter' + self.collNP.node().getName(), self.handleCollision), Func(self.shootOut), Parallel(SoundInterval(self.hangupSfx), Sequence(Wait(delayAfterShootToIgnoreCollisions), Func(self.ignore, 'enter' + self.collNP.node().getName()))))) self.suitTrack.append(Sequence(Func(self.phone.reparentTo, self.suit.find('**/joint_Lhold')), Func(self.cord.reparentTo, render), Wait(delay2PickUpReceiver), Func(self.receiver.reparentTo, self.suit.find('**/joint_Rhold')), Func(self.receiver.setPos, receiverInHandPos), Func(self.receiver.setH, 270.0))) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.finishedAttack) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self.suit, name) self.suitTrack.start(ts) def handleCollision(self, entry): if self.suit: self.suit.sendUpdate('toonHitByWeapon', [self.getAttackId(self.attack), base.localAvatar.doId]) base.localAvatar.b_handleSuitAttack(self.getAttackId(self.attack), self.suit.doId) def shootOut(self): pathNode = NodePath('path') pathNode.reparentTo(self.suit) pathNode.setPos(0, 50, self.phone.getZ(self.suit)) self.collNP.reparentTo(render) self.shootIval = LerpPosInterval(self.collNP, duration=1.0, pos=pathNode.getPos(render), startPos=self.phone.getPos(render)) self.shootIval.start() pathNode.removeNode() del pathNode def cleanup(self): Attack.cleanup(self) if self.shootIval: self.shootIval.pause() self.shootIval = None if self.cord: self.cord.removeNode() self.cord = None if self.phone: self.phone.removeNode() self.phone = None if self.receiver: self.receiver.removeNode() self.receiver = None if self.collNP: self.collNP.node().clearSolids() self.collNP.removeNode() self.collNP = None if self.phoneSfx: self.phoneSfx.stop() self.phoneSfx = None return
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedPartyGate') def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = 'doneChoosingPublicParty' self.publicPartyGui = PublicPartyGui( self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept('stoppedAsleep', self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in range(1, 13): if i < 10: si = '0%d' % i else: si = '%d' % i self.clockSounds.append( base.loadSfx('phase_4/audio/sfx/clock%s.mp3' % si)) def generate(self): DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGate_grp') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return self.clockFlat = partyGate.find('**/clock_flat') collSphere = CollisionSphere(0, 0, 0, 6.9) collSphere.setTangible(1) self.partyGateSphere = CollisionNode('PartyGateSphere') self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find( '**/partyGate_stepsLocator').attachNewNode(self.partyGateSphere) self.__enableCollisions() self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos( partyGate.find('**/clockText_locator').getPos() + Point3(0.0, 0.0, -0.2)) self.toontownTimeGui.setHpr( partyGate.find('**/clockText_locator').getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGateSignGroup') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find('**/signTextL_locatorBack') signScale = 0.35 wordWrap = 8 leftText = DirectLabel.DirectLabel(parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) rightSign = partyGate.find('**/signTextR_locatorFront') rightText = DirectLabel.DirectLabel( parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if ToontownGlobals.dnaMap.has_key(self.zoneId): playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel[ 'text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel[ 'text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel[ 'text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel[ 'text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self.__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None return def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName('messageDoneEvent') self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog( doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge) def __handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None return def __handleAskDone(self): DistributedPartyGate.notify.debug('__handleAskDone') self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: self.freeAvatar() return self.sendUpdate('partyChoiceRequest', [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) return def partyRequestDenied(self, reason): DistributedPartyGate.notify.debug( 'partyRequestDenied( reason=%s )' % PartyGlobals.PartyGateDenialReasons.getString(reason)) if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple): DistributedPartyGate.notify.debug('setParty') self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug( 'Public Party closed before toon could get to it.') return shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple if base.localAvatar.defaultShard == shardId: shardId = None base.cr.playGame.getPlace().requestLeave({ 'loader': 'safeZoneLoader', 'where': 'party', 'how': 'teleportIn', 'hoodId': ToontownGlobals.PartyHood, 'zoneId': zoneId, 'shardId': shardId, 'avId': -1 }) return def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState('walk') def hourChange(self, currentHour): currentHour = currentHour % 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() seq1 = Sequence() for i in range(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.2)) timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in range(currentHour): seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(0.9, 1.0, 1.2), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.9), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType='easeInOut')) self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug('Entering steps Sphere....') base.cr.playGame.getPlace().fsm.request('stopped') self.sendUpdate('getPartyList', [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): self.notify.debug('listAllPublicParties : publicPartyInfo = %s' % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self.__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def __enableCollisions(self): self.accept('enterPartyGateSphere', self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def __disableCollisions(self): self.ignore('enterPartyGateSphere') self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, 'messageGui') and self.messageGui: self.__handleMessageDone()
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory( "DistributedPartyGate") def __init__(self, cr): """__init__(cr) """ DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = "doneChoosingPublicParty" self.publicPartyGui = PublicPartyGui( self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept('stoppedAsleep', self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in range(1, 13): if i < 10: si = "0%d" % i else: si = "%d" % i self.clockSounds.append( base.loader.loadSfx("phase_4/audio/sfx/clock%s.mp3" % si)) 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. """ DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGate_grp') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return self.clockFlat = partyGate.find("**/clock_flat") collSphere = CollisionSphere(0, 0, 0, 6.9) collSphere.setTangible(1) self.partyGateSphere = CollisionNode("PartyGateSphere") self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find( "**/partyGate_stepsLocator").attachNewNode(self.partyGateSphere) self.__enableCollisions() # self.tunnelOrigin = NodePath("PartyGateTunnelOrigin") # self.tunnelOrigin.reparentTo(partyGate) # self.tunnelOrigin.setPos(partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -12.0)) self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos( partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -0.2)) self.toontownTimeGui.setHpr( partyGate.find("**/clockText_locator").getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): """Attach text to the left and right signs""" loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGateSignGroup') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find("**/signTextL_locatorBack") signScale = 0.35 wordWrap = 8 leftText = DirectLabel.DirectLabel( parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale, ) rightSign = partyGate.find("**/signTextR_locatorFront") rightText = DirectLabel.DirectLabel( parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale, ) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if self.zoneId in ToontownGlobals.dnaMap: playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self.__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName("messageDoneEvent") self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog( doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge, ) def __handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None def __handleAskDone(self): DistributedPartyGate.notify.debug("__handleAskDone") self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: # They don't want to party... just let them walk away from the hat self.freeAvatar() return self.sendUpdate("partyChoiceRequest", [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) def partyRequestDenied(self, reason): """ Called by the AI when the player's request to join a public party was denied. """ DistributedPartyGate.notify.debug( "partyRequestDenied( reason=%s )" % PartyGlobals.PartyGateDenialReasons.getString(reason)) # let the local toon know that they were denied # TODO-parties: tell player through gui if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple): """ Gets called by the AI server with the approved partyId. """ DistributedPartyGate.notify.debug("setParty") self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug( "Public Party closed before toon could get to it.") return # We now need to enter the party with the given partyId, that is, move # our toon toward the hat entrance and do the appropriate state transition shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple if base.localAvatar.defaultShard == shardId: shardId = None base.cr.playGame.getPlace().requestLeave({ "loader": "safeZoneLoader", "where": "party", "how": "teleportIn", "hoodId": ToontownGlobals.PartyHood, "zoneId": zoneId, "shardId": shardId, "avId": -1, # "partyHat" : True, # "tunnelOrigin" : self.tunnelOrigin, }) def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState("walk") def hourChange(self, currentHour): currentHour = currentHour % 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() # Make a sequence with all the clock sounds seq1 = Sequence() for i in range(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.2)) # Now make a sequence that will deform the clock face timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in range(currentHour): seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(0.9, 1.0, 1.2), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.9), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType='easeInOut')) # Now parallel the two together self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug("Entering steps Sphere....") # Freeze the toon, don't let him walk away... base.cr.playGame.getPlace().fsm.request('stopped') self.sendUpdate("getPartyList", [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): """ Called from DistributedPartyGateAI with a tuple of all the public party information as told to it by the DistributedPartyManagerAI in order of newest party to oldest party. ( shardId, zoneId, numberOfGuests, hostName, activityIds, minLeft ) """ self.notify.debug("listAllPublicParties : publicPartyInfo = %s" % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self.__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def __enableCollisions(self): # start listening for toons to enter. self.accept('enterPartyGateSphere', self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def __disableCollisions(self): # stop listening for toons. self.ignore('enterPartyGateSphere') self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, 'messageGui'): self.__handleMessageDone()
class DistributedPairingGame(DistributedMinigame): TOON_SPEED = 11 MAX_FRAME_MOVE = 1 MAX_FACE_UP_CARDS = 2 notify = directNotify.newCategory('DistributedPairingGame') bonusGlowTime = 0.5 EndGameTaskName = 'endPairingGame' xCardInc = 4 cardsPerRow = 8 cardsPerCol = 5 def __init__(self, cr): DistributedMinigame.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM('DistributedPairingGame', [ State.State('off', self.enterOff, self.exitOff, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, []) ], 'off', 'cleanup') self.addChildGameFSM(self.gameFSM) self.cameraTopView = (17.6, 6.18756, 43.9956, 0, -89, 0) self.cameraThreeQuarterView = (14.0, -8.93352, 33.4497, 0, -62.89, 0) self.deckSeed = 0 self.faceUpList = [] self.localFaceUpList = [] self.inList = [] self.inactiveList = [] self.points = 0 self.flips = 0 self.matches = 0 self.yCardInc = 4 self.startingPositions = [ (0, 0, 0, -45), ((self.cardsPerRow - 1) * self.xCardInc, (self.cardsPerCol - 1) * self.yCardInc, 0, 135), ((self.cardsPerRow - 1) * self.xCardInc, 0, 0, 45), (0, (self.cardsPerCol - 1) * self.yCardInc, 0, -135) ] self.stageMin = Point2(0, 0) self.stageMax = Point2((self.cardsPerRow - 1) * self.xCardInc, (self.cardsPerCol - 1) * self.yCardInc) self.gameDuration = PairingGameGlobals.EasiestGameDuration def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def getTitle(self): return TTLocalizer.PairingGameTitle def getInstructions(self): if self.numPlayers > 1: return TTLocalizer.PairingGameInstructionsMulti else: return TTLocalizer.PairingGameInstructions def getMaxDuration(self): return 0 def load(self): self.notify.debug('load') DistributedMinigame.load(self) self.gameDuration = PairingGameGlobals.calcGameDuration( self.getDifficulty()) self.gameBoard = loader.loadModel( 'phase_4/models/minigames/memory_room') self.gameBoard.setPosHpr(0.5, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.deck = PairingGameGlobals.createDeck(self.deckSeed, self.numPlayers) self.notify.debug('%s' % self.deck.cards) testCard = self.getDeckOrderIndex(self.cardsPerCol - 1, 0) if not testCard > -1: self.yCardInc *= 1.25 self.cards = [] for index in xrange(len(self.deck.cards)): cardValue = self.deck.cards[index] oneCard = PairingGameCard.PairingGameCard(cardValue) oneCard.load() xPos, yPos = self.getCardPos(index) oneCard.setPos(xPos, yPos, 0) oneCard.reparentTo(render) self.notify.debug('%s' % oneCard.getPos()) self.notify.debug('suit %s rank %s value %s' % (oneCard.suit, oneCard.rank, oneCard.value)) self.accept('entercardCollision-%d' % oneCard.value, self.enterCard) self.accept('exitcardCollision-%d' % oneCard.value, self.exitCard) oneCard.turnDown(doInterval=False) self.cards.append(oneCard) self.bonusTraversal = range(len(self.cards)) self.bonusGlow = render.attachNewNode('bonusGlow') sign = loader.loadModel('phase_4/models/minigames/garden_sign_memory') sign.find('**/sign1').removeNode() sign.find('**/sign2').removeNode() sign.find('**/collision').removeNode() sign.setPos(0, 0, 0.05) sign.reparentTo(self.bonusGlow) self.bonusGlow.setScale(2.5) self.pointsFrame = DirectFrame(relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(-0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGamePoints, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGpointsFrame, text_pos=(-1.94, -0.1, 0.0)) self.pointsLabel = DirectLabel(parent=self.pointsFrame, relief=None, text='0', text_fg=VBase4(0, 0.5, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15)) self.flipsFrame = DirectFrame(relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGameFlips, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGflipsFrame, text_pos=(-1.94, -0.1, 0.0)) self.flipsLabel = DirectLabel(parent=self.flipsFrame, relief=None, text='0', text_fg=VBase4(0, 1.0, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15)) self.__textGen = TextNode('ringGame') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.sndPerfect = base.loadSfx( 'phase_4/audio/sfx/MG_pairing_all_matched.ogg') self.calcBonusTraversal() self.music = base.loadMusic('phase_4/audio/bgm/MG_Pairing.ogg') self.matchSfx = base.loadSfx('phase_4/audio/sfx/MG_pairing_match.ogg') self.matchWithBonusSfx = base.loadSfx( 'phase_4/audio/sfx/MG_pairing_match_bonus_both.ogg') self.signalSfx = [] for i in range(4): self.signalSfx.append( base.loadSfx( 'phase_4/audio/sfx/MG_pairing_jumping_signal.ogg')) self.bonusMovesSfx = base.loadSfx( 'phase_4/audio/sfx/MG_pairing_bonus_moves.ogg') return def unload(self): self.notify.debug('unload') DistributedMinigame.unload(self) self.removeChildGameFSM(self.gameFSM) del self.gameFSM self.gameBoard.removeNode() del self.gameBoard for card in self.cards: card.unload() del card self.cards = [] self.pointsFrame.removeNode() del self.pointsFrame self.flipsFrame.removeNode() del self.flipsFrame del self.__textGen del self.sndPerfect self.bonusGlow.removeNode() del self.bonusGlow del self.music del self.matchSfx del self.matchWithBonusSfx for i in range(4): del self.signalSfx[0] self.signalSfx = [] del self.bonusMovesSfx def onstage(self): self.notify.debug('onstage') DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) for card in self.cards: card.reparentTo(render) lt = base.localAvatar lt.reparentTo(render) lt.hideName() self.__placeToon(self.localAvId) lt.setAnimState('Happy', 1.0) lt.setSpeed(0, 0) self.moveCameraToTop() def offstage(self): self.notify.debug('offstage') self.gameBoard.hide() for card in self.cards: card.hide() DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug('handleDisabledAvatar') self.notify.debug('avatar ' + str(avId) + ' disabled') DistributedMinigame.handleDisabledAvatar(self, avId) def setGameReady(self): if not self.hasLocalToon: return self.notify.debug('setGameReady') if DistributedMinigame.setGameReady(self): return for index in xrange(self.numPlayers): avId = self.avIdList[index] toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self.__placeToon(avId) toon.setAnimState('Happy', 1.0) toon.startSmooth() toon.startLookAround() def setGameStart(self, timestamp): if not self.hasLocalToon: return self.notify.debug('setGameStart') DistributedMinigame.setGameStart(self, timestamp) for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() self.gameFSM.request('play') def isInPlayState(self): if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == 'play': return False return True def enterOff(self): self.notify.debug('enterOff') def exitOff(self): pass def enterPlay(self): self.notify.debug('enterPlay') base.playMusic(self.music, looping=1, volume=0.9) orthoDrive = OrthoDrive( self.TOON_SPEED, maxFrameMove=self.MAX_FRAME_MOVE, customCollisionCallback=self.__doPairingGameCollisions) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=not self.isSinglePlayer()) self.orthoWalk.start() self.accept('insert', self.__flipKeyPressed) self.accept('delete', self.__flipKeyPressed) self.accept('time-control', self.__beginSignal) self.accept('time-control-up', self.__endSignal) self.bonusGlowIndex = 0 self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex] self.startBonusTask() self.timer = ToontownTimer.ToontownTimer() self.timer.posInTopRightCorner() self.timer.setTime(self.gameDuration) self.timer.countdown(self.gameDuration, self.timerExpired) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() def exitPlay(self): self.music.stop() self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk self.bonusGlow.hide() self.stopBonusTask() self.timer.stop() self.timer.destroy() del self.timer self.ignoreAll() if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() if hasattr(self, 'perfectIval'): self.perfectIval.pause() del self.perfectIval taskMgr.remove(self.EndGameTaskName) taskMgr.remove('pairGameContinueSignal') def enterCleanup(self): self.notify.debug('enterCleanup') def exitCleanup(self): pass def __placeToon(self, avId): toon = self.getAvatar(avId) if self.numPlayers == 1: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) else: posIndex = self.avIdList.index(avId) pos = self.startingPositions[posIndex] toon.setPos(pos[0], pos[1], pos[2]) toon.setHpr(pos[3], 0, 0) def __doPairingGameCollisions(self, oldPos, newPos): x = bound(newPos[0], self.stageMin[0], self.stageMax[0]) y = bound(newPos[1], self.stageMin[1], self.stageMax[1]) newPos.setX(x) newPos.setY(y) if self.inList: newPos.setZ(0.15) else: newPos.setZ(0.0) if not oldPos == newPos: taskMgr.remove('pairGameContinueSignal') return newPos def getDeckOrderFromValue(self, value): for index in xrange(len(self.cards)): if self.cards[index].value == value: return index return -1 def getDeckOrderFromPairingGameCard(self, into): try: index = self.cards.index(into) except ValueError: index = -1 return index def enterCard(self, colEntry): intoName = colEntry.getIntoNodePath().getName() parts = intoName.split('-') value = int(parts[1]) self.notify.debug('entered cardValue %d' % value) deckOrder = self.getDeckOrderFromValue(value) if deckOrder not in self.inList: self.inList.append(deckOrder) def exitCard(self, colEntry): intoName = colEntry.getIntoNodePath().getName() parts = intoName.split('-') value = int(parts[1]) self.notify.debug('exited cardValue %d' % value) deckOrder = self.getDeckOrderFromValue(value) if deckOrder in self.inList: self.inList.remove(deckOrder) def handleMatch(self, cardA, cardB, withBonus): self.notify.debug('we got a match %d %d' % (cardA, cardB)) self.matches += 1 if cardA in self.faceUpList: self.faceUpList.remove(cardA) if cardB in self.faceUpList: self.faceUpList.remove(cardB) self.inactiveList.append(cardA) self.inactiveList.append(cardB) matchIval = Parallel() for card in [cardA, cardB]: self.cards[card].setTransparency(1) cardSeq = Sequence( LerpColorScaleInterval(self.cards[card], duration=1, colorScale=Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.cards[card].hide)) matchIval.append(cardSeq) if withBonus: matchIval.append( SoundInterval(self.matchWithBonusSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240)) else: matchIval.append( SoundInterval(self.matchSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240)) matchIval.start() if len(self.inactiveList) == len(self.cards): self.sendUpdate('reportDone') def turnUpCard(self, deckOrder): self.cards[deckOrder].turnUp() self.faceUpList.append(deckOrder) def turnDownCard(self, deckOrder): self.cards[deckOrder].turnDown() if deckOrder in self.faceUpList: self.faceUpList.remove(deckOrder) def __flipKeyPressed(self): if self.inList: shortestDistance = 10000 cardToFlip = -1 for deckOrder in self.inList: dist = base.localAvatar.getDistance(self.cards[deckOrder]) if dist < shortestDistance: shortestDistance = dist cardToFlip = deckOrder deckOrderIndex = cardToFlip card = self.cards[deckOrderIndex] if card.isFaceDown() and deckOrderIndex not in self.inactiveList: self.sendUpdate('openCardRequest', [deckOrderIndex, self.bonusGlowCard]) elif card.isFaceUp() and deckOrderIndex in self.faceUpList: pass def moveBonusGlowTask(self, task): if len(self.cards) == 0: return Task.done curT = self.getCurrentGameTime() intTime = int(curT / self.bonusGlowTime) newIndex = intTime % len(self.cards) if not newIndex == self.bonusGlowIndex: self.bonusGlowIndex = newIndex self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex] card = self.cards[self.bonusGlowCard] self.bonusGlow.setPos(card.getPos()) base.playSfx(self.bonusMovesSfx, node=card, volume=0.25) return Task.cont def timerExpired(self): self.sendUpdate('reportDone') def setDeckSeed(self, deckSeed): if not self.hasLocalToon: return self.deckSeed = deckSeed def updateFlipText(self): self.flipsLabel['text'] = str(self.flips) lowFlipModifier = PairingGameGlobals.calcLowFlipModifier( self.matches, self.flips) red = 1.0 - lowFlipModifier green = lowFlipModifier self.flipsLabel['text_fg'] = Vec4(red, green, 0, 1.0) def openCardResult(self, cardToTurnUp, avId, matchingCard, points, cardsToTurnDown): if not self.hasLocalToon: return if not self.isInPlayState(): return if avId == base.localAvatar.doId: self.localFaceUpList.append(cardToTurnUp) self.turnUpCard(cardToTurnUp) gotBonus = False if points - self.points > 1: gotBonus = True if matchingCard > -1: self.handleMatch(cardToTurnUp, matchingCard, gotBonus) self.flips += 1 self.updateFlipText() self.points = points self.pointsLabel['text'] = str(self.points) for card in cardsToTurnDown: self.turnDownCard(card) def startBonusTask(self): taskMgr.add(self.moveBonusGlowTask, self.taskName('moveBonusGlowTask')) def stopBonusTask(self): taskMgr.remove(self.taskName('moveBonusGlowTask')) def setEveryoneDone(self): if not self.hasLocalToon: return if self.gameFSM.getCurrentState().getName() != 'play': self.notify.warning('ignoring setEveryoneDone msg') return self.notify.debug('setEveryoneDone') def endGame(task, self=self): if not PairingGameGlobals.EndlessGame: self.gameOver() return Task.done self.timer.hide() self.bonusGlow.hide() if len(self.inactiveList) == len(self.cards): self.notify.debug('perfect game!') perfectTextSubnode = hidden.attachNewNode( self.__genText(TTLocalizer.PairingGamePerfect)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text=perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text=perfectText): text.removeNode() textTrack = Sequence( Func(perfectText.reparentTo, aspect2d), Parallel( LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel( LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5), Func(endGame, None)) soundTrack = SoundInterval(self.sndPerfect) self.perfectIval = Parallel(textTrack, soundTrack) self.perfectIval.start() else: taskMgr.doMethodLater(1, endGame, self.EndGameTaskName) return def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def b_setSignaling(self, avId): self.setSignaling(avId) self.sendUpdate('setSignaling', [self.localAvId]) def setSignaling(self, avId): if not self.hasLocalToon: return avIndex = self.avIdList.index(avId) av = base.cr.doId2do.get(avId) if av and avIndex >= 0 and hasattr(self, 'signalSfx') and self.signalSfx: base.playSfx(self.signalSfx[avIndex], node=av) def __beginSignal(self, mouseParam): self.notify.debug('beginSignal') base.localAvatar.b_setEmoteState(1, 1.0) self.b_setSignaling(self.localAvId) taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal') def __endSignal(self, mouseParam): self.notify.debug('endSignal') base.localAvatar.b_setEmoteState(-1, 1.0) taskMgr.remove('pairGameContinueSignal') def __continueSignal(self, task): base.localAvatar.b_setEmoteState(1, 1.0) self.b_setSignaling(self.localAvId) taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal') def getCardPos(self, deckOrderIndex): col = deckOrderIndex % self.cardsPerRow row = deckOrderIndex / self.cardsPerRow x = col * self.xCardInc y = row * self.yCardInc return (x, y) def getDeckOrderIndex(self, row, col): retval = row * self.cardsPerRow retval += col if retval >= len(self.deck.cards): retval = -1 return retval def calcBonusTraversal(self): self.bonusTraversal = [] halfRow = self.cardsPerRow / 2 if self.cardsPerRow % 2: halfRow += 1 for i in xrange(halfRow): for j in xrange(2): col = i + j * halfRow for row in xrange(self.cardsPerCol): card = self.getDeckOrderIndex(row, col) if card > -1: self.bonusTraversal.append(card)
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode): notify = directNotify.newCategory('DistributedPieTurret') def __init__(self, cr): DistributedAvatar.__init__(self, cr) DistributedSmoothNode.__init__(self, cr) self.fsm = ClassicFSM( 'DistributedPieTurret', [ State('off', self.enterOff, self.exitOff), State('scan', self.enterScan, self.exitScan), State('shoot', self.enterShoot, self.exitShoot) ], 'off', 'off' ) self.fsm.enterInitialState() self.reloadTime = 0.25 self.cannon = None self.track = None self.owner = None self.gag = None self.readyGag = None self.hitGag = None self.explosion = None self.wallCollNode = None self.eventCollNode = None self.event = None self.suit = None self.eventId = None self.entities = [] self.upgradeID = None self.deathEvent = None def setOwner(self, avatar): self.owner = avatar def getOwner(self): return self.owner def setGag(self, upgradeId): gags = {0 : CIGlobals.WholeCreamPie, 1 : CIGlobals.WholeFruitPie, 2 : CIGlobals.BirthdayCake, 3 : CIGlobals.WeddingCake} self.gag = gags.get(upgradeId) if not self.readyGag: self.loadGagInTurret() def b_setGag(self, upgradeId): self.sendUpdate('setGag', [upgradeId]) self.setGag(upgradeId) self.upgradeID = upgradeId def getGag(self): return self.gag def getGagID(self): return self.upgradeID def generate(self): DistributedAvatar.generate(self) DistributedSmoothNode.generate(self) def announceGenerate(self): DistributedAvatar.announceGenerate(self) DistributedSmoothNode.announceGenerate(self) self.healthLabel.setScale(1.1) self.deathEvent = self.uniqueName('DistributedPieTurret-death') self.makeTurret() def disable(self): self.fsm.requestFinalState() del self.fsm # This should fix crashes related to Sequences. if self.track: self.track.pause() self.track = None # Cleanup entities. for ent in self.entities: ent.cleanup() self.entities = None # Get rid of explosions. if self.explosion: self.explosion.removeNode() self.explosion = None self.removeTurret() DistributedSmoothNode.disable(self) DistributedAvatar.disable(self) def showAndMoveHealthLabel(self): self.unstashHpLabel() self.stopMovingHealthLabel() moveTrack = LerpPosInterval(self.healthLabel, duration = 0.5, pos = Point3(0, 0, 5), startPos = Point3(0, 0, 0), blendType = 'easeOut') self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel)) self.healthLabelTrack.start() # BEGIN STATES def enterShoot(self, suitId): if self.cannon: smoke = loader.loadModel("phase_4/models/props/test_clouds.bam") smoke.setBillboardPointEye() smoke.reparentTo(self.cannon.find('**/cannon')) smoke.setPos(0, 6, -3) smoke.setScale(0.5) smoke.wrtReparentTo(render) self.suit = self.cr.doId2do.get(suitId) self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head')) self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head')) self.track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode)) self.track.start() self.createAndShootGag() def exitShoot(self): if hasattr(self, 'suit'): del self.suit def shoot(self, suitId): self.fsm.request('shoot', [suitId]) def scan(self, timestamp = None, afterShooting = 0): if timestamp == None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) self.fsm.request('scan', [ts, afterShooting]) def buildScanTrack(self, ts = None): if self.track: self.track.pause() self.track = None self.track = Parallel( Sequence( LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0), startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0), startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'), ), Sequence( LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0), startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0), startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'), ) ) if ts: self.track.loop(ts) else: self.track.loop() def enterScan(self, ts = 0, afterShooting = 0): if afterShooting: self.track = Parallel( LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0), startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'), LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0), startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'), name = "afterShootTrack" + str(id(self)) ) self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone) self.track.start(ts) else: self.buildScanTrack(ts) def exitScan(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None def enterOff(self): pass def exitOff(self): pass # END STATES def _afterShootTrackDone(self): self.buildScanTrack() def makeTurret(self): self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon.bam') self.cannon.reparentTo(self) self.loadGagInTurret() self.setupWallSphere() if self.isLocal(): self.setupEventSphere() def removeTurret(self): self.removeWallSphere() self.removeGagInTurret() if self.cannon: self.cannon.removeNode() self.cannon = None def getCannon(self): return self.cannon.find('**/cannon') def setupWallSphere(self): sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0) node = CollisionNode('DistributedPieTurret.WallSphere') node.addSolid(sphere) node.setCollideMask(CIGlobals.WallBitmask) self.wallCollNode = self.cannon.attachNewNode(node) self.wallCollNode.setZ(2) self.wallCollNode.setY(1.0) def removeWallSphere(self): if self.wallCollNode: self.wallCollNode.removeNode() self.wallCollNode = None def createAndShootGag(self): if not self.readyGag: self.loadGagInTurret() if self.readyGag: self.readyGag.shoot(Point3(0, 200, -90)) self.entities.append(self.readyGag) collideEventName = self.readyGag.getCollideEventName() self.readyGag = None if self.isLocal(): self.acceptOnce(collideEventName, self.handleGagCollision) Sequence(Wait(self.reloadTime), Func(self.loadGagInTurret)).start() def loadGagInTurret(self): if self.cannon and self.gag: self.removeGagInTurret() self.eventId = random.uniform(0, 100000000) self.readyGag = TurretGag(self, self.uniqueName('pieTurretCollision') + str(self.eventId), self.gag) self.readyGag.build() def removeGagInTurret(self): if self.readyGag: self.readyGag.cleanup() self.readyGag = None def makeSplat(self, index, pos): if index >= len(self.entities): return ent = self.entities[index] gagClass = ent.gagClass splat = gagClass.buildSplat(gagClass.splatScale, gagClass.splatColor) base.audio3d.attachSoundToObject(gagClass.hitSfx, splat) splat.reparentTo(render) splat.setPos(pos[0], pos[1], pos[2]) gagClass.hitSfx.play() Sequence(Wait(0.5), Func(splat.cleanup)).start() self.hitGag = None def d_makeSplat(self, index, pos): self.sendUpdate('makeSplat', [index, pos]) def b_makeSplat(self, index, pos): self.d_makeSplat(index, pos) self.makeSplat(index, pos) def handleGagCollision(self, entry, ent): x, y, z = ent.getGag().getPos(render) self.b_makeSplat(self.entities.index(ent), [x, y, z]) if self.isLocal(): intoNP = entry.getIntoNodePath() avNP = intoNP.getParent() for key in self.cr.doId2do.keys(): obj = self.cr.doId2do[key] if obj.__class__.__name__ == 'DistributedSuit': if obj.getKey() == avNP.getKey(): if obj.getHealth() > 0: obj.sendUpdate('hitByGag', [ent.getID()]) ent.cleanup() def setHealth(self, hp): DistributedAvatar.setHealth(self, hp) if self.isLocal(): base.localAvatar.getMyBattle().getTurretManager().updateTurretGui() def die(self): self.fsm.requestFinalState() turretPos = self.cannon.getPos(render) self.removeTurret() self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam") self.explosion.setScale(0.5) self.explosion.reparentTo(render) self.explosion.setBillboardPointEye() self.explosion.setPos(turretPos + (0, 0, 5)) sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg") base.audio3d.attachSoundToObject(sfx, self) base.playSfx(sfx) messenger.send(self.deathEvent) def isLocal(self): return self.getOwner() == base.localAvatar.doId def getDeathEvent(self): return self.deathEvent
class TestCutscene: def __init__(self, dcs): self.dcs = dcs self.ival = None def run(self): boss = base.bspLoader.getPyEntityByTargetName("groom_boss_suit") boss.show() boss.cleanupPropeller() boss.animFSM.request('neutral') camera.reparentTo(boss) onBtn = base.bspLoader.getPyEntityByTargetName("powerovrd_on_button") # press animation (fingerwag): 1-31 32-1 buttonPos = (-1105 / 16.0, 2683 / 16.0, 76 / 16.0) camBtnPosHpr = (-1027 / 16.0, 2638 / 16.0, 96 / 16.0, 135 - 90, 30, 0) camBtnPosHpr2 = (-1009 / 16.0, 2764 / 16.0, 169 / 16.0, 232 - 90, 0, 0) def __pingpongboss_speak(): boss.pingpong("speak", fromFrame=95, toFrame=100) def __boss_pressseq(): return Sequence( ActorInterval(boss, "fingerwag", startFrame=1, endFrame=31), Func(onBtn.d_requestPress), ActorInterval(boss, "fingerwag", startFrame=32, endFrame=1)) def __localavplay_duck(): base.localAvatar.setAnimState('off') base.localAvatar.play("duck", fromFrame=19) numGoons = 6 goonWakeup = Parallel() for i in xrange(numGoons): delay = random.uniform(0.0, 0.5) goon = base.bspLoader.getPyEntityByTargetName( "groom_goon_{0}".format(i)) goonWakeup.append(Sequence(Wait(delay), Func(goon.wakeup))) bdoor = base.bspLoader.getPyEntityByTargetName("to_groom_botdoor") tdoor = base.bspLoader.getPyEntityByTargetName("to_groom_topdoor") oldHpr = boss.getHpr(render) bossTrack = Parallel( Sequence( Wait(10.0), Func(boss.setHpr, oldHpr), ActorInterval(boss, "speak", startFrame=55, endFrame=105, playRate=1.5), #Func(__pingpongboss_speak), Wait(2.0), Func(boss.loop, "neutral")), Sequence( Func(boss.play, "speak"), Func(boss.setChat, "What's this?! How did a Toon get down here?"), Wait(2.5), Func( boss.setChat, "The only place you'll be going is back to the playground." ), Func(boss.loop, "walk"), Func(boss.headsUp, *buttonPos), LerpPosInterval(boss, 2.5, buttonPos), __boss_pressseq(), Wait(2.5), Func(boss.setChat, "Goons, ATTACK!!!"))) camTrack = Sequence( Func(camera.setPos, 2.5, 14, 7), Func(camera.lookAt, boss, 0, 0, 4), Wait(2.5), Func(camera.reparentTo, render), Func(camera.setPosHpr, *camBtnPosHpr), Wait(2.0), Func(camera.setPosHpr, *camBtnPosHpr2), Wait(0.5), Wait(3.0), Func(camera.setPosHpr, 4.351, 126.686, 5.5, -154.16, 16.11, 0), Wait(0.3), Func(bdoor.request, 'Closing'), Func(tdoor.request, 'Closing'), Func(__localavplay_duck), Wait(0.9), Func(base.doCamShake, 0.5, 0.35), Wait(0.9), Func(camera.reparentTo, boss), Func(camera.setPos, 2.5, 17, 7), Func(camera.lookAt, boss, 0, 0, 4), LerpPosHprInterval(camera, duration=0.75, blendType='easeOut', pos=(1, 5, 4), hpr=(165, 20, 0)), Wait(1.75), Func(camera.reparentTo, render), Func(camera.setPosHpr, 88 / 16.0, 2746 / 16.0, 127 / 16.0, 71 - 90, -10, 0)) goonTrack = Sequence(Wait(12.6), goonWakeup) self.ival = Parallel(camTrack, bossTrack, goonTrack) self.ival.start() def stop(self): if self.ival: self.ival.pause() self.ival = None def cleanup(self): self.dcs = None
class DistributedPartyCatchActivity(DistributedPartyActivity, DistributedPartyCatchActivityBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCatchActivity') DropTaskName = 'dropSomething' DropObjectPlurals = {'apple': TTLocalizer.PartyCatchActivityApples, 'orange': TTLocalizer.PartyCatchActivityOranges, 'pear': TTLocalizer.PartyCatchActivityPears, 'coconut': TTLocalizer.PartyCatchActivityCoconuts, 'watermelon': TTLocalizer.PartyCatchActivityWatermelons, 'pineapple': TTLocalizer.PartyCatchActivityPineapples, 'anvil': TTLocalizer.PartyCatchActivityAnvils} class Generation: def __init__(self, generation, startTime, startNetworkTime, numPlayers): self.generation = generation self.startTime = startTime self.startNetworkTime = startNetworkTime self.numPlayers = numPlayers self.hasBeenScheduled = False self.droppedObjNames = [] self.dropSchedule = [] self.numItemsDropped = 0 self.droppedObjCaught = {} def __init__(self, cr): DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyCatch, PartyGlobals.ActivityTypes.HostInitiated, wantRewardGui=True) self.setUsesSmoothing() self.setUsesLookAround() self._sNumGen = SerialNumGen() def getTitle(self): return TTLocalizer.PartyCatchActivityTitle def getInstructions(self): return TTLocalizer.PartyCatchActivityInstructions % {'badThing': self.DropObjectPlurals['anvil']} def generate(self): DistributedPartyActivity.generate(self) self.notify.info('localAvatar doId: %s' % base.localAvatar.doId) self.notify.info('generate()') self._generateFrame = globalClock.getFrameCount() self._id2gen = {} self._orderedGenerations = [] self._orderedGenerationIndex = None rng = RandomNumGen(self.doId) self._generationSeedBase = rng.randrange(1000) self._lastDropTime = 0.0 return def getCurGeneration(self): if self._orderedGenerationIndex is None: return return self._orderedGenerations[self._orderedGenerationIndex] def _addGeneration(self, generation, startTime, startNetworkTime, numPlayers): self._id2gen[generation] = self.Generation(generation, startTime, startNetworkTime, numPlayers) i = 0 while 1: if i >= len(self._orderedGenerations): break gen = self._orderedGenerations[i] startNetT = self._id2gen[gen].startTime genId = self._id2gen[gen].generation if startNetT > startNetworkTime: break if startNetT == startNetworkTime and genId > generation: break i += 1 self._orderedGenerations = self._orderedGenerations[:i] + [generation] + self._orderedGenerations[i:] if self._orderedGenerationIndex is not None: if self._orderedGenerationIndex >= i: self._orderedGenerationIndex += 1 def _removeGeneration(self, generation): del self._id2gen[generation] i = self._orderedGenerations.index(generation) self._orderedGenerations = self._orderedGenerations[:i] + self._orderedGenerations[i + 1:] if self._orderedGenerationIndex is not None: if len(self._orderedGenerations): if self._orderedGenerationIndex >= i: self._orderedGenerationIndex -= 1 else: self._orderedGenerationIndex = None return def announceGenerate(self): self.notify.info('announceGenerate()') self.catchTreeZoneEvent = 'fence_floor' DistributedPartyActivity.announceGenerate(self) def load(self, loadModels = 1, arenaModel = 'partyCatchTree'): self.notify.info('load()') DistributedPartyCatchActivity.notify.debug('PartyCatch: load') self.activityFSM = CatchActivityFSM(self) if __dev__: for o in xrange(3): print {0: 'SPOTS PER PLAYER', 1: 'DROPS PER MINUTE PER SPOT DURING NORMAL DROP PERIOD', 2: 'DROPS PER MINUTE PER PLAYER DURING NORMAL DROP PERIOD'}[o] for i in xrange(1, self.FallRateCap_Players + 10): self.defineConstants(forceNumPlayers=i) numDropLocations = self.DropRows * self.DropColumns numDropsPerMin = 60.0 / self.DropPeriod if o == 0: spotsPerPlayer = numDropLocations / float(i) print '%2d PLAYERS: %s' % (i, spotsPerPlayer) elif o == 1: numDropsPerMinPerSpot = numDropsPerMin / numDropLocations print '%2d PLAYERS: %s' % (i, numDropsPerMinPerSpot) elif i > 0: numDropsPerMinPerPlayer = numDropsPerMin / i print '%2d PLAYERS: %s' % (i, numDropsPerMinPerPlayer) self.defineConstants() self.treesAndFence = loader.loadModel('phase_13/models/parties/%s' % arenaModel) self.treesAndFence.setScale(0.9) self.treesAndFence.find('**/fence_floor').setPos(0.0, 0.0, 0.1) self.treesAndFence.reparentTo(self.root) ground = self.treesAndFence.find('**/groundPlane') ground.setBin('ground', 1) DistributedPartyActivity.load(self) exitText = TextNode('PartyCatchExitText') exitText.setCardAsMargin(0.1, 0.1, 0.1, 0.1) exitText.setCardDecal(True) exitText.setCardColor(1.0, 1.0, 1.0, 0.0) exitText.setText(TTLocalizer.PartyCatchActivityExit) exitText.setTextColor(0.0, 8.0, 0.0, 0.9) exitText.setAlign(exitText.ACenter) exitText.setFont(ToontownGlobals.getBuildingNametagFont()) exitText.setShadowColor(0, 0, 0, 1) exitText.setBin('fixed') if TTLocalizer.BuildingNametagShadow: exitText.setShadow(*TTLocalizer.BuildingNametagShadow) exitTextLoc = self.treesAndFence.find('**/loc_exitSignText') exitTextNp = exitTextLoc.attachNewNode(exitText) exitTextNp.setDepthWrite(0) exitTextNp.setScale(4) exitTextNp.setZ(-.5) self.sign.reparentTo(self.treesAndFence.find('**/loc_eventSign')) self.sign.wrtReparentTo(self.root) self.avatarNodePath = NodePath('PartyCatchAvatarNodePath') self.avatarNodePath.reparentTo(self.root) self._avatarNodePathParentToken = 3 base.cr.parentMgr.registerParent(self._avatarNodePathParentToken, self.avatarNodePath) self.toonSDs = {} self.dropShadow = loader.loadModelOnce('phase_3/models/props/drop_shadow') self.dropObjModels = {} if loadModels: self.__loadDropModels() self.sndGoodCatch = base.loadSfx('phase_4/audio/sfx/SZ_DD_treasure.ogg') self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndAnvilLand = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg') self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg') self.__textGen = TextNode('partyCatchActivity') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.activityFSM.request('Idle') def __loadDropModels(self): for objType in PartyGlobals.DropObjectTypes: model = loader.loadModel(objType.modelPath) self.dropObjModels[objType.name] = model modelScales = {'apple': 0.7, 'orange': 0.7, 'pear': 0.5, 'coconut': 0.7, 'watermelon': 0.6, 'pineapple': 0.45} if objType.name in modelScales: model.setScale(modelScales[objType.name]) if objType == PartyGlobals.Name2DropObjectType['pear']: model.setZ(-.6) if objType == PartyGlobals.Name2DropObjectType['coconut']: model.setP(180) if objType == PartyGlobals.Name2DropObjectType['watermelon']: model.setH(135) model.setZ(-.5) if objType == PartyGlobals.Name2DropObjectType['pineapple']: model.setZ(-1.7) if objType == PartyGlobals.Name2DropObjectType['anvil']: model.setZ(-self.ObjRadius) model.flattenStrong() def unload(self): DistributedPartyCatchActivity.notify.debug('unload') self.finishAllDropIntervals() self.destroyOrthoWalk() DistributedPartyActivity.unload(self) self.stopDropTask() del self.activityFSM del self.__textGen for avId in self.toonSDs.keys(): if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.unload() del self.toonSDs self.treesAndFence.removeNode() del self.treesAndFence self.dropShadow.removeNode() del self.dropShadow base.cr.parentMgr.unregisterParent(self._avatarNodePathParentToken) for model in self.dropObjModels.values(): model.removeNode() del self.dropObjModels del self.sndGoodCatch del self.sndOof del self.sndAnvilLand del self.sndPerfect def setStartTimestamp(self, timestamp32): self.notify.info('setStartTimestamp(%s)' % (timestamp32,)) self._startTimestamp = globalClockDelta.networkToLocalTime(timestamp32, bits=32) def getCurrentCatchActivityTime(self): return globalClock.getFrameTime() - self._startTimestamp def getObjModel(self, objName): return self.dropObjModels[objName].copyTo(hidden) def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) base.cr.playGame.getPlace().fsm.request('walk') def handleToonJoined(self, toonId): if toonId not in self.toonSDs: toonSD = PartyCatchActivityToonSD(toonId, self) self.toonSDs[toonId] = toonSD toonSD.load() self.notify.debug('handleToonJoined : currentState = %s' % self.activityFSM.state) self.cr.doId2do[toonId].useLOD(500) if self.activityFSM.state == 'Active': if toonId in self.toonSDs: self.toonSDs[toonId].enter() if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(self._avatarNodePathParentToken) self.putLocalAvatarInActivity() if toonId in self.toonSDs: self.toonSDs[toonId].fsm.request('rules') def handleToonExited(self, toonId): self.notify.debug('handleToonExited( toonId=%s )' % toonId) if toonId in self.cr.doId2do: self.cr.doId2do[toonId].resetLOD() if toonId in self.toonSDs: self.toonSDs[toonId].fsm.request('notPlaying') self.toonSDs[toonId].exit() self.toonSDs[toonId].unload() del self.toonSDs[toonId] if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(ToontownGlobals.SPRender) def takeLocalAvatarOutOfActivity(self): self.notify.debug('localToon has left the circle') base.camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) DistributedSmoothNode.activateSmoothing(1, 0) def _enableCollisions(self): DistributedPartyActivity._enableCollisions(self) self._enteredTree = False self.accept('enter' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('again' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('exit' + self.catchTreeZoneEvent, self._toonExitedTree) self.accept(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT, self._handleCannonLanded) def _disableCollisions(self): self.ignore(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT) self.ignore('enter' + self.catchTreeZoneEvent) self.ignore('again' + self.catchTreeZoneEvent) self.ignore('exit' + self.catchTreeZoneEvent) DistributedPartyActivity._disableCollisions(self) def _handleCannonLanded(self): x = base.localAvatar.getX() y = base.localAvatar.getY() if x > self.x - self.StageHalfWidth and x < self.x + self.StageHalfWidth and y > self.y - self.StageHalfHeight and y < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def _toonMayHaveEnteredTree(self, collEntry): if self._enteredTree: return if base.localAvatar.controlManager.currentControls.getIsAirborne(): return self._toonEnteredTree(collEntry) def _toonEnteredTree(self, collEntry): self.notify.debug('_toonEnteredTree : avid = %s' % base.localAvatar.doId) self.notify.debug('_toonEnteredTree : currentState = %s' % self.activityFSM.state) if self.isLocalToonInActivity(): return if self.activityFSM.state == 'Active': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() elif self.activityFSM.state == 'Idle': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() self._enteredTree = True def _toonExitedTree(self, collEntry): self.notify.debug('_toonExitedTree : avid = %s' % base.localAvatar.doId) self._enteredTree = False if hasattr(base.cr.playGame.getPlace(), 'fsm') and self.activityFSM.state == 'Active' and self.isLocalToonInActivity(): if base.localAvatar.doId in self.toonSDs: self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') self.d_toonExitDemand() def setToonsPlaying(self, toonIds): self.notify.info('setToonsPlaying(%s)' % (toonIds,)) DistributedPartyActivity.setToonsPlaying(self, toonIds) if self.isLocalToonInActivity() and base.localAvatar.doId not in toonIds: if base.localAvatar.doId in self.toonSDs: self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def getNumPlayers(self): return len(self.toonIds) def defineConstants(self, forceNumPlayers = None): DistributedPartyCatchActivity.notify.debug('defineConstants') self.ShowObjSpheres = 0 self.ShowToonSpheres = 0 self.useGravity = True self.trickShadows = True if forceNumPlayers is None: numPlayers = self.getNumPlayers() else: numPlayers = forceNumPlayers self.calcDifficultyConstants(numPlayers) DistributedPartyCatchActivity.notify.debug('ToonSpeed: %s' % self.ToonSpeed) DistributedPartyCatchActivity.notify.debug('total drops: %s' % self.totalDrops) DistributedPartyCatchActivity.notify.debug('numFruits: %s' % self.numFruits) DistributedPartyCatchActivity.notify.debug('numAnvils: %s' % self.numAnvils) self.ObjRadius = 1.0 dropRegionTable = PartyRegionDropPlacer.getDropRegionTable(numPlayers) self.DropRows, self.DropColumns = len(dropRegionTable), len(dropRegionTable[0]) for objType in PartyGlobals.DropObjectTypes: DistributedPartyCatchActivity.notify.debug('*** Object Type: %s' % objType.name) objType.onscreenDuration = objType.onscreenDurMult * self.BaselineOnscreenDropDuration DistributedPartyCatchActivity.notify.debug('onscreenDuration=%s' % objType.onscreenDuration) v_0 = 0.0 t = objType.onscreenDuration x_0 = self.MinOffscreenHeight x = 0.0 g = 2.0 * (x - x_0 - v_0 * t) / (t * t) DistributedPartyCatchActivity.notify.debug('gravity=%s' % g) objType.trajectory = Trajectory(0, Vec3(0, 0, x_0), Vec3(0, 0, v_0), gravMult=abs(g / Trajectory.gravity)) objType.fallDuration = objType.onscreenDuration + self.OffscreenTime return def grid2world(self, column, row): x = column / float(self.DropColumns - 1) y = row / float(self.DropRows - 1) x = x * 2.0 - 1.0 y = y * 2.0 - 1.0 x *= self.StageHalfWidth y *= self.StageHalfHeight return (x, y) def showPosts(self): self.hidePosts() self.posts = [Toon.Toon(), Toon.Toon(), Toon.Toon(), Toon.Toon()] for i in xrange(len(self.posts)): tree = self.posts[i] tree.reparentTo(render) x = self.StageHalfWidth y = self.StageHalfHeight if i > 1: x = -x if i % 2: y = -y tree.setPos(x + self.x, y + self.y, 0) def hidePosts(self): if hasattr(self, 'posts'): for tree in self.posts: tree.removeNode() del self.posts def showDropGrid(self): self.hideDropGrid() self.dropMarkers = [] for row in xrange(self.DropRows): self.dropMarkers.append([]) rowList = self.dropMarkers[row] for column in xrange(self.DropColumns): toon = Toon.Toon() toon.setDNA(base.localAvatar.getStyle()) toon.reparentTo(self.root) toon.setScale(1.0 / 3) x, y = self.grid2world(column, row) toon.setPos(x, y, 0) rowList.append(toon) def hideDropGrid(self): if hasattr(self, 'dropMarkers'): for row in self.dropMarkers: for marker in row: marker.removeNode() del self.dropMarkers def handleToonDisabled(self, avId): DistributedPartyCatchActivity.notify.debug('handleToonDisabled') DistributedPartyCatchActivity.notify.debug('avatar ' + str(avId) + ' disabled') if avId in self.toonSDs: self.toonSDs[avId].exit(unexpectedExit=True) del self.toonSDs[avId] def turnOffSmoothingOnGuests(self): pass def setState(self, newState, timestamp): self.notify.info('setState(%s, %s)' % (newState, timestamp)) DistributedPartyCatchActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) if newState == 'Active': if base.localAvatar.doId != self.party.partyInfo.hostId: if globalClock.getFrameCount() > self._generateFrame: if base.localAvatar.getX() > self.x - self.StageHalfWidth and base.localAvatar.getX() < self.x + self.StageHalfWidth and base.localAvatar.getY() > self.y - self.StageHalfHeight and base.localAvatar.getY() < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def putLocalAvatarInActivity(self): if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'): base.cr.playGame.getPlace().fsm.request('activity', [False]) else: self.notify.info("Avoided crash: toontown.parties.DistributedPartyCatchActivity:632, toontown.parties.DistributedPartyCatchActivity:1198, toontown.parties.activityFSMMixins:49, direct.fsm.FSM:423, AttributeError: 'NoneType' object has no attribute 'fsm'") base.localAvatar.stopUpdateSmartCamera() base.camera.reparentTo(self.treesAndFence) base.camera.setPosHpr(0.0, -63.0, 30.0, 0.0, -20.0, 0.0) if not hasattr(self, 'ltLegsCollNode'): self.createCatchCollisions() def createCatchCollisions(self): radius = 0.7 handler = CollisionHandlerEvent() handler.setInPattern('ltCatch%in') self.ltLegsCollNode = CollisionNode('catchLegsCollNode') self.ltLegsCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltHeadCollNode = CollisionNode('catchHeadCollNode') self.ltHeadCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltLHandCollNode = CollisionNode('catchLHandCollNode') self.ltLHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltRHandCollNode = CollisionNode('catchRHandCollNode') self.ltRHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) legsCollNodepath = base.localAvatar.attachNewNode(self.ltLegsCollNode) legsCollNodepath.hide() head = base.localAvatar.getHeadParts().getPath(2) headCollNodepath = head.attachNewNode(self.ltHeadCollNode) headCollNodepath.hide() lHand = base.localAvatar.getLeftHands()[0] lHandCollNodepath = lHand.attachNewNode(self.ltLHandCollNode) lHandCollNodepath.hide() rHand = base.localAvatar.getRightHands()[0] rHandCollNodepath = rHand.attachNewNode(self.ltRHandCollNode) rHandCollNodepath.hide() base.localAvatar.cTrav.addCollider(legsCollNodepath, handler) base.localAvatar.cTrav.addCollider(headCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) if self.ShowToonSpheres: legsCollNodepath.show() headCollNodepath.show() lHandCollNodepath.show() rHandCollNodepath.show() self.ltLegsCollNode.addSolid(CollisionSphere(0, 0, radius, radius)) self.ltHeadCollNode.addSolid(CollisionSphere(0, 0, 0, radius)) self.ltLHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.ltRHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.toonCollNodes = [legsCollNodepath, headCollNodepath, lHandCollNodepath, rHandCollNodepath] def destroyCatchCollisions(self): if not hasattr(self, 'ltLegsCollNode'): return for collNode in self.toonCollNodes: while collNode.node().getNumSolids(): collNode.node().removeSolid(0) base.localAvatar.cTrav.removeCollider(collNode) del self.toonCollNodes del self.ltLegsCollNode del self.ltHeadCollNode del self.ltLHandCollNode del self.ltRHandCollNode def timerExpired(self): pass def __handleCatch(self, generation, objNum): DistributedPartyCatchActivity.notify.debug('catch: %s' % [generation, objNum]) if base.localAvatar.doId not in self.toonIds: return self.showCatch(base.localAvatar.doId, generation, objNum) objName = self._id2gen[generation].droppedObjNames[objNum] objTypeId = PartyGlobals.Name2DOTypeId[objName] self.sendUpdate('claimCatch', [generation, objNum, objTypeId]) self.finishDropInterval(generation, objNum) def showCatch(self, avId, generation, objNum): if avId not in self.toonSDs: return isLocal = avId == base.localAvatar.doId if generation not in self._id2gen: return if not self._id2gen[generation].hasBeenScheduled: return objName = self._id2gen[generation].droppedObjNames[objNum] objType = PartyGlobals.Name2DropObjectType[objName] if objType.good: if objNum not in self._id2gen[generation].droppedObjCaught: if isLocal: base.playSfx(self.sndGoodCatch) fruit = self.getObjModel(objName) toon = self.getAvatar(avId) rHand = toon.getRightHands()[1] self.toonSDs[avId].eatFruit(fruit, rHand) else: self.toonSDs[avId].fsm.request('fallForward') self._id2gen[generation].droppedObjCaught[objNum] = 1 def setObjectCaught(self, avId, generation, objNum): self.notify.info('setObjectCaught(%s, %s, %s)' % (avId, generation, objNum)) if self.activityFSM.state != 'Active': DistributedPartyCatchActivity.notify.warning('ignoring msg: object %s caught by %s' % (objNum, avId)) return isLocal = avId == base.localAvatar.doId if not isLocal: DistributedPartyCatchActivity.notify.debug('AI: avatar %s caught %s' % (avId, objNum)) self.finishDropInterval(generation, objNum) self.showCatch(avId, generation, objNum) self._scheduleGenerations() gen = self._id2gen[generation] if gen.hasBeenScheduled: objName = gen.droppedObjNames[objNum] if PartyGlobals.Name2DropObjectType[objName].good: if hasattr(self, 'fruitsCaught'): self.fruitsCaught += 1 def finishDropInterval(self, generation, objNum): if hasattr(self, 'dropIntervals'): if (generation, objNum) in self.dropIntervals: self.dropIntervals[generation, objNum].finish() def finishAllDropIntervals(self): if hasattr(self, 'dropIntervals'): for dropInterval in self.dropIntervals.values(): dropInterval.finish() def setGenerations(self, generations): self.notify.info('setGenerations(%s)' % (generations,)) gen2t = {} gen2nt = {} gen2np = {} for id, timestamp32, numPlayers in generations: gen2t[id] = globalClockDelta.networkToLocalTime(timestamp32, bits=32) - self._startTimestamp gen2nt[id] = timestamp32 gen2np[id] = numPlayers ids = self._id2gen.keys() for id in ids: if id not in gen2t: self._removeGeneration(id) for id in gen2t: if id not in self._id2gen: self._addGeneration(id, gen2t[id], gen2nt[id], gen2np[id]) def scheduleDrops(self, genId = None): if genId is None: genId = self.getCurGeneration() gen = self._id2gen[genId] if gen.hasBeenScheduled: return fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration) fruitNames = ['apple', 'orange', 'pear', 'coconut', 'watermelon', 'pineapple'] fruitName = fruitNames[fruitIndex % len(fruitNames)] rng = RandomNumGen(genId + self._generationSeedBase) gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils rng.shuffle(gen.droppedObjNames) dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime) gen.numItemsDropped = 0 tIndex = gen.startTime % PartyGlobals.CatchActivityDuration tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration gen.numItemsDropped += dropPlacer.skipPercent(tPercent) while not dropPlacer.doneDropping(continuous=True): nextDrop = dropPlacer.getNextDrop() gen.dropSchedule.append(nextDrop) gen.hasBeenScheduled = True return def startDropTask(self): taskMgr.add(self.dropTask, self.DropTaskName) def stopDropTask(self): taskMgr.remove(self.DropTaskName) def _scheduleGenerations(self): curT = self.getCurrentCatchActivityTime() genIndex = self._orderedGenerationIndex newGenIndex = genIndex while genIndex is None or genIndex < len(self._orderedGenerations) - 1: if genIndex is None: nextGenIndex = 0 else: nextGenIndex = genIndex + 1 nextGenId = self._orderedGenerations[nextGenIndex] nextGen = self._id2gen[nextGenId] startT = nextGen.startTime if curT >= startT: newGenIndex = nextGenIndex if not nextGen.hasBeenScheduled: self.defineConstants(forceNumPlayers=nextGen.numPlayers) self.scheduleDrops(genId=self._orderedGenerations[nextGenIndex]) genIndex = nextGenIndex self._orderedGenerationIndex = newGenIndex return def dropTask(self, task): self._scheduleGenerations() curT = self.getCurrentCatchActivityTime() if self._orderedGenerationIndex is not None: i = self._orderedGenerationIndex genIndex = self._orderedGenerations[i] gen = self._id2gen[genIndex] while len(gen.dropSchedule) > 0 and gen.dropSchedule[0][0] < curT: drop = gen.dropSchedule[0] gen.dropSchedule = gen.dropSchedule[1:] dropTime, objName, dropCoords = drop objNum = gen.numItemsDropped x, y = self.grid2world(*dropCoords) dropIval = self.getDropIval(x, y, objName, genIndex, objNum) def cleanup(generation, objNum, self = self): del self.dropIntervals[generation, objNum] dropIval.append(Func(Functor(cleanup, genIndex, objNum))) self.dropIntervals[genIndex, objNum] = dropIval gen.numItemsDropped += 1 dropIval.start(curT - dropTime) self._lastDropTime = dropTime return Task.cont def getDropIval(self, x, y, dropObjName, generation, num): objType = PartyGlobals.Name2DropObjectType[dropObjName] id = (generation, num) dropNode = hidden.attachNewNode('catchDropNode%s' % (id,)) dropNode.setPos(x, y, 0) shadow = self.dropShadow.copyTo(dropNode) shadow.setZ(PartyGlobals.CatchDropShadowHeight) shadow.setColor(1, 1, 1, 1) object = self.getObjModel(dropObjName) object.reparentTo(hidden) if dropObjName in ['watermelon', 'anvil']: objH = object.getH() absDelta = {'watermelon': 12, 'anvil': 15}[dropObjName] delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta newH = objH + delta else: newH = self.randomNumGen.random() * 360.0 object.setH(newH) sphereName = 'FallObj%s' % (id,) radius = self.ObjRadius if objType.good: radius *= lerp(1.0, 1.3, 0.5) collSphere = CollisionSphere(0, 0, 0, radius) collSphere.setTangible(0) collNode = CollisionNode(sphereName) collNode.setCollideMask(PartyGlobals.CatchActivityBitmask) collNode.addSolid(collSphere) collNodePath = object.attachNewNode(collNode) collNodePath.hide() if self.ShowObjSpheres: collNodePath.show() catchEventName = 'ltCatch' + sphereName def eatCollEntry(forward, collEntry): forward() self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1]))) def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName): self.ignore(event) dropNode.removeNode() duration = objType.fallDuration onscreenDuration = objType.onscreenDuration targetShadowScale = 0.3 if self.trickShadows: intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration) shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0)) shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale)) else: shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0) targetShadowAlpha = 0.4 shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) if self.useGravity: def setObjPos(t, objType = objType, object = object): z = objType.trajectory.calcZ(t) object.setZ(z) setObjPos(0) dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration) else: startPos = Point3(0, 0, self.MinOffscreenHeight) object.setPos(startPos) dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,)) if objType == PartyGlobals.Name2DropObjectType['anvil']: ival.append(Func(self.playAnvil)) return ival def playAnvil(self): if base.localAvatar.doId in self.toonIds: base.playSfx(self.sndAnvilLand) def initOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('startOrthoWalk') def doCollisions(oldPos, newPos, self = self): x = bound(newPos[0], self.StageHalfWidth, -self.StageHalfWidth) y = bound(newPos[1], self.StageHalfHeight, -self.StageHalfHeight) newPos.setX(x) newPos.setY(y) return newPos orthoDrive = OrthoDrive(self.ToonSpeed, instantTurn=True) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True) def destroyOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('destroyOrthoWalk') if hasattr(self, 'orthoWalk'): self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk def startIdle(self): DistributedPartyCatchActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyCatchActivity.notify.debug('finishIdle') def startActive(self): DistributedPartyCatchActivity.notify.debug('startActive') for avId in self.toonIds: if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.enter() toonSD.fsm.request('normal') self.fruitsCaught = 0 self.dropIntervals = {} self.startDropTask() if base.localAvatar.doId in self.toonIds: self.putLocalAvatarInActivity() def finishActive(self): DistributedPartyCatchActivity.notify.debug('finishActive') self.stopDropTask() if hasattr(self, 'finishIval'): self.finishIval.pause() del self.finishIval if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() for ival in self.dropIntervals.values(): ival.finish() del self.dropIntervals def startConclusion(self): DistributedPartyCatchActivity.notify.debug('startConclusion') for avId in self.toonIds: if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.fsm.request('notPlaying') self.destroyCatchCollisions() if base.localAvatar.doId not in self.toonIds: return else: self.localToonExiting() if self.fruitsCaught >= self.numFruits: finishText = TTLocalizer.PartyCatchActivityFinishPerfect else: finishText = TTLocalizer.PartyCatchActivityFinish perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text = perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text = perfectText): text.removeNode() textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5)) soundTrack = SoundInterval(self.sndPerfect) self.finishIval = Parallel(textTrack, soundTrack) self.finishIval.start() def finishConclusion(self): DistributedPartyCatchActivity.notify.debug('finishConclusion') if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() base.cr.playGame.getPlace().fsm.request('walk') def showJellybeanReward(self, earnedAmount, jarAmount, message): if earnedAmount > 0: DistributedPartyActivity.showJellybeanReward(self, earnedAmount, jarAmount, message) else: base.cr.playGame.getPlace().fsm.request('walk')
class DistributedNPCToon(DistributedToon): notify = directNotify.newCategory('DistributedNPCToon') def __init__(self, cr): DistributedToon.__init__(self, cr) self.collisionNodePath = None self.cameraTrack = None self.originIndex = None self.npcId = None self.currentChatIndex = 0 self.chatArray = None return def setLoadout(self, foo): pass def lookAtAvatar(self, avId): av = self.cr.doId2do.get(avId) if av: self.headsUp(av) def setNpcId(self, id): self.npcId = id def getNpcId(self): return self.npcId def setOriginIndex(self, index): self.originIndex = index def getOriginIndex(self): return self.originIndex def __setupCollisions(self): sphere = CollisionSphere(0, 0, 0, 4) sphere.setTangible(0) collisionNode = CollisionNode(self.uniqueName('NPCToonSphere')) collisionNode.addSolid(sphere) collisionNode.setCollideMask(CIGlobals.WallBitmask) self.collisionNodePath = self.attachNewNode(collisionNode) self.collisionNodePath.setY(1.5) def __removeCollisions(self): if self.collisionNodePath: self.collisionNodePath.removeNode() self.collisionNodePath = None return def handleEnterCollision(self, entry): self.cr.playGame.getPlace().fsm.request('stop') base.localAvatar.stopSmartCamera() self.sendUpdate('requestEnter', []) def doCameraNPCInteraction(self): currCamPos = camera.getPos() currCamHpr = camera.getHpr() camera.setX(camera.getX() + 5) camera.setY(camera.getY() + 5) camera.headsUp(self) newCamPos = camera.getPos() newCamHpr = camera.getHpr() camera.setPos(currCamPos) camera.setHpr(currCamHpr) self.cameraTrack = Parallel( LerpPosInterval(camera, duration=1.0, pos=newCamPos, startPos=currCamPos, blendType='easeOut'), LerpQuatInterval(camera, duration=1.0, quat=newCamHpr, startHpr=currCamHpr, blendType='easeOut')) self.cameraTrack.start() def stopCameraTrack(self): if self.cameraTrack: self.cameraTrack.finish() self.cameraTrack = None return def oneChatThenExit(self): self.acceptOnce('mouse1-up', self.d_requestExit) def enterAccepted(self): self.doCameraNPCInteraction() questData = base.localAvatar.questManager.getQuestAndIdWhereCurrentObjectiveIsToVisit( self.npcId) if questData: quest = questData[1] self.currentQuestObjective = quest.currentObjectiveIndex self.currentQuestId = questData[0] self.currentChatIndex = 0 if CIGlobals.NPCToonDict[self.npcId][3] == CIGlobals.NPC_HQ: if not quest.isComplete(): self.doNPCChat(array=Quests.QuestHQOfficerDialogue) if CIGlobals.NPCToonDict[self.npcId][3] == CIGlobals.NPC_REGULAR: self.doNPCChat(array=Quests.QuestNPCDialogue) def doNPCChat(self, array=Quests.QuestNPCDialogue, chat=None): if array and not chat: self.chatArray = array self.b_setChat(array[self.currentQuestId][ self.currentQuestObjective][self.currentChatIndex]) self.currentChatIndex += 1 Sequence(Wait(0.1), Func(self.acceptOnce, 'mouse1-up', self.doNextNPCChat)).start() else: if chat and not array: self.b_setChat(chat) Sequence( Wait(0.1), Func(self.acceptOnce, 'mouse1-up', self.d_requestExit)).start() def d_requestExit(self): self.sendUpdate('requestExit', []) def doNextNPCChat(self): if self.currentChatIndex >= len(self.chatArray[self.currentQuestId][ self.currentQuestObjective]): self.chatArray = None self.d_requestExit() else: self.doNPCChat(self.chatArray) return def rejectEnter(self): self.exitAccepted() def exitAccepted(self): self.stopCameraTrack() self.cr.playGame.getPlace().fsm.request('walk') self.acceptCollisions() def acceptCollisions(self): self.acceptOnce('enter' + self.uniqueName('NPCToonSphere'), self.handleEnterCollision) def ignoreCollisions(self): self.ignore('enter' + self.uniqueName('NPCToonSphere')) def __npcOriginPoll(self, task): if task.time > 4.0: self.notify.warning( 'Giving up waiting for npc origin after %d seconds. Will parent to render.' % task.time) self.reparentTo(render) return task.done npcOrigin = render.find('**/npc_origin_' + str(self.originIndex)) if not npcOrigin.isEmpty(): self.reparentTo(npcOrigin) return task.done return task.cont def startNPCOriginPoll(self): base.taskMgr.add(self.__npcOriginPoll, self.uniqueName('NPCOriginPoll')) def stopNPCOriginPoll(self): base.taskMgr.remove(self.uniqueName('NPCOriginPoll')) def setupNameTag(self, tempName=None): DistributedToon.setupNameTag(self, tempName) self.nametag.setNametagColor( NametagGlobals.NametagColors[NametagGlobals.CCNPC]) self.nametag.setActive(0) self.nametag.updateAll() def announceGenerate(self): DistributedToon.announceGenerate(self) self.startLookAround() self.__setupCollisions() npcOrigin = render.find('**/npc_origin_' + str(self.originIndex)) if not npcOrigin.isEmpty(): self.reparentTo(npcOrigin) else: self.startNPCOriginPoll() self.acceptCollisions() def disable(self): self.ignore('mouse1-up') self.stopLookAround() self.stopNPCOriginPoll() self.chatArray = None self.originIndex = None self.npcId = None self.stopCameraTrack() self.ignoreCollisions() self.__removeCollisions() DistributedToon.disable(self) return
class BambooCane(ToonUpGag): def __init__(self): ToonUpGag.__init__(self, CIGlobals.BambooCane, 'phase_5/models/props/cane.bam', 40, 45, 100, GagGlobals.BAMBOO_CANE_SFX, 1) self.setImage('phase_3.5/maps/bamboo-cane.png') self.hatPath = 'phase_5/models/props/hat.bam' self.hat = None self.track = None self.scaleDuration = 0.5 self.scaleUp = None self.scaleDown = None self.soundInterval = None self.timeout = 5.0 def buildHat(self): self.cleanupHat() self.hat = loader.loadModel(self.hatPath) def cleanupHat(self): if self.hat: self.hat.removeNode() def buildScaleTracks(self): props = [] props.append(self.hat) props.append(self.gag) self.scaleUp = self.getScaleTrack(props, self.scaleDuration, self.PNTNEARZERO, self.PNTNORMAL) self.scaleDown = self.getScaleTrack(props, self.scaleDuration, self.PNTNORMAL, self.PNTNEARZERO) def start(self): super(BambooCane, self).start() if not self.hat: self.buildHat() if not self.gag: self.build() self.setupHandJoints() if not self.scaleUp: self.buildScaleTracks() self.placeProp(self.handJoint, self.hat, Point3(0.23, 0.09, 0.69), Point3(180, 0, 0)) self.placeProp(self.lHandJoint, self.gag, Point3(-0.28, 0.0, 0.14), Point3(0.0, 0.0, -150.0)) self.soundInterval = self.getSoundTrack(0.2, self.gag, 6.4) propInterval = Sequence() propInterval.append(self.scaleUp) propInterval.append( Wait(base.localAvatar.getDuration('happy-dance') - 2)) if self.avatar == base.localAvatar: propInterval.append(Func(self.setHealAmount)) propInterval.append(Func(self.healNearbyAvatars, 25)) propInterval.append(self.scaleDown) propInterval.append(Func(self.cleanupGag)) propInterval.append(Func(self.reset)) self.track = Parallel(propInterval, ActorInterval(self.avatar, 'happy-dance'), Func(self.soundInterval.start)) self.track.start() def equip(self): # self.gag returns the cane object. super(BambooCane, self).equip() self.build() self.buildHat() self.buildScaleTracks() def unEquip(self): if self.track: self.soundInterval.finish() self.track.finish() self.track = None self.reset() if self.scaleDown: Sequence(self.scaleDown, Func(self.cleanupGag)).start() def cleanupGag(self): if self.gag: self.gag.removeNode() self.cleanupHat()
class PairingGameCard(PlayingCardNodePath): """ The specifc class used for the pairing game """ DoIntervalDefault = True FlipTime = 0.25 UseDifferentCardColors = True # these color values were taken from ToonDNA.py CardColors = [ (0.933594, 0.265625, 0.28125, 1.0), # bright red (0.550781, 0.824219, 0.324219, 1.0), # light green (0.347656, 0.820312, 0.953125, 1.0), # light blue (0.460938, 0.378906, 0.824219, 1.0), # purple blue (0.710938, 0.234375, 0.4375, 1.0), # plum (0.285156, 0.328125, 0.726562, 1.0), # blue (0.242188, 0.742188, 0.515625, 1.0), # seafoam (0.96875, 0.691406, 0.699219, 1.0), # light pink (0.996094, 0.957031, 0.597656, 1.0), # light yellow (0.992188, 0.480469, 0.167969, 1.0), # orange ] def __init__(self, value): """Constructor, value should be [0..51].""" style = PlayingCardGlobals.Styles[0] PlayingCardNodePath.__init__(self, style, value) self.enterCallback = None self.exitCallback = None def load(self): """Load the assets.""" # these are just temp assets oneCard = loader.loadModel( "phase_4/models/minigames/garden_sign_memory") # grab the gag icon prop = self.attachNewNode('prop') PlayingCardGlobals.getImage(self.style, self.suit, self.rank).copyTo(prop) prop.setScale(7) # remove the bits we don't want oneCard.find('**/glow').removeNode() #oneCard.find('**/shadow').removeNode() # munge the collision to fit just the sign cs = oneCard.find('**/collision') #cs.setScale(1, 1.0, 0.5) #cs.setPos(0,0, 0.9) for solidIndex in range(cs.node().getNumSolids()): cs.node().modifySolid(solidIndex).setTangible(False) cs.node().setName('cardCollision-%d' % self.value) # munge the sign to fit the rank sign = oneCard.find('**/sign1') if self.UseDifferentCardColors: index = self.rank % len(self.CardColors) color = self.CardColors[index] sign.setColorScale(*color) # set up the prop that shows which tree it is prop.setPos(0.0, 0.0, 0.08) prop.setP(-90) prop.reparentTo(oneCard) oneCard.reparentTo(self) #set up the back of the card cardBack = oneCard.find('**/sign2') cardBack.setColorScale(0.12, 0.35, 0.5, 1.0) cardModel = loader.loadModel('phase_3.5/models/gui/playingCard') logo = cardModel.find('**/logo') logo.reparentTo(self) logo.setScale(0.45) logo.setP(90) logo.setZ(0.025) logo.setX(-0.05) logo.setH(180) cardModel.remove() self.setR(0) # the default value is face Up self.setScale(2.5) self.flipIval = None self.turnUpSound = base.loadSfx( "phase_4/audio/sfx/MG_pairing_card_flip_face_up.mp3") self.turnDownSound = base.loadSfx( "phase_4/audio/sfx/MG_pairing_card_flip_face_down.mp3") def unload(self): """Unload the assets.""" self.clearFlipIval() self.removeNode() del self.turnUpSound del self.turnDownSound def turnUp(self, doInterval=DoIntervalDefault): """Turn up the card. doInterval -- if true do a sound and flip up animation """ assert self.value != PlayingCardGlobals.Unknown self.faceUp = 1 if doInterval: self.clearFlipIval() self.flipIval = Parallel( LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 0)), SoundInterval(self.turnUpSound, node=self, listenerNode=base.localAvatar, cutOff=240)) self.flipIval.start() else: self.setR(0) def clearFlipIval(self): """Clear any flip intervals on this card.""" if self.flipIval: self.flipIval.finish() self.flipIval = None def turnDown(self, doInterval=DoIntervalDefault): """Turn up the card. doInterval -- if true do a sound and flip up animation """ self.faceUp = 0 if doInterval: self.clearFlipIval() self.flipIval = Parallel( LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 180)), SoundInterval(self.turnDownSound, node=self, listenerNode=base.localAvatar, cutOff=240)) self.flipIval.start() else: self.setR(180)
class DistributedBoat(DistributedObject): notify = directNotify.newCategory("DistributedBoat") def __init__(self, cr): DistributedObject.__init__(self, cr) self.fsm = ClassicFSM('DistributedBoat', [ State('off', self.enterOff, self.exitOff), State('eastToWest', self.enterEastToWest, self.exitEastToWest), State('westToEast', self.enterWestToEast, self.exitWestToEast) ], 'off', 'off') self.boat = None self.eastPier = None self.eastPierPath = 'east_pier' self.westPier = None self.westPierPath = 'west_pier' self.pierUpP = 0.0 self.pierDownP = -45.0 self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.ogg' self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.ogg' self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.ogg' self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.ogg' self.eastWest = 'phase_6/paths/dd-e-w.bam' self.westEast = 'phase_6/paths/dd-w-e.bam' self.track = None self.state = None self.animBoat1Track = None self.animBoatTrack = None # Variables that handle the winter collision node. self.crashColl = None self.crashCollNP = None def __handleOnBoat(self, entry): base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat) def __handleOffBoat(self, entry): base.localAvatar.b_setParent(CIGlobals.SPRender) base.localAvatar.setR(0) base.localAvatar.setP(0) def generate(self): DistributedObject.generate(self) self.soundFogHorn = base.audio3d.loadSfx(self.fogHorn) self.soundShipBell = base.audio3d.loadSfx(self.shipBell) self.soundWaterLap = base.audio3d.loadSfx(self.waterLap) self.soundDockCreak = base.audio3d.loadSfx(self.dockCreak) geom = self.cr.playGame.hood.loader.geom self.boatMdl = geom.find('**/*donalds_boat*') self.boat = geom.find("**/ddBoatRoot") self.boatMdl1 = geom.find("**/ddBoatMdl1") base.audio3d.attachSoundToObject(self.soundFogHorn, self.boat) base.audio3d.attachSoundToObject(self.soundShipBell, self.boat) base.audio3d.attachSoundToObject(self.soundWaterLap, self.boat) base.audio3d.attachSoundToObject(self.soundDockCreak, self.boat) self.soundWaterLap.setLoop(True) self.soundWaterLap.play() self.generated() def generated(self): self.eastPier = self.cr.playGame.hood.loader.geom.find( '**/' + self.eastPierPath) self.westPier = self.cr.playGame.hood.loader.geom.find( '**/' + self.westPierPath) base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boatMdl) self.accept('enterdonalds_boat_floor', self.__handleOnBoat) self.accept('exitdonalds_boat_floor', self.__handleOffBoat) self.d_requestCurrentStateAndTimestamp() self.fsm.enterInitialState() speedFactor = 2 self.animBoatTrack = Sequence( LerpHprInterval(self.boatMdl, duration=1 * speedFactor, hpr=(0, 0, -1), startHpr=(0, 0, 1), blendType='easeInOut'), LerpHprInterval(self.boatMdl, duration=1 * speedFactor, hpr=(0, 0, 1), startHpr=(0, 0, -1), blendType='easeInOut')) import math self.animBoat1Track = Sequence( LerpHprInterval(self.boatMdl1, duration=math.pi * speedFactor, hpr=(0, 1, 0), startHpr=(0, -1, 0), blendType='easeInOut'), LerpHprInterval(self.boatMdl1, duration=math.pi * speedFactor, hpr=(0, -1, 0), startHpr=(0, 1, 0), blendType='easeInOut')) self.animBoat1Track.loop() self.animBoatTrack.loop() if base.cr.holidayManager.getHoliday() == HolidayType.CHRISTMAS: self.boat.setPosHpr(12.73, -1.6, -4.7, 341.57, 350.0, 26.5) self.fsm.request('off') self.crashColl = CollisionSphere(0, 0, 0, 15) self.crashCollNP = self.boat.attachNewNode( CollisionNode('crashed_boat_collision')) self.crashCollNP.node().addSolid(self.crashColl) self.crashCollNP.node().setCollideMask(CIGlobals.WallBitmask) self.crashCollNP.setSz(2) self.crashCollNP.setSx(0.75) self.crashCollNP.setSy(1.25) self.crashCollNP.setPosHpr(2.05, 3.21, 1.66, 8.44, 6.93, 332.61) def disable(self): base.taskMgr.remove(self.uniqueName('__pollBoat')) base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat) self.ignore('enterdonalds_boat_floor') self.ignore('exitdonalds_boat_floor') self.fsm.requestFinalState() if self.animBoat1Track: self.animBoat1Track.finish() self.animBoat1Track = None if self.animBoatTrack: self.animBoatTrack.finish() self.animBoatTrack = None if self.crashCollNP: self.crashCollNP.removeNode() del self.crashCollNP del self.crashColl del self.fsm del self.soundFogHorn del self.soundShipBell self.soundWaterLap.stop() del self.soundWaterLap del self.soundDockCreak self.fogHorn = None self.shipBell = None self.waterLap = None self.dockCreak = None self.boat = None self.boatMdl = None self.boatMdl1 = None self.track = None self.pierDownP = None self.pierUpP = None self.eastPier = None self.eastPierPath = None self.westPier = None self.westPierPath = None self.boatPath = None self.westEast = None self.eastWest = None DistributedObject.disable(self) def currentStateAndTimestamp(self, state, timestamp): self.setState(state, timestamp) def d_requestCurrentStateAndTimestamp(self): self.sendUpdate('requestCurrentStateAndTimestamp', []) def setState(self, state, timestamp=None): if timestamp is None: ts = 0.0 else: ts = globalClockDelta.localElapsedTime(timestamp) self.state = state if self.boat and base.cr.holidayManager.getHoliday( ) != HolidayType.CHRISTMAS: self.fsm.request(state, [ts]) def enterEastToWest(self, ts=0): moPath = Mopath.Mopath() moPath.loadFile(self.eastWest) moIval = MopathInterval(moPath, self.boat, blendType='easeInOut') self.track = Parallel( SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.eastPier), moIval, LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierDownP, 0), startHpr=(90, self.pierUpP, 0), blendType='easeInOut'), Sequence( Wait(15.0), Parallel( LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierUpP, 0), startHpr=(-90, self.pierDownP, 0), blendType='easeInOut'), Sequence( Wait(2.0), SoundInterval(self.soundDockCreak, node=self.westPier))), SoundInterval(self.soundFogHorn, node=self.boat))) self.track.start(ts) def exitEastToWest(self): if self.track: self.track.finish() self.track = None def enterWestToEast(self, ts=0): moPath = Mopath.Mopath() moPath.loadFile(self.westEast) moIval = MopathInterval(moPath, self.boat, blendType='easeInOut') self.track = Parallel( SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.westPier), moIval, LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierDownP, 0), startHpr=(-90, self.pierUpP, 0), blendType='easeInOut'), Sequence( Wait(15.0), Parallel( LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierUpP, 0), startHpr=(90, self.pierDownP, 0), blendType='easeInOut'), Sequence( Wait(2.0), SoundInterval(self.soundDockCreak, node=self.eastPier))), SoundInterval(self.soundFogHorn, node=self.boat))) self.track.start(ts) def exitWestToEast(self): if self.track: self.track.finish() self.track = None def enterOff(self): pass def exitOff(self): pass
class FountainPenAttack(Attack): notify = directNotify.newCategory('FountainPenAttack') attack = 'fountainpen' def __init__(self, attacksClass, suit): Attack.__init__(self, attacksClass, suit) self.pen = None self.spray = None self.splat = None self.spraySfx = None self.sprayParticle = None self.sprayScaleIval = None self.wsnp = None return def loadAttack(self): self.pen = loader.loadModel('phase_5/models/props/pen.bam') self.pen.reparentTo(self.suit.find('**/joint_Rhold')) self.sprayParticle = ParticleLoader.loadParticleEffect('phase_5/etc/penSpill.ptf') self.spray = loader.loadModel('phase_3.5/models/props/spray.bam') self.spray.setColor(VBase4(0, 0, 0, 1)) self.splat = Actor('phase_3.5/models/props/splat-mod.bam', {'chan': 'phase_3.5/models/props/splat-chan.bam'}) self.splat.setColor(VBase4(0, 0, 0, 1)) self.sprayScaleIval = LerpScaleInterval(self.spray, duration=0.3, scale=(1, 20, 1), startScale=(1, 1, 1)) sphere = CollisionSphere(0, 0, 0, 0.5) sphere.setTangible(0) if hasattr(self.suit, 'uniqueName'): collName = self.suit.uniqueName('fountainPenCollNode') else: collName = 'fountainPenCollNode' collNode = CollisionNode(collName) collNode.addSolid(sphere) collNode.setCollideMask(CIGlobals.WallBitmask) self.wsnp = self.spray.attachNewNode(collNode) self.wsnp.setY(1) def doAttack(self, ts = 0): self.loadAttack() if hasattr(self.suit, 'uniqueName'): name = self.suit.uniqueName('doFountainPenAttack') else: name = 'doFountainPenAttack' self.suitTrack = Parallel(name=name) self.suitTrack.append(ActorInterval(self.suit, 'fountainpen')) self.suitTrack.append(Sequence(Wait(1.2), Func(self.acceptOnce, 'enter' + self.wsnp.node().getName(), self.handleSprayCollision), Func(self.playWeaponSound), Func(self.attachSpray), Func(self.sprayParticle.start, self.pen.find('**/joint_toSpray'), self.pen.find('**/joint_toSpray')), self.sprayScaleIval, Wait(0.5), Func(self.sprayParticle.cleanup), Func(self.spray.setScale, 1), Func(self.spray.reparentTo, hidden), Func(self.ignore, 'enter' + self.wsnp.node().getName()))) self.suitTrack.setDoneEvent(self.suitTrack.getName()) self.acceptOnce(self.suitTrack.getDoneEvent(), self.finishedAttack) self.suitTrack.delayDelete = DelayDelete.DelayDelete(self.suit, name) self.suitTrack.start(ts) def attachSpray(self): self.spray.reparentTo(self.pen.find('**/joint_toSpray')) pos = self.spray.getPos(render) hpr = self.spray.getHpr(render) self.spray.reparentTo(render) self.spray.setPos(pos) self.spray.setHpr(hpr) self.spray.setP(0) if self.suit.type == 'C': self.spray.setH(self.spray.getH() + 7.5) self.spray.setTwoSided(True) def handleSprayCollision(self, entry): if self.suit: self.suit.sendUpdate('toonHitByWeapon', [self.getAttackId(self.attack), base.localAvatar.doId]) base.localAvatar.b_handleSuitAttack(self.getAttackId(self.attack), self.suit.doId) self.sprayScaleIval.pause() def playWeaponSound(self): self.spraySfx = base.audio3d.loadSfx('phase_5/audio/sfx/SA_fountain_pen.mp3') base.audio3d.attachSoundToObject(self.spraySfx, self.pen) self.spraySfx.play() def cleanup(self): Attack.cleanup(self) if self.wsnp: self.wsnp.node().clearSolids() self.wsnp.removeNode() self.wsnp = None if self.pen: self.pen.removeNode() self.pen = None if self.sprayParticle: self.sprayParticle.cleanup() self.sprayParticle = None if self.spray: self.spray.removeNode() self.spray = None if self.splat: self.splat.cleanup() self.splat = None if self.sprayScaleIval: self.sprayScaleIval.pause() self.sprayScaleIval = None self.spraySfx = None return
class DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedBanquetTable") rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble("water-power-speed", 15) waterPowerExponent = base.config.GetDouble("water-power-exponent", 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = "BanquetTableUpdateKeyPressRateTask" YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.96999999999999997 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, "DistributedBanquetTable") self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self._DistributedBanquetTable__broadcastPeriod = 0.20000000000000001 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in self.dinerStatusIndicators.values(): indicator.delete() self.dinerStatusIndicators = {} for diner in self.diners.values(): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName("pitcherSmooth") self.pitcherAdviceName = self.uniqueName("pitcherAdvice") self.posHprBroadcastName = self.uniqueName("pitcherBroadcast") self.waterPowerTaskName = self.uniqueName("updateWaterPower") self.triggerName = self.uniqueName("trigger") self.watchControlsName = self.uniqueName("watchControls") def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == "F": self.demand("Off") elif state == "N": self.demand("On") elif state == "I": self.demand("Inactive") elif state == "R": self.demand("Free") elif state == "C": self.demand("Controlled", avId) elif state == "L": self.demand("Flat", avId) else: self.notify.error("Invalid state from AI: %s" % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in xrange(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel("phase_12/models/bossbotHQ/BanquetTableChairs") tableLocator = self.boss.geom.find("**/TableLocator_%d" % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find("**/Geometry") self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx("phase_4/audio/sfx/AA_squirt_seltzer_miss.mp3") self.hitBossSfx = loader.loadSfx("phase_5/audio/sfx/SA_watercooler_spray_only.mp3") self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx("phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.mp3") self.pitcherMoveSfx = base.loadSfx("phase_4/audio/sfx/MG_cannon_adjust.mp3") def setupDiners(self): for i in xrange(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept="c") diner.setDNA(diner.dna) if self.useNewAnimations: diner.loop("sit", fromFrame=i) else: diner.pose("landing", 0) locator = self.tableGroup.find("**/chair_%d" % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode("correctHeading") self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode("sitLocator") base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == "c": sitLocator.setPos(0.5, 3.6499999999999999, -3.75) else: sitLocator.setZ(-2.3999999999999999) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath("serviceLoc-%d-%d" % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find("**/joint_head") newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in xrange(self.numDiners): chairCol = self.tableGroup.find("**/collision_chair_%d" % (i + 1)) colName = "ChairCol-%d-%d" % (self.index, i) chairCol.setTag("chairIndex", str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept("enter" + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag("chairIndex")) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel("phase_12/models/bossbotHQ/canoffood") foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find("**/tray") if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel( SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval( food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc) ), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0)), ) intervalName = "serveFood-%d-%d" % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in xrange(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request("Eating", eatingDuration) diner = self.diners[chairIndex] intervalName = "eating-%d-%d" % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self=self, diner=diner): foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.14999999999999999, -0.69999999999999996, -0.40000000000000002)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 (foodModel.setPos(Point3(0.10000000000000001, -0.25, -0.31)),) else: scaleAdj = 0.80000000000000004 (foodModel.setPos(Point3(-0.25, -0.84999999999999998, -0.34000000000000002)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self=self, diner=diner): foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 else: scakeAdj = 0.80000000000000004 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence( ActorInterval(diner, "sit", duration=waitTime), ActorInterval(diner, "sit-eat-in", startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, "sit-eat-in", startFrame=6, endFrame=32), ActorInterval(diner, "sit-eat-loop", duration=loopDuration, loop=1), ActorInterval(diner, "sit-eat-out", startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, "sit-eat-out", startFrame=12, endFrame=21), ) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = "eating-%d-%d" % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Hungry", self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop("sit-hungry-left") else: diner.loop("sit-hungry-right") def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Angry") diner = self.diners[chairIndex] diner.loop("sit-angry") def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Dead") diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find("**/chair_%d" % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence( Func(self.notify.debug, "before actorinterval sit-lose"), ActorInterval(diner, "sit-lose"), Func(self.notify.debug, "before deathSuit.setHpr"), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, "before diner.hide"), Func(diner.hide), Func(self.notify.debug, "before deathSuit.reparentTo"), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, "befor ActorInterval lose"), ActorInterval(deathSuit, "lose", duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, "before remove deathsuit"), Func(removeDeathSuit, diner, deathSuit, name="remove-death-suit-%d-%d" % (chairIndex, self.index)), Func(self.notify.debug, "diner.stash"), Func(diner.stash), ) spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.mp3") deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.mp3") deathSoundTrack = Sequence( Wait(0.80000000000000004), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.20000000000000001, node=deathSuit), SoundInterval( spinningSound, duration=3.0, startTime=0.59999999999999998, volume=0.80000000000000004, node=deathSuit ), SoundInterval(deathSound, volume=0.32000000000000001, node=deathSuit), ) intervalName = "dinerDie-%d-%d" % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in self.diners.values(): if not diner.isHidden(): diner.loop("sit", fromFrame=startFrame) startFrame += 1 continue def cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish=1): if self.activeIntervals.has_key(name): ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if self.activeIntervals.has_key(name): del self.activeIntervals[name] else: self.notify.debug("interval: %s already cleared" % name) def finishInterval(self, name): if self.activeIntervals.has_key(name): interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in xrange(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) continue return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in xrange(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.29999999999999999) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self._DistributedBanquetTable__allowDetect, self.triggerName) self.fadeTrack = Sequence( Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 0.29999999999999999)), ) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag("tableIndex")) if self.state == "Free" and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in xrange(8): chair = self.tableGroup.find("**/chair_%d" % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches("**/ChairCol*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches("**/collision_chair*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find("**/collision_table") colName = "TableCol-%d" % self.index tableCol.setTag("tableIndex", str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept("enter" + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel("phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle") lampNode = self.tableGroup.find("**/lamp_med_5") pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find("**/bottle_locator") pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode("pitcherNode") self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.waterPitcherModel.ls() self.nozzle = self.waterPitcherModel.find("**/nozzle_tip") self.handLocator = self.waterPitcherModel.find("**/hand_locator") self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate("requestControl") def d_requestFree(self, gotHitByBoss): self.sendUpdate("requestFree", [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return None self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug("grabTrack=%s" % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self._DistributedBanquetTable__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence( self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode), ) if self.TugOfWarControls: self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() self.accept("exitCrane", self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore("exitCrane") if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug("nextState=%s" % nextState) if nextState == "Flat": place = base.cr.playGame.getPlace() self.notify.debug("%s" % place.fsm) if self.avId == localAvatar.doId: self._DistributedBanquetTable__disableControlInterface() elif self.toon and not self.toon.isDisabled(): self.toon.loop("neutral") self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self._DistributedBanquetTable__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, "fsm"): if place.fsm.getCurrentState().getName() == "crane": place.setState("finalBattle") def makeToonGrabInterval(self, toon): toon.pose("leverNeutral", 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence( Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, "neutral"), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), Parallel( ProjectileInterval( toon, duration=0.90000000000000002, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition, ), LerpHprInterval(toon, 0.90000000000000002, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.90000000000000002, Point3(1, 1, destZScale)), ), ), ), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, "leverNeutral"), ) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode("temp1") temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode("temp2") temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug("creating zap interval instead") grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, "slip-backward"), toon.posInterval(0.5, getSlideToPos, fluid=1)), ) else: grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), ProjectileInterval(toon, duration=0.90000000000000002, startPos=startPos, endPos=endPos), ), ), ) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate("clearSmoothing", [0]) def clearSmoothing(self, bogus=None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def _DistributedBanquetTable__enableControlInterface(self): gui = loader.loadModel("phase_3.5/models/gui/avatar_panel_gui") self.closeButton = DirectButton( image=( gui.find("**/CloseBtn_UP"), gui.find("**/CloseBtn_DN"), gui.find("**/CloseBtn_Rllvr"), gui.find("**/CloseBtn_UP"), ), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.040000000000000001, text_pos=(0, -0.070000000000000007), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.81999999999999995), command=self._DistributedBanquetTable__exitPitcher, ) self.accept("escape", self._DistributedBanquetTable__exitPitcher) self.accept("control", self._DistributedBanquetTable__controlPressed) self.accept("control-up", self._DistributedBanquetTable__controlReleased) self.accept("InputState-forward", self._DistributedBanquetTable__upArrow) self.accept("InputState-reverse", self._DistributedBanquetTable__downArrow) self.accept("InputState-turnLeft", self._DistributedBanquetTable__leftArrow) self.accept("InputState-turnRight", self._DistributedBanquetTable__rightArrow) self.accept("arrow_up", self._DistributedBanquetTable__upArrowKeyPressed) self.accept("arrow_down", self._DistributedBanquetTable__downArrowKeyPressed) taskMgr.add(self._DistributedBanquetTable__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self._DistributedBanquetTable__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() def _DistributedBanquetTable__disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self._DistributedBanquetTable__cleanupPitcherAdvice() self.ignore("escape") self.ignore("control") self.ignore("control-up") self.ignore("InputState-forward") self.ignore("InputState-reverse") self.ignore("InputState-turnLeft") self.ignore("InputState-turnRight") self.ignore("arrow_up") self.ignore("arrow_down") self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self._DistributedBanquetTable__killUpdateKeyPressRateTask() self.keyTTL = [] self._DistributedBanquetTable__setMoveSound(None) def _DistributedBanquetTable__displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel( text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.68999999999999995), scale=0.10000000000000001, ) def _DistributedBanquetTable__cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.059999999999999998, text_fg=VBase4(1, 1, 1, 1), ) self._DistributedBanquetTable__cleanupPitcherAdvice() def _DistributedBanquetTable__exitPitcher(self): self.showExiting() self.d_requestFree(False) def _DistributedBanquetTable__controlPressed(self): self._DistributedBanquetTable__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self._DistributedBanquetTable__endFireWater() elif self.state == "Controlled": self._DistributedBanquetTable__beginFireWater() def _DistributedBanquetTable__controlReleased(self): if self.TugOfWarControls: pass 1 if self.state == "Controlled": self._DistributedBanquetTable__endFireWater() def _DistributedBanquetTable__upArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def _DistributedBanquetTable__downArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def _DistributedBanquetTable__rightArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def _DistributedBanquetTable__leftArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def _DistributedBanquetTable__incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) def _DistributedBanquetTable__posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate("setPitcherPos", [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def _DistributedBanquetTable__watchControls(self, task): if self.arrowHorz: self._DistributedBanquetTable__movePitcher(self.arrowHorz) else: self._DistributedBanquetTable__setMoveSound(None) return Task.cont def _DistributedBanquetTable__movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug( "rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f" % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h) ) limitH = h self.waterPitcherNode.setH(limitH) if xd: self._DistributedBanquetTable__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack( self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale=1.0, vertScale=1.0, parent=render ): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp("spray") sprayScale = hidden.attachNewNode("spray-parent") sprayRot = hidden.attachNewNode("spray-rotate") spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target=target, origin=origin, horizScale=horizScale, vertScale=vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return None if self.avId != base.localAvatar.doId: return None tag = self.hitObject.getNetTag("pieCode") pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate("waterHitBoss", [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar( pos=(0.0, 0, -0.93999999999999995), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.20000000000000001, 0.20000000000000001), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.80000000000000004), text="", text_scale=0.26000000000000001, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.050000000000000003), ) self.power = 0 self.powerBar["value"] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar["value"] = self.power self.powerBar["text"] = "" self.keyTTL = [] def _DistributedBanquetTable__beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return None if self.aimStart != None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None time = globalClock.getFrameTime() self.aimStart = time messenger.send("wakeup") taskMgr.add(self._DistributedBanquetTable__updateWaterPower, self.waterPowerTaskName) def _DistributedBanquetTable__endFireWater(self): if self.aimStart == None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None taskMgr.remove(self.waterPowerTaskName) messenger.send("wakeup") self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode("pitcherColNode")) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask( ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask ) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() def _DistributedBanquetTable__updateWaterPower(self, task): if not self.powerBar: print "### no power bar!!!" return task.done newPower = self._DistributedBanquetTable__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) return task.cont def _DistributedBanquetTable__getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate("firingWater", [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.80000000000000004) dScaleUp = 0.10000000000000001 dHold = 0.29999999999999999 dScaleDown = 0.10000000000000001 horizScale = 0.10000000000000001 vertScale = 0.10000000000000001 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt=render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug("enterFlat %d" % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState("neutral") toon.setAnimState("neutral") toon.loop("leverNeutral") def _DistributedBanquetTable__allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence( self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency), ) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def _DistributedBanquetTable__upArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(0) def _DistributedBanquetTable__downArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(1) def _DistributedBanquetTable__pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def _DistributedBanquetTable__spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater( 0.10000000000000001, self._DistributedBanquetTable__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK), ) def _DistributedBanquetTable__killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def _DistributedBanquetTable__updateKeyPressRateTask(self, task): if self.state not in "Controlled": return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.10000000000000001 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break continue self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug("diffPower=%.2f keyRate = %d, newPower=%.2f" % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() return Task.done def _DistributedBanquetTable__setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
class DodgeballFirstPerson(FirstPerson): """The first person controls for the local player in Winter Dodgeball""" notify = directNotify.newCategory("DodgeballFirstPerson") MaxPickupDistance = 5.0 def __init__(self, mg): self.mg = mg self.crosshair = None self.soundCatch = None self.vModelRoot = None self.vModel = None self.ival = None self.soundPickup = base.loadSfx( 'phase_4/audio/sfx/MG_snowball_pickup.wav') self.fakeSnowball = loader.loadModel( "phase_5/models/props/snowball.bam") self.hasSnowball = False self.mySnowball = None self.fsm = ClassicFSM.ClassicFSM("DodgeballFirstPerson", [ State.State("off", self.enterOff, self.exitOff), State.State("hold", self.enterHold, self.exitHold), State.State("catch", self.enterCatch, self.exitCatch), State.State("throw", self.enterThrow, self.exitThrow) ], "off", "off") self.fsm.enterInitialState() FirstPerson.__init__(self) def enterOff(self): if self.vModel: self.vModel.hide() def exitOff(self): if self.vModel: self.vModel.show() def enterHold(self): self.ival = Sequence(ActorInterval(self.vModel, "hold-start"), Func(self.vModel.loop, "hold")) self.ival.start() def exitHold(self): if self.ival: self.ival.finish() self.ival = None self.vModel.stop() def enterThrow(self): self.ival = Parallel( Sequence(Wait(0.4), Func(self.mySnowball.b_throw)), Sequence(ActorInterval(self.vModel, "throw"), Func(self.fsm.request, 'off'))) self.ival.start() def exitThrow(self): if self.ival: self.ival.pause() self.ival = None self.vModel.stop() def enterCatch(self): self.ival = Parallel( Sequence(Wait(0.2), Func(self.__tryToCatchOrGrab)), Sequence(ActorInterval(self.vModel, "catch"), Func(self.__maybeHold))) self.ival.start() def __maybeHold(self): if self.hasSnowball: self.fsm.request('hold') else: self.fsm.request('off') def __tryToCatchOrGrab(self): snowballs = list(self.mg.snowballs) snowballs.sort( key=lambda snowball: snowball.getDistance(base.localAvatar)) for i in xrange(len(snowballs)): snowball = snowballs[i] if (not snowball.hasOwner() and not snowball.isAirborne and snowball.getDistance(base.localAvatar) <= DodgeballFirstPerson.MaxPickupDistance): snowball.b_pickup() self.mySnowball = snowball self.fakeSnowball.setPosHpr(0, 0.73, 0, 0, 0, 0) self.fakeSnowball.reparentTo( self.vModel.exposeJoint(None, "modelRoot", "Bone.011")) base.playSfx(self.soundPickup) self.hasSnowball = True break def exitCatch(self): self.vModel.stop() if self.ival: self.ival.pause() self.ival = None def start(self): # Black crosshair because basically the entire arena is white. self.crosshair = getCrosshair(color=(0, 0, 0, 1), hidden=False) self.soundCatch = base.loadSfx( "phase_4/audio/sfx/MG_sfx_vine_game_catch.ogg") self.vModelRoot = camera.attachNewNode('vModelRoot') self.vModelRoot.setPos(-0.09, 1.38, -2.48) self.vModel = Actor( "phase_4/models/minigames/v_dgm.egg", { "hold": "phase_4/models/minigames/v_dgm-ball-hold.egg", "hold-start": "phase_4/models/minigames/v_dgm-ball-hold-start.egg", "throw": "phase_4/models/minigames/v_dgm-ball-throw.egg", "catch": "phase_4/models/minigames/v_dgm-ball-catch.egg" }) self.vModel.setBlend(frameBlend=True) self.vModel.reparentTo(self.vModelRoot) self.vModel.setBin("fixed", 40) self.vModel.setDepthTest(False) self.vModel.setDepthWrite(False) self.vModel.hide() base.localAvatar.walkControls.setWalkSpeed(ToonForwardSpeed, ToonJumpForce, ToonReverseSpeed, ToonRotateSpeed) FirstPerson.start(self) def reallyStart(self): FirstPerson.reallyStart(self) base.localAvatar.startTrackAnimToSpeed() self.accept('mouse3', self.__handleCatchOrGrabButton) self.accept('mouse1', self.__handleThrowButton) def __handleThrowButton(self): if self.hasSnowball and self.mySnowball and self.fsm.getCurrentState( ).getName() == 'hold': self.fakeSnowball.reparentTo(hidden) self.fsm.request('throw') def __handleCatchOrGrabButton(self): if not self.hasSnowball and not self.mySnowball and self.fsm.getCurrentState( ).getName() == 'off': self.fsm.request('catch') def reallyEnd(self): base.localAvatar.setWalkSpeedNormal() FirstPerson.reallyEnd(self)
class CogThief(DirectObject): """This represents a single cog thief in the cog thief game""" notify = directNotify.newCategory("CogThief") DefaultSpeedWalkAnim = 4. CollisionRadius = 1.25 MaxFriendsVisible = 4 Infinity = 100000.0 # just a really big number SeparationDistance = 6.0 MinUrgency = 0.5 MaxUrgency = 0.75 def __init__(self, cogIndex, suitType, game, cogSpeed): self.cogIndex = cogIndex self.suitType = suitType self.game = game self.cogSpeed = cogSpeed suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitType) suit.setDNA(d) # cache the walk anim suit.pose('walk', 0) self.suit = suit self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId self.lastLocalTimeStampFromAI = 0 self.lastPosFromAI = Point3(0, 0, 0) self.lastThinkTime = 0 self.doneAdjust = False self.barrel = CTGG.NoBarrelCarried self.signalledAtReturnPos = False self.defaultPlayRate = 1.0 self.netTimeSentToStartByHit = 0 # steering loosely based on boid code game programming gems #1 # "Portions Copyright (C) Steven Woodcock, 2000" self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) self.bodyLength = self.CollisionRadius * 2 # Desired distance from closest neighbor when flying. self.cruiseDistance = 2 * self.bodyLength self.maxVelocity = self.cogSpeed # Maximum magnitude of acceleration as a fraction of maxSpeed. self.maxAcceleration = 5.0 self.perceptionRange = 6 self.notify.debug('cogSpeed=%s' % self.cogSpeed) self.kaboomSound = loader.loadSfx( "phase_4/audio/sfx/MG_cannon_fire_alt.mp3") self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() self.kaboom.hide() self.kaboomTrack = None splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') def destroy(self): self.ignoreAll() self.suit.delete() self.game = None def uniqueName(self, baseStr): return baseStr + '-' + str(self.game.doId) def handleEnterSphere(self, collEntry): """Handle the suit colliding with localToon.""" #assert self.notify.debugStateCall(self) intoNp = collEntry.getIntoNodePath() self.notify.debug('handleEnterSphere suit %d hit %s' % (self.cogIndex, intoNp)) if self.game: self.game.handleEnterSphere(collEntry) def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollisions() self.startWalkAnim() def gameEnd(self): self.moveIval.pause() del self.moveIval self.shutdownCollisions() # keep the suits from walking in place self.suit.loop('neutral') def initCollisions(self): # Make a sphere, give it a unique name, and parent it # to the suit. self.collSphere = CollisionSphere(0, 0, 0, 1.25) # Make he sphere intangible self.collSphere.setTangible(1) name = "CogThiefSphere-%d" % self.cogIndex self.collSphereName = self.uniqueName(name) self.collNode = CollisionNode(self.collSphereName) self.collNode.setIntoCollideMask(CTGG.BarrelBitmask | ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) #self.collNodePath.hide() # Add a hook looking for collisions with localToon self.accept('enter' + self.collSphereName, self.handleEnterSphere) # we need a taller collision tube to collide against for pie self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4, self.CollisionRadius) # Make he sphere intangible self.pieCollSphere.setTangible(1) name = "CogThiefPieSphere-%d" % self.cogIndex self.pieCollSphereName = self.uniqueName(name) self.pieCollNode = CollisionNode(self.pieCollSphereName) self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.pieCollNode.addSolid(self.pieCollSphere) self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode) #self.pieCollNodePath.show() # Add a hook looking for collisions with localToon #self.accept('enter' + self.pieCollSphereName, # self.handleEnter) def shutdownCollisions(self): self.ignore(self.uniqueName('enter' + self.collSphereName)) del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId, pos): """Update our goal and position.""" assert self.notify.debugStateCall(self) self.notify.debug('self.netTimeSentToStartByHit =%s' % self.netTimeSentToStartByHit) if not self.game: self.notify.debug('updateGoal self.game is None, just returning') return if not self.suit: self.notify.debug('updateGoal self.suit is None, just returning') return if self.goal == CTGG.NoGoal: self.startWalkAnim() if goalType == CTGG.NoGoal: self.notify.debug('updateGoal setting position to %s' % pos) self.suit.setPos(pos) self.lastThinkTime = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) if goalType == CTGG.RunAwayGoal: #import pdb; pdb.set_trace() pass if inResponseClientStamp < self.netTimeSentToStartByHit and \ self.goal == CTGG.NoGoal and \ goalType == CTGG.RunAwayGoal: #import pdb; pdb.set_trace() self.notify.warning( 'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s' % (CTGG.GoalStr[goalType], self.cogIndex, inResponseClientStamp, self.netTimeSentToStartByHit)) else: self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime( timestamp, bits=32) self.goal = goalType self.goalId = goalId self.lastPosFromAI = pos self.doneAdjust = False self.signalledAtReturnPos = False # TODO move the suit to where we expect him to be given the time difference def startWalkAnim(self): if self.suit: self.suit.loop('walk') speed = self.cogSpeed # float(MazeData.CELL_WIDTH) / self.cellWalkDuration self.defaultPlayRate = float(self.cogSpeed / self.DefaultSpeedWalkAnim) self.suit.setPlayRate(self.defaultPlayRate, 'walk') def think(self): """Calculate where we should go.""" if self.goal == CTGG.ToonGoal: self.thinkAboutCatchingToon() elif self.goal == CTGG.BarrelGoal: self.thinkAboutGettingBarrel() elif self.goal == CTGG.RunAwayGoal: self.thinkAboutRunAway() def thinkAboutCatchingToon(self): if not self.game: return av = self.game.getAvatar(self.goalId) if av: if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime avPos = av.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutCatchingToon not doneAdjust setting pos %s' % myPos) self.doneAdjust = True self.suit.setPos(myPos) if self.game.isToonPlayingHitTrack(self.goalId): # do nothing, just look at toon self.suit.headsUp(av) self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) else: self.commonMove() newPos = self.suit.getPos() self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def convertNetworkStampToGameTime(self, timestamp): """Convert a network timestamp to game time.""" localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) gameTime = self.game.local2GameTime(localStamp) return gameTime def respondToToonHit(self, timestamp): """The toon hit us, react appropriately.""" assert self.notify.debugStateCall(self) localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # using 1.0 sec as fudge #if localStamp > self.lastLocalTimeStampFromAI: if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showKaboom() # move him to his starting postion startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToToonHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearGoal(self): """Clear goal and goal id.""" self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId def thinkAboutGettingBarrel(self): """Go for a barrel.""" if not self.game: return if not hasattr(self.game, 'barrels'): return if not self.goalId in xrange(len(self.game.barrels)): return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime barrel = self.game.barrels[self.goalId] barrelPos = barrel.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutGettingBarrel not doneAdjust setting position to %s' % myPos) self.suit.setPos(myPos) """ diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI self.notify.debug('doing adjust, diffTime = %s' % diffTime) if diffTime < 0: # it just looks really weird when it moves backwards diffTime = 0 self.notify.debug('forcing diffTime to %s' % diffTime) """ self.doneAdjust = True displacement = barrelPos - myPos distanceToToon = displacement.length() #self.notify.debug('diffTime = %s' % diffTime) self.suit.headsUp(barrel) lengthTravelled = diffTime * self.cogSpeed #self.notify.debug('lengthTravelled = %s' % lengthTravelled) # don't overshoot our target if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled) displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector # always keep them grounded newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def stopWalking(self, timestamp): """Stop the cog from walking.""" localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if localStamp > self.lastLocalTimeStampFromAI: self.suit.loop('neutral') self.clearGoal() def thinkAboutRunAway(self): """Go for a barrel.""" if not self.game: return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime returnPos = CTGG.CogReturnPositions[self.goalId] myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.suit.setPos(myPos) """ diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI self.notify.debug('run away doing adjust, diffTime = %s' % diffTime) if diffTime < 0: # it just looks really weird when it moves backwards diffTime = 0 self.notify.debug('forcing diffTime to %s' % diffTime) """ self.doneAdjust = True displacement = returnPos - myPos distanceToToon = displacement.length() #self.notify.debug('diffTime = %s' % diffTime) tempNp = render.attachNewNode('tempRet') tempNp.setPos(returnPos) self.suit.headsUp(tempNp) tempNp.removeNode() lengthTravelled = diffTime * self.cogSpeed #self.notify.debug('lengthTravelled = %s' % lengthTravelled) # don't overshoot our target if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled) displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector # always keep them grounded newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) if (self.suit.getPos() - returnPos).length() < 0.0001: if not self.signalledAtReturnPos and self.barrel >= 0: # tell the AI we're at return Pos self.game.sendCogAtReturnPos(self.cogIndex, self.barrel) self.signalledAtReturnPos = True self.lastThinkTime = globalClock.getFrameTime() def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, cogPos): """Handle the AI telling us the barrel is attached to a cog.""" #assert self.notify.debugStateCall(self) if not self.game: return localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # TODO validate time? self.lastLocalTimeStampFromAI = localTimeStamp inResponseGameTime = self.convertNetworkStampToGameTime( inResponseClientStamp) self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' % (inResponseGameTime, self.netTimeSentToStartByHit)) if inResponseClientStamp < self.netTimeSentToStartByHit and \ self.goal == CTGG.NoGoal: self.notify.warning('ignoring makeCogCarrybarrel') else: barrelModel.setPos(0, -1.0, 1.5) barrelModel.reparentTo(self.suit) self.suit.setPos(cogPos) self.barrel = barrelIndex def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, barrelPos): """Handle the AI telling us the barrel is attached to a cog.""" #assert self.notify.debugStateCall(self) localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # TODO validate time? self.lastLocalTimeStampFromAI = localTimeStamp barrelModel.reparentTo(render) barrelModel.setPos(barrelPos) self.barrel = CTGG.NoBarrelCarried # #self.suit.setPos(cogPos) def respondToPieHit(self, timestamp): """The toon hit us, react appropriately.""" assert self.notify.debugStateCall(self) localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # argh using 1.0 sec as fudge #if localStamp > self.lastLocalTimeStampFromAI: if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showSplat() # move him to his starting postion startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def cleanup(self): """Do whatever is necessary to cleanup properly.""" self.clearGoal() self.ignoreAll() self.suit.delete() if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.suit = None self.game = None def adjustPlayRate(self, newPos, oldPos, diffTime): """Adjust animation rate based on how far he's moved.""" # lets slowdown playrate if they're not moving much lengthTravelled = (newPos - oldPos).length() if diffTime: speed = lengthTravelled / diffTime else: speed = self.cogSpeed rateMult = speed / self.cogSpeed newRate = rateMult * self.defaultPlayRate self.suit.setPlayRate(newRate, 'walk') def commonMove(self): """Move the cog thief. Common for all 3 behaviors """ if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() dt = globalClock.getFrameTime() - self.lastThinkTime # Step 1: Update our position. # Update our position based on the velocity # vector we computed last time around. self.oldpos = self.suit.getPos() # save off our previous position pos = self.suit.getPos() pos += self.velocity * dt # apply velocities. self.suit.setPos(pos) # Step 2: SeeFriends. # Determine if we can see any of our flockmates. self.seeFriends() acc = Vec3(0, 0, 0) # well first off we want to move to our target self.accumulate(acc, self.getTargetVector()) # Step 3: Flocking behavior. # Do we see any of our flockmates? If yes, it's time to implement # the first Three Rules (they don't matter if we can't see anybody) if self.numFlockmatesSeen > 0: #if hasattr(base,'doDebug') and base.doDebug: # import pdb; pdb.set_trace() keepDistanceVector = self.keepDistance() oldAcc = Vec3(acc) self.accumulate(acc, keepDistanceVector) if self.cogIndex == 0: #self.notify.debug('oldAcc=%s, keepDist=%s newAcc=%s' % # (oldAcc,keepDistanceVector, acc)) pass # Step 8: Constrain acceleration # If our acceleration change is more than we allow, constrain it if (acc.length() > self.maxAcceleration): # definitely too much...constrain to maximum change acc.normalize() acc *= self.maxAcceleration # Step 9: Implementation. # Here's where we apply our newly computed acceleration vector # to create a new velocity vector to use next update cycle. self.oldVelocity = self.velocity # save off our previous velocity # now add in the acceleration self.velocity += acc # Step 10: constraint Y velocity changes. # Attempt to restrict flight straight up/down by damping out Y axis velocity. # This isn't strictly necessary, but does lead to more realistic looking flight. # Step 11: Constrain our speed. # If we're moving faster than we're allowed to move, constrain our velocity. if self.velocity.length() > self.maxVelocity: self.velocity.normalize() self.velocity *= self.maxVelocity # Step 12: Compute roll/pitch/yaw. # Compute our orientation after all this speed adjustment nonsense. # bah no need, we turn on a dime towards our velocity forwardVec = Vec3(1, 0, 0) heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0])) heading -= 90 self.suit.setH(heading) def getTargetVector(self): """Return a vector to my goal.""" targetPos = Point3(0, 0, 0) if self.goal == CTGG.ToonGoal: av = self.game.getAvatar(self.goalId) if av: targetPos = av.getPos() elif self.goal == CTGG.BarrelGoal: barrel = self.game.barrels[self.goalId] targetPos = barrel.getPos() elif self.goal == CTGG.RunAwayGoal: targetPos = CTGG.CogReturnPositions[self.goalId] targetPos.setZ(0) myPos = self.suit.getPos() diff = targetPos - myPos if diff.length() > 1.0: diff.normalize() diff *= 1.0 return diff def accumulate(self, accumulator, valueToAdd): """Return the magnitude of the accumulated vector.""" accumulator += valueToAdd return accumulator.length() def seeFriends(self): """Determines which flockmates a given flock boid can see.""" # clear the existing visibility list of any holdover from last round self.clearVisibleList() for cogIndex in self.game.cogInfo.keys(): if cogIndex == self.cogIndex: continue if self.sameGoal(cogIndex): dist = self.canISee(cogIndex) if dist != self.Infinity: self.addToVisibleList(cogIndex) if dist < self.distToNearestFlockmate: self.nearestFlockmate = cogIndex self.distToNearestFlockmate = dist return self.numFlockmatesSeen def clearVisibleList(self): """Clears the visibility list and associated fields.""" self.visibleFriendsList = [] self.numFlockmatesSeen = 0 self.nearestFlockmate = None self.distToNearestFlockmate = self.Infinity def addToVisibleList(self, cogIndex): """Add the cog to the visible list.""" # test: do we see enough buddies already? if self.numFlockmatesSeen < self.MaxFriendsVisible: #nope--we can add to this one to the list self.visibleFriendsList.append(cogIndex) self.numFlockmatesSeen += 1 if self.cogIndex == 0: #self.notify.debug('self.numFlockmatesSeen = %s' % self.numFlockmatesSeen) pass def canISee(self, cogIndex): """Return distance if I can see the other cog, infinity otherwise""" if self.cogIndex == cogIndex: # well we should never see ourself return self.Infinity cogThief = self.game.getCogThief(cogIndex) distance = self.suit.getDistance(cogThief.suit) if distance < self.perceptionRange: #self.notify.debug('%s can see %s' % (self.cogIndex, cogIndex)) return distance # fell through; can not see it return self.Infinity def sameGoal(self, cogIndex): """Return true if we have the same goal.""" cogThief = self.game.getCogThief(cogIndex) result = (cogThief.goalId == self.goalId) and (cogThief.goal == self.goal) return result def keepDistance(self): """Generates a vector for a flock boid to maintain his desired separation distance from the nearest flockmate he sees. """ ratio = self.distToNearestFlockmate / self.SeparationDistance nearestThief = self.game.getCogThief(self.nearestFlockmate) change = nearestThief.suit.getPos() - self.suit.getPos() if ratio < self.MinUrgency: ratio = self.MinUrgency if ratio > self.MaxUrgency: ratio = self.MaxUrgency # test: are we too close to our nearest flockmate? if self.distToNearestFlockmate < self.SeparationDistance: #self.notify.debug('%d is too close to %d' % (self.cogIndex, self.nearestFlockmate)) # too close...move away from our neighbor change.normalize() change *= -(1 - ratio ) # the close we are the more we are pushed away elif self.distToNearestFlockmate > self.SeparationDistance: # too far away move towards our neighbor change.normalize() change *= ratio else: # in the UNLIKELY event we're exactly the right distance away, do nothing change = Vec3(0, 0, 0) return change def showKaboom(self): """Show the kaboom graphic and sound.""" if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboom.reparentTo(render) self.kaboom.setPos(self.suit.getPos()) self.kaboom.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.kaboomSound, volume=0.5), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), startScale=Point3(1, 1, 1), blendType='easeOut'), Func(self.kaboom.hide), )) self.kaboomTrack.start() def showSplat(self): """Show the splat graphic and sound.""" if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.splat.reparentTo(render) self.splat.setPos(self.suit.getPos()) self.splat.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0), Sequence( Func(self.splat.showThrough), LerpScaleInterval(self.splat, duration=0.5, scale=1.75, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Func(self.splat.hide), )) self.kaboomTrack.start()
class DistributedPartyCatchActivity(DistributedPartyActivity, DistributedPartyCatchActivityBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCatchActivity') DropTaskName = 'dropSomething' DropObjectPlurals = {'apple': TTLocalizer.PartyCatchActivityApples, 'orange': TTLocalizer.PartyCatchActivityOranges, 'pear': TTLocalizer.PartyCatchActivityPears, 'coconut': TTLocalizer.PartyCatchActivityCoconuts, 'watermelon': TTLocalizer.PartyCatchActivityWatermelons, 'pineapple': TTLocalizer.PartyCatchActivityPineapples, 'anvil': TTLocalizer.PartyCatchActivityAnvils} class Generation: def __init__(self, generation, startTime, startNetworkTime, numPlayers): self.generation = generation self.startTime = startTime self.startNetworkTime = startNetworkTime self.numPlayers = numPlayers self.hasBeenScheduled = False self.droppedObjNames = [] self.dropSchedule = [] self.numItemsDropped = 0 self.droppedObjCaught = {} def __init__(self, cr): DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyCatch, PartyGlobals.ActivityTypes.HostInitiated, wantRewardGui=True) self.setUsesSmoothing() self.setUsesLookAround() self._sNumGen = SerialNumGen() def getTitle(self): return TTLocalizer.PartyCatchActivityTitle def getInstructions(self): return TTLocalizer.PartyCatchActivityInstructions % {'badThing': self.DropObjectPlurals['anvil']} def generate(self): DistributedPartyActivity.generate(self) self.notify.info('localAvatar doId: %s' % base.localAvatar.doId) self.notify.info('generate()') self._generateFrame = globalClock.getFrameCount() self._id2gen = {} self._orderedGenerations = [] self._orderedGenerationIndex = None rng = RandomNumGen(self.doId) self._generationSeedBase = rng.randrange(1000) self._lastDropTime = 0.0 return def getCurGeneration(self): if self._orderedGenerationIndex is None: return return self._orderedGenerations[self._orderedGenerationIndex] def _addGeneration(self, generation, startTime, startNetworkTime, numPlayers): self._id2gen[generation] = self.Generation(generation, startTime, startNetworkTime, numPlayers) i = 0 while 1: if i >= len(self._orderedGenerations): break gen = self._orderedGenerations[i] startNetT = self._id2gen[gen].startTime genId = self._id2gen[gen].generation if startNetT > startNetworkTime: break if startNetT == startNetworkTime and genId > generation: break i += 1 self._orderedGenerations = self._orderedGenerations[:i] + [generation] + self._orderedGenerations[i:] if self._orderedGenerationIndex is not None: if self._orderedGenerationIndex >= i: self._orderedGenerationIndex += 1 def _removeGeneration(self, generation): del self._id2gen[generation] i = self._orderedGenerations.index(generation) self._orderedGenerations = self._orderedGenerations[:i] + self._orderedGenerations[i + 1:] if self._orderedGenerationIndex is not None: if len(self._orderedGenerations): if self._orderedGenerationIndex >= i: self._orderedGenerationIndex -= 1 else: self._orderedGenerationIndex = None return def announceGenerate(self): self.notify.info('announceGenerate()') self.catchTreeZoneEvent = 'fence_floor' DistributedPartyActivity.announceGenerate(self) def load(self, loadModels = 1, arenaModel = 'partyCatchTree'): self.notify.info('load()') DistributedPartyCatchActivity.notify.debug('PartyCatch: load') self.activityFSM = CatchActivityFSM(self) if __dev__: for o in xrange(3): print {0: 'SPOTS PER PLAYER', 1: 'DROPS PER MINUTE PER SPOT DURING NORMAL DROP PERIOD', 2: 'DROPS PER MINUTE PER PLAYER DURING NORMAL DROP PERIOD'}[o] for i in xrange(1, self.FallRateCap_Players + 10): self.defineConstants(forceNumPlayers=i) numDropLocations = self.DropRows * self.DropColumns numDropsPerMin = 60.0 / self.DropPeriod if o == 0: spotsPerPlayer = numDropLocations / float(i) print '%2d PLAYERS: %s' % (i, spotsPerPlayer) elif o == 1: numDropsPerMinPerSpot = numDropsPerMin / numDropLocations print '%2d PLAYERS: %s' % (i, numDropsPerMinPerSpot) elif i > 0: numDropsPerMinPerPlayer = numDropsPerMin / i print '%2d PLAYERS: %s' % (i, numDropsPerMinPerPlayer) self.defineConstants() self.treesAndFence = loader.loadModel('phase_13/models/parties/%s' % arenaModel) self.treesAndFence.setScale(0.9) self.treesAndFence.find('**/fence_floor').setPos(0.0, 0.0, 0.1) self.treesAndFence.reparentTo(self.root) ground = self.treesAndFence.find('**/groundPlane') ground.setBin('ground', 1) DistributedPartyActivity.load(self) exitText = TextNode('PartyCatchExitText') exitText.setCardAsMargin(0.1, 0.1, 0.1, 0.1) exitText.setCardDecal(True) exitText.setCardColor(1.0, 1.0, 1.0, 0.0) exitText.setText(TTLocalizer.PartyCatchActivityExit) exitText.setTextColor(0.0, 8.0, 0.0, 0.9) exitText.setAlign(exitText.ACenter) exitText.setFont(ToontownGlobals.getBuildingNametagFont()) exitText.setShadowColor(0, 0, 0, 1) exitText.setBin('fixed') if TTLocalizer.BuildingNametagShadow: exitText.setShadow(*TTLocalizer.BuildingNametagShadow) exitTextLoc = self.treesAndFence.find('**/loc_exitSignText') exitTextNp = exitTextLoc.attachNewNode(exitText) exitTextNp.setDepthWrite(0) exitTextNp.setScale(4) exitTextNp.setZ(-.5) self.sign.reparentTo(self.treesAndFence.find('**/loc_eventSign')) self.sign.wrtReparentTo(self.root) self.avatarNodePath = NodePath('PartyCatchAvatarNodePath') self.avatarNodePath.reparentTo(self.root) self._avatarNodePathParentToken = 3 base.cr.parentMgr.registerParent(self._avatarNodePathParentToken, self.avatarNodePath) self.toonSDs = {} self.dropShadow = loader.loadModelOnce('phase_3/models/props/drop_shadow') self.dropObjModels = {} if loadModels: self.__loadDropModels() self.sndGoodCatch = base.loadSfx('phase_4/audio/sfx/SZ_DD_treasure.ogg') self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndAnvilLand = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg') self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg') self.__textGen = TextNode('partyCatchActivity') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.activityFSM.request('Idle') def __loadDropModels(self): for objType in PartyGlobals.DropObjectTypes: model = loader.loadModel(objType.modelPath) self.dropObjModels[objType.name] = model modelScales = {'apple': 0.7, 'orange': 0.7, 'pear': 0.5, 'coconut': 0.7, 'watermelon': 0.6, 'pineapple': 0.45} if modelScales.has_key(objType.name): model.setScale(modelScales[objType.name]) if objType == PartyGlobals.Name2DropObjectType['pear']: model.setZ(-.6) if objType == PartyGlobals.Name2DropObjectType['coconut']: model.setP(180) if objType == PartyGlobals.Name2DropObjectType['watermelon']: model.setH(135) model.setZ(-.5) if objType == PartyGlobals.Name2DropObjectType['pineapple']: model.setZ(-1.7) if objType == PartyGlobals.Name2DropObjectType['anvil']: model.setZ(-self.ObjRadius) model.flattenStrong() def unload(self): DistributedPartyCatchActivity.notify.debug('unload') self.finishAllDropIntervals() self.destroyOrthoWalk() DistributedPartyActivity.unload(self) self.stopDropTask() del self.activityFSM del self.__textGen for avId in self.toonSDs.keys(): if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.unload() del self.toonSDs self.treesAndFence.removeNode() del self.treesAndFence self.dropShadow.removeNode() del self.dropShadow base.cr.parentMgr.unregisterParent(self._avatarNodePathParentToken) for model in self.dropObjModels.values(): model.removeNode() del self.dropObjModels del self.sndGoodCatch del self.sndOof del self.sndAnvilLand del self.sndPerfect def setStartTimestamp(self, timestamp32): self.notify.info('setStartTimestamp(%s)' % (timestamp32,)) self._startTimestamp = globalClockDelta.networkToLocalTime(timestamp32, bits=32) def getCurrentCatchActivityTime(self): return globalClock.getFrameTime() - self._startTimestamp def getObjModel(self, objName): return self.dropObjModels[objName].copyTo(hidden) def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) base.cr.playGame.getPlace().fsm.request('walk') def handleToonJoined(self, toonId): if not self.toonSDs.has_key(toonId): toonSD = PartyCatchActivityToonSD(toonId, self) self.toonSDs[toonId] = toonSD toonSD.load() self.notify.debug('handleToonJoined : currentState = %s' % self.activityFSM.state) self.cr.doId2do[toonId].useLOD(500) if self.activityFSM.state == 'Active': if self.toonSDs.has_key(toonId): self.toonSDs[toonId].enter() if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(self._avatarNodePathParentToken) self.putLocalAvatarInActivity() if self.toonSDs.has_key(toonId): self.toonSDs[toonId].fsm.request('rules') def handleToonExited(self, toonId): self.notify.debug('handleToonExited( toonId=%s )' % toonId) if self.cr.doId2do.has_key(toonId): self.cr.doId2do[toonId].resetLOD() if self.toonSDs.has_key(toonId): self.toonSDs[toonId].fsm.request('notPlaying') self.toonSDs[toonId].exit() self.toonSDs[toonId].unload() del self.toonSDs[toonId] if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(ToontownGlobals.SPRender) def takeLocalAvatarOutOfActivity(self): self.notify.debug('localToon has left the circle') camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) DistributedSmoothNode.activateSmoothing(1, 0) def _enableCollisions(self): DistributedPartyActivity._enableCollisions(self) self._enteredTree = False self.accept('enter' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('again' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('exit' + self.catchTreeZoneEvent, self._toonExitedTree) self.accept(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT, self._handleCannonLanded) def _disableCollisions(self): self.ignore(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT) self.ignore('enter' + self.catchTreeZoneEvent) self.ignore('again' + self.catchTreeZoneEvent) self.ignore('exit' + self.catchTreeZoneEvent) DistributedPartyActivity._disableCollisions(self) def _handleCannonLanded(self): x = base.localAvatar.getX() y = base.localAvatar.getY() if x > self.x - self.StageHalfWidth and x < self.x + self.StageHalfWidth and y > self.y - self.StageHalfHeight and y < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def _toonMayHaveEnteredTree(self, collEntry): if self._enteredTree: return if base.localAvatar.controlManager.currentControls.getIsAirborne(): return self._toonEnteredTree(collEntry) def _toonEnteredTree(self, collEntry): self.notify.debug('_toonEnteredTree : avid = %s' % base.localAvatar.doId) self.notify.debug('_toonEnteredTree : currentState = %s' % self.activityFSM.state) if self.isLocalToonInActivity(): return if self.activityFSM.state == 'Active': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() elif self.activityFSM.state == 'Idle': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() self._enteredTree = True def _toonExitedTree(self, collEntry): self.notify.debug('_toonExitedTree : avid = %s' % base.localAvatar.doId) self._enteredTree = False if hasattr(base.cr.playGame.getPlace(), 'fsm') and self.activityFSM.state == 'Active' and self.isLocalToonInActivity(): if self.toonSDs.has_key(base.localAvatar.doId): self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') self.d_toonExitDemand() def setToonsPlaying(self, toonIds): self.notify.info('setToonsPlaying(%s)' % (toonIds,)) DistributedPartyActivity.setToonsPlaying(self, toonIds) if self.isLocalToonInActivity() and base.localAvatar.doId not in toonIds: if self.toonSDs.has_key(base.localAvatar.doId): self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def getNumPlayers(self): return len(self.toonIds) def defineConstants(self, forceNumPlayers = None): DistributedPartyCatchActivity.notify.debug('defineConstants') self.ShowObjSpheres = 0 self.ShowToonSpheres = 0 self.useGravity = True self.trickShadows = True if forceNumPlayers is None: numPlayers = self.getNumPlayers() else: numPlayers = forceNumPlayers self.calcDifficultyConstants(numPlayers) DistributedPartyCatchActivity.notify.debug('ToonSpeed: %s' % self.ToonSpeed) DistributedPartyCatchActivity.notify.debug('total drops: %s' % self.totalDrops) DistributedPartyCatchActivity.notify.debug('numFruits: %s' % self.numFruits) DistributedPartyCatchActivity.notify.debug('numAnvils: %s' % self.numAnvils) self.ObjRadius = 1.0 dropRegionTable = PartyRegionDropPlacer.getDropRegionTable(numPlayers) self.DropRows, self.DropColumns = len(dropRegionTable), len(dropRegionTable[0]) for objType in PartyGlobals.DropObjectTypes: DistributedPartyCatchActivity.notify.debug('*** Object Type: %s' % objType.name) objType.onscreenDuration = objType.onscreenDurMult * self.BaselineOnscreenDropDuration DistributedPartyCatchActivity.notify.debug('onscreenDuration=%s' % objType.onscreenDuration) v_0 = 0.0 t = objType.onscreenDuration x_0 = self.MinOffscreenHeight x = 0.0 g = 2.0 * (x - x_0 - v_0 * t) / (t * t) DistributedPartyCatchActivity.notify.debug('gravity=%s' % g) objType.trajectory = Trajectory(0, Vec3(0, 0, x_0), Vec3(0, 0, v_0), gravMult=abs(g / Trajectory.gravity)) objType.fallDuration = objType.onscreenDuration + self.OffscreenTime return def grid2world(self, column, row): x = column / float(self.DropColumns - 1) y = row / float(self.DropRows - 1) x = x * 2.0 - 1.0 y = y * 2.0 - 1.0 x *= self.StageHalfWidth y *= self.StageHalfHeight return (x, y) def showPosts(self): self.hidePosts() self.posts = [Toon.Toon(), Toon.Toon(), Toon.Toon(), Toon.Toon()] for i in xrange(len(self.posts)): tree = self.posts[i] tree.reparentTo(render) x = self.StageHalfWidth y = self.StageHalfHeight if i > 1: x = -x if i % 2: y = -y tree.setPos(x + self.x, y + self.y, 0) def hidePosts(self): if hasattr(self, 'posts'): for tree in self.posts: tree.removeNode() del self.posts def showDropGrid(self): self.hideDropGrid() self.dropMarkers = [] for row in xrange(self.DropRows): self.dropMarkers.append([]) rowList = self.dropMarkers[row] for column in xrange(self.DropColumns): toon = Toon.Toon() toon.setDNA(base.localAvatar.getStyle()) toon.reparentTo(self.root) toon.setScale(1.0 / 3) x, y = self.grid2world(column, row) toon.setPos(x, y, 0) rowList.append(toon) def hideDropGrid(self): if hasattr(self, 'dropMarkers'): for row in self.dropMarkers: for marker in row: marker.removeNode() del self.dropMarkers def handleToonDisabled(self, avId): DistributedPartyCatchActivity.notify.debug('handleToonDisabled') DistributedPartyCatchActivity.notify.debug('avatar ' + str(avId) + ' disabled') if self.toonSDs.has_key(avId): self.toonSDs[avId].exit(unexpectedExit=True) del self.toonSDs[avId] def turnOffSmoothingOnGuests(self): pass def setState(self, newState, timestamp): self.notify.info('setState(%s, %s)' % (newState, timestamp)) DistributedPartyCatchActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) if newState == 'Active': if base.localAvatar.doId != self.party.partyInfo.hostId: if globalClock.getFrameCount() > self._generateFrame: if base.localAvatar.getX() > self.x - self.StageHalfWidth and base.localAvatar.getX() < self.x + self.StageHalfWidth and base.localAvatar.getY() > self.y - self.StageHalfHeight and base.localAvatar.getY() < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def putLocalAvatarInActivity(self): if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'): base.cr.playGame.getPlace().fsm.request('activity', [False]) else: self.notify.info("Avoided crash: toontown.parties.DistributedPartyCatchActivity:632, toontown.parties.DistributedPartyCatchActivity:1198, toontown.parties.activityFSMMixins:49, direct.fsm.FSM:423, AttributeError: 'NoneType' object has no attribute 'fsm'") base.localAvatar.stopUpdateSmartCamera() camera.reparentTo(self.treesAndFence) camera.setPosHpr(0.0, -63.0, 30.0, 0.0, -20.0, 0.0) if not hasattr(self, 'ltLegsCollNode'): self.createCatchCollisions() def createCatchCollisions(self): radius = 0.7 handler = CollisionHandlerEvent() handler.setInPattern('ltCatch%in') self.ltLegsCollNode = CollisionNode('catchLegsCollNode') self.ltLegsCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltHeadCollNode = CollisionNode('catchHeadCollNode') self.ltHeadCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltLHandCollNode = CollisionNode('catchLHandCollNode') self.ltLHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltRHandCollNode = CollisionNode('catchRHandCollNode') self.ltRHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) legsCollNodepath = base.localAvatar.attachNewNode(self.ltLegsCollNode) legsCollNodepath.hide() head = base.localAvatar.getHeadParts().getPath(2) headCollNodepath = head.attachNewNode(self.ltHeadCollNode) headCollNodepath.hide() lHand = base.localAvatar.getLeftHands()[0] lHandCollNodepath = lHand.attachNewNode(self.ltLHandCollNode) lHandCollNodepath.hide() rHand = base.localAvatar.getRightHands()[0] rHandCollNodepath = rHand.attachNewNode(self.ltRHandCollNode) rHandCollNodepath.hide() base.localAvatar.cTrav.addCollider(legsCollNodepath, handler) base.localAvatar.cTrav.addCollider(headCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) if self.ShowToonSpheres: legsCollNodepath.show() headCollNodepath.show() lHandCollNodepath.show() rHandCollNodepath.show() self.ltLegsCollNode.addSolid(CollisionSphere(0, 0, radius, radius)) self.ltHeadCollNode.addSolid(CollisionSphere(0, 0, 0, radius)) self.ltLHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.ltRHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.toonCollNodes = [legsCollNodepath, headCollNodepath, lHandCollNodepath, rHandCollNodepath] def destroyCatchCollisions(self): if not hasattr(self, 'ltLegsCollNode'): return for collNode in self.toonCollNodes: while collNode.node().getNumSolids(): collNode.node().removeSolid(0) base.localAvatar.cTrav.removeCollider(collNode) del self.toonCollNodes del self.ltLegsCollNode del self.ltHeadCollNode del self.ltLHandCollNode del self.ltRHandCollNode def timerExpired(self): pass def __handleCatch(self, generation, objNum): DistributedPartyCatchActivity.notify.debug('catch: %s' % [generation, objNum]) if base.localAvatar.doId not in self.toonIds: return self.showCatch(base.localAvatar.doId, generation, objNum) objName = self._id2gen[generation].droppedObjNames[objNum] objTypeId = PartyGlobals.Name2DOTypeId[objName] self.sendUpdate('claimCatch', [generation, objNum, objTypeId]) self.finishDropInterval(generation, objNum) def showCatch(self, avId, generation, objNum): if not self.toonSDs.has_key(avId): return isLocal = avId == base.localAvatar.doId if generation not in self._id2gen: return if not self._id2gen[generation].hasBeenScheduled: return objName = self._id2gen[generation].droppedObjNames[objNum] objType = PartyGlobals.Name2DropObjectType[objName] if objType.good: if not self._id2gen[generation].droppedObjCaught.has_key(objNum): if isLocal: base.playSfx(self.sndGoodCatch) fruit = self.getObjModel(objName) toon = self.getAvatar(avId) rHand = toon.getRightHands()[1] self.toonSDs[avId].eatFruit(fruit, rHand) else: self.toonSDs[avId].fsm.request('fallForward') self._id2gen[generation].droppedObjCaught[objNum] = 1 def setObjectCaught(self, avId, generation, objNum): self.notify.info('setObjectCaught(%s, %s, %s)' % (avId, generation, objNum)) if self.activityFSM.state != 'Active': DistributedPartyCatchActivity.notify.warning('ignoring msg: object %s caught by %s' % (objNum, avId)) return isLocal = avId == base.localAvatar.doId if not isLocal: DistributedPartyCatchActivity.notify.debug('AI: avatar %s caught %s' % (avId, objNum)) self.finishDropInterval(generation, objNum) self.showCatch(avId, generation, objNum) self._scheduleGenerations() gen = self._id2gen[generation] if gen.hasBeenScheduled: objName = gen.droppedObjNames[objNum] if PartyGlobals.Name2DropObjectType[objName].good: if hasattr(self, 'fruitsCaught'): self.fruitsCaught += 1 def finishDropInterval(self, generation, objNum): if hasattr(self, 'dropIntervals'): if self.dropIntervals.has_key((generation, objNum)): self.dropIntervals[generation, objNum].finish() def finishAllDropIntervals(self): if hasattr(self, 'dropIntervals'): for dropInterval in self.dropIntervals.values(): dropInterval.finish() def setGenerations(self, generations): self.notify.info('setGenerations(%s)' % (generations,)) gen2t = {} gen2nt = {} gen2np = {} for id, timestamp32, numPlayers in generations: gen2t[id] = globalClockDelta.networkToLocalTime(timestamp32, bits=32) - self._startTimestamp gen2nt[id] = timestamp32 gen2np[id] = numPlayers ids = self._id2gen.keys() for id in ids: if id not in gen2t: self._removeGeneration(id) for id in gen2t: if id not in self._id2gen: self._addGeneration(id, gen2t[id], gen2nt[id], gen2np[id]) def scheduleDrops(self, genId = None): if genId is None: genId = self.getCurGeneration() gen = self._id2gen[genId] if gen.hasBeenScheduled: return fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration) fruitNames = ['apple', 'orange', 'pear', 'coconut', 'watermelon', 'pineapple'] fruitName = fruitNames[fruitIndex % len(fruitNames)] rng = RandomNumGen(genId + self._generationSeedBase) gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils rng.shuffle(gen.droppedObjNames) dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime) gen.numItemsDropped = 0 tIndex = gen.startTime % PartyGlobals.CatchActivityDuration tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration gen.numItemsDropped += dropPlacer.skipPercent(tPercent) while not dropPlacer.doneDropping(continuous=True): nextDrop = dropPlacer.getNextDrop() gen.dropSchedule.append(nextDrop) gen.hasBeenScheduled = True return def startDropTask(self): taskMgr.add(self.dropTask, self.DropTaskName) def stopDropTask(self): taskMgr.remove(self.DropTaskName) def _scheduleGenerations(self): curT = self.getCurrentCatchActivityTime() genIndex = self._orderedGenerationIndex newGenIndex = genIndex while genIndex is None or genIndex < len(self._orderedGenerations) - 1: if genIndex is None: nextGenIndex = 0 else: nextGenIndex = genIndex + 1 nextGenId = self._orderedGenerations[nextGenIndex] nextGen = self._id2gen[nextGenId] startT = nextGen.startTime if curT >= startT: newGenIndex = nextGenIndex if not nextGen.hasBeenScheduled: self.defineConstants(forceNumPlayers=nextGen.numPlayers) self.scheduleDrops(genId=self._orderedGenerations[nextGenIndex]) genIndex = nextGenIndex self._orderedGenerationIndex = newGenIndex return def dropTask(self, task): self._scheduleGenerations() curT = self.getCurrentCatchActivityTime() if self._orderedGenerationIndex is not None: i = self._orderedGenerationIndex genIndex = self._orderedGenerations[i] gen = self._id2gen[genIndex] while len(gen.dropSchedule) > 0 and gen.dropSchedule[0][0] < curT: drop = gen.dropSchedule[0] gen.dropSchedule = gen.dropSchedule[1:] dropTime, objName, dropCoords = drop objNum = gen.numItemsDropped x, y = self.grid2world(*dropCoords) dropIval = self.getDropIval(x, y, objName, genIndex, objNum) def cleanup(generation, objNum, self = self): del self.dropIntervals[generation, objNum] dropIval.append(Func(Functor(cleanup, genIndex, objNum))) self.dropIntervals[genIndex, objNum] = dropIval gen.numItemsDropped += 1 dropIval.start(curT - dropTime) self._lastDropTime = dropTime return Task.cont def getDropIval(self, x, y, dropObjName, generation, num): objType = PartyGlobals.Name2DropObjectType[dropObjName] id = (generation, num) dropNode = hidden.attachNewNode('catchDropNode%s' % (id,)) dropNode.setPos(x, y, 0) shadow = self.dropShadow.copyTo(dropNode) shadow.setZ(PartyGlobals.CatchDropShadowHeight) shadow.setColor(1, 1, 1, 1) object = self.getObjModel(dropObjName) object.reparentTo(hidden) if dropObjName in ['watermelon', 'anvil']: objH = object.getH() absDelta = {'watermelon': 12, 'anvil': 15}[dropObjName] delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta newH = objH + delta else: newH = self.randomNumGen.random() * 360.0 object.setH(newH) sphereName = 'FallObj%s' % (id,) radius = self.ObjRadius if objType.good: radius *= lerp(1.0, 1.3, 0.5) collSphere = CollisionSphere(0, 0, 0, radius) collSphere.setTangible(0) collNode = CollisionNode(sphereName) collNode.setCollideMask(PartyGlobals.CatchActivityBitmask) collNode.addSolid(collSphere) collNodePath = object.attachNewNode(collNode) collNodePath.hide() if self.ShowObjSpheres: collNodePath.show() catchEventName = 'ltCatch' + sphereName def eatCollEntry(forward, collEntry): forward() self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1]))) def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName): self.ignore(event) dropNode.removeNode() duration = objType.fallDuration onscreenDuration = objType.onscreenDuration targetShadowScale = 0.3 if self.trickShadows: intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration) shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0)) shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale)) else: shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0) targetShadowAlpha = 0.4 shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) if self.useGravity: def setObjPos(t, objType = objType, object = object): z = objType.trajectory.calcZ(t) object.setZ(z) setObjPos(0) dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration) else: startPos = Point3(0, 0, self.MinOffscreenHeight) object.setPos(startPos) dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,)) if objType == PartyGlobals.Name2DropObjectType['anvil']: ival.append(Func(self.playAnvil)) return ival def playAnvil(self): if base.localAvatar.doId in self.toonIds: base.playSfx(self.sndAnvilLand) def initOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('startOrthoWalk') def doCollisions(oldPos, newPos, self = self): x = bound(newPos[0], self.StageHalfWidth, -self.StageHalfWidth) y = bound(newPos[1], self.StageHalfHeight, -self.StageHalfHeight) newPos.setX(x) newPos.setY(y) return newPos orthoDrive = OrthoDrive(self.ToonSpeed, instantTurn=True) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True) def destroyOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('destroyOrthoWalk') if hasattr(self, 'orthoWalk'): self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk def startIdle(self): DistributedPartyCatchActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyCatchActivity.notify.debug('finishIdle') def startActive(self): DistributedPartyCatchActivity.notify.debug('startActive') for avId in self.toonIds: if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.enter() toonSD.fsm.request('normal') self.fruitsCaught = 0 self.dropIntervals = {} self.startDropTask() if base.localAvatar.doId in self.toonIds: self.putLocalAvatarInActivity() def finishActive(self): DistributedPartyCatchActivity.notify.debug('finishActive') self.stopDropTask() if hasattr(self, 'finishIval'): self.finishIval.pause() del self.finishIval if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() for ival in self.dropIntervals.values(): ival.finish() del self.dropIntervals def startConclusion(self): DistributedPartyCatchActivity.notify.debug('startConclusion') for avId in self.toonIds: if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.fsm.request('notPlaying') self.destroyCatchCollisions() if base.localAvatar.doId not in self.toonIds: return else: self.localToonExiting() if self.fruitsCaught >= self.numFruits: finishText = TTLocalizer.PartyCatchActivityFinishPerfect else: finishText = TTLocalizer.PartyCatchActivityFinish perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text = perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text = perfectText): text.removeNode() textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5)) soundTrack = SoundInterval(self.sndPerfect) self.finishIval = Parallel(textTrack, soundTrack) self.finishIval.start() def finishConclusion(self): DistributedPartyCatchActivity.notify.debug('finishConclusion') if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() base.cr.playGame.getPlace().fsm.request('walk') def showJellybeanReward(self, earnedAmount, jarAmount, message): if earnedAmount > 0: DistributedPartyActivity.showJellybeanReward(self, earnedAmount, jarAmount, message) else: base.cr.playGame.getPlace().fsm.request('walk')
class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIceWorld.DistributedIceWorld): notify = directNotify.newCategory("DistributedIceGame") MaxLocalForce = 100 MaxPhysicsForce = 25000 def __init__(self, cr): DistributedMinigame.DistributedMinigame.__init__(self, cr) DistributedIceWorld.DistributedIceWorld.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM( "DistributedIceGame", [ State.State("off", self.enterOff, self.exitOff, ["inputChoice"]), State.State( "inputChoice", self.enterInputChoice, self.exitInputChoice, ["waitServerChoices", "moveTires", "displayVotes", "cleanup"], ), State.State( "waitServerChoices", self.enterWaitServerChoices, self.exitWaitServerChoices, ["moveTires", "cleanup"], ), State.State("moveTires", self.enterMoveTires, self.exitMoveTires, ["synch", "cleanup"]), State.State("synch", self.enterSynch, self.exitSynch, ["inputChoice", "scoring", "cleanup"]), State.State("scoring", self.enterScoring, self.exitScoring, ["cleanup", "finalResults", "inputChoice"]), State.State("finalResults", self.enterFinalResults, self.exitFinalResults, ["cleanup"]), State.State("cleanup", self.enterCleanup, self.exitCleanup, []), ], "off", "cleanup", ) self.addChildGameFSM(self.gameFSM) self.cameraThreeQuarterView = (0, -22, 45, 0, -62.89, 0) self.tireDict = {} self.forceArrowDict = {} self.canDrive = False self.timer = None self.timerStartTime = None self.curForce = 0 self.curHeading = 0 self.headingMomentum = 0.0 self.forceMomentum = 0.0 self.allTireInputs = None self.curRound = 0 self.curMatch = 0 self.controlKeyWarningLabel = DirectLabel( text=TTLocalizer.IceGameControlKeyWarning, text_fg=VBase4(1, 0, 0, 1), relief=None, pos=(0.0, 0, 0), scale=0.15, ) self.controlKeyWarningLabel.hide() self.waitingMoveLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForPlayersToFinishMove, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075, ) self.waitingMoveLabel.hide() self.waitingSyncLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForAISync, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075, ) self.waitingSyncLabel.hide() self.infoLabel = DirectLabel(text="", text_fg=VBase4(0, 0, 0, 1), relief=None, pos=(0.0, 0, 0.7), scale=0.075) self.updateInfoLabel() self.lastForceArrowUpdateTime = 0 self.sendForceArrowUpdateAsap = False self.treasures = [] self.penalties = [] self.obstacles = [] self.controlKeyPressed = False self.controlKeyWarningIval = None return def delete(self): DistributedIceWorld.DistributedIceWorld.delete(self) DistributedMinigame.DistributedMinigame.delete(self) if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningLabel.destroy() del self.controlKeyWarningLabel self.waitingMoveLabel.destroy() del self.waitingMoveLabel self.waitingSyncLabel.destroy() del self.waitingSyncLabel self.infoLabel.destroy() del self.infoLabel for treasure in self.treasures: treasure.destroy() del self.treasures for penalty in self.penalties: penalty.destroy() del self.penalties for obstacle in self.obstacles: obstacle.removeNode() del self.obstacles del self.gameFSM return def announceGenerate(self): DistributedMinigame.DistributedMinigame.announceGenerate(self) DistributedIceWorld.DistributedIceWorld.announceGenerate(self) self.debugTaskName = self.uniqueName("debugTask") def getTitle(self): return TTLocalizer.IceGameTitle def getInstructions(self): szId = self.getSafezoneId() numPenalties = IceGameGlobals.NumPenalties[szId] result = TTLocalizer.IceGameInstructions if numPenalties == 0: result = TTLocalizer.IceGameInstructionsNoTnt return result def getMaxDuration(self): return 0 def load(self): self.notify.debug("load") DistributedMinigame.DistributedMinigame.load(self) self.music = base.loadMusic("phase_4/audio/bgm/MG_IceGame.ogg") self.gameBoard = loader.loadModel("phase_4/models/minigames/ice_game_icerink") background = loader.loadModel("phase_4/models/minigames/ice_game_2d") backgroundWide = loader.loadModel("phase_4/models/minigames/iceslide_ground") background.reparentTo(self.gameBoard) backgroundWide.reparentTo(self.gameBoard) backgroundWide.setPos(0, -0.3, -0.5) self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.setupSimulation() index = 0 for avId in self.avIdList: self.setupTire(avId, index) self.setupForceArrow(avId) index += 1 for index in xrange(len(self.avIdList), 4): self.setupTire(-index, index) self.setupForceArrow(-index) self.showForceArrows(realPlayersOnly=True) self.westWallModel = NodePath() if not self.westWallModel.isEmpty(): self.westWallModel.reparentTo(self.gameBoard) self.westWallModel.setPos(IceGameGlobals.MinWall[0], IceGameGlobals.MinWall[1], 0) self.westWallModel.setScale(4) self.eastWallModel = NodePath() if not self.eastWallModel.isEmpty(): self.eastWallModel.reparentTo(self.gameBoard) self.eastWallModel.setPos(IceGameGlobals.MaxWall[0], IceGameGlobals.MaxWall[1], 0) self.eastWallModel.setScale(4) self.eastWallModel.setH(180) self.arrowKeys = ArrowKeys.ArrowKeys() self.target = loader.loadModel("phase_3/models/misc/sphere") self.target.setScale(0.01) self.target.reparentTo(self.gameBoard) self.target.setPos(0, 0, 0) self.scoreCircle = loader.loadModel("phase_4/models/minigames/ice_game_score_circle") self.scoreCircle.setScale(0.01) self.scoreCircle.reparentTo(self.gameBoard) self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0) self.scoreCircle.setAlphaScale(0.5) self.scoreCircle.setTransparency(1) self.scoreCircle.hide() self.treasureModel = loader.loadModel("phase_4/models/minigames/ice_game_barrel") self.penaltyModel = loader.loadModel("phase_4/models/minigames/ice_game_tnt2") self.penaltyModel.setScale(0.75, 0.75, 0.7) szId = self.getSafezoneId() obstacles = IceGameGlobals.Obstacles[szId] index = 0 cubicObstacle = IceGameGlobals.ObstacleShapes[szId] for pos in obstacles: newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius) newObstacle = self.createObstacle(newPos, index, cubicObstacle) self.obstacles.append(newObstacle) index += 1 self.countSound = loader.loadSfx("phase_3.5/audio/sfx/tick_counter.ogg") self.treasureGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_vine_game_bananas.ogg") self.penaltyGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_cannon_fire_alt.ogg") self.tireSounds = [] for tireIndex in xrange(4): tireHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg") wallHit = loader.loadSfx("phase_4/audio/sfx/MG_maze_pickup.ogg") obstacleHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_2.ogg") self.tireSounds.append({"tireHit": tireHit, "wallHit": wallHit, "obstacleHit": obstacleHit}) self.arrowRotateSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_rotate.ogg") self.arrowUpSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.ogg") self.arrowDownSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.ogg") self.scoreCircleSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_scoring_1.ogg") def unload(self): self.notify.debug("unload") DistributedMinigame.DistributedMinigame.unload(self) del self.music self.gameBoard.removeNode() del self.gameBoard for forceArrow in self.forceArrowDict.values(): forceArrow.removeNode() del self.forceArrowDict self.scoreCircle.removeNode() del self.scoreCircle del self.countSound def onstage(self): self.notify.debug("onstage") DistributedMinigame.DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) self.__placeToon(self.localAvId) self.moveCameraToTop() self.scorePanels = [] base.playMusic(self.music, looping=1, volume=0.8) def offstage(self): self.notify.debug("offstage") self.music.stop() self.gameBoard.hide() self.infoLabel.hide() for avId in self.tireDict: self.tireDict[avId]["tireNodePath"].hide() for panel in self.scorePanels: panel.cleanup() del self.scorePanels for obstacle in self.obstacles: obstacle.hide() for treasure in self.treasures: treasure.nodePath.hide() for penalty in self.penalties: penalty.nodePath.hide() for avId in self.avIdList: av = self.getAvatar(avId) if av: av.dropShadow.show() av.resetLOD() taskMgr.remove(self.uniqueName("aimtask")) self.arrowKeys.destroy() del self.arrowKeys DistributedMinigame.DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug("handleDisabledAvatar") self.notify.debug("avatar " + str(avId) + " disabled") DistributedMinigame.DistributedMinigame.handleDisabledAvatar(self, avId) def setGameReady(self): if not self.hasLocalToon: return self.notify.debug("setGameReady") if DistributedMinigame.DistributedMinigame.setGameReady(self): return for index in xrange(self.numPlayers): avId = self.avIdList[index] toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self.__placeToon(avId) toon.forwardSpeed = 0 toon.rotateSpeed = False toon.dropShadow.hide() toon.setAnimState("Sit") if avId in self.tireDict: tireNp = self.tireDict[avId]["tireNodePath"] toon.reparentTo(tireNp) toon.setY(1.0) toon.setZ(-3) toon.startLookAround() def setGameStart(self, timestamp): if not self.hasLocalToon: return self.notify.debug("setGameStart") DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp) for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() self.scores = [0] * self.numPlayers spacing = 0.4 for i in xrange(self.numPlayers): avId = self.avIdList[i] avName = self.getAvatarName(avId) scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(avId, avName) scorePanel.setScale(0.9) scorePanel.setPos(-0.583 - spacing * (self.numPlayers - 1 - i), 0.0, -0.15) scorePanel.reparentTo(base.a2dTopRight) scorePanel.makeTransparent(0.75) self.scorePanels.append(scorePanel) self.arrowKeys.setPressHandlers( [ self.__upArrowPressed, self.__downArrowPressed, self.__leftArrowPressed, self.__rightArrowPressed, self.__controlPressed, ] ) def isInPlayState(self): if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == "play": return False return True def enterOff(self): self.notify.debug("enterOff") def exitOff(self): pass def enterInputChoice(self): self.notify.debug("enterInputChoice") self.forceLocalToonToTire() self.controlKeyPressed = False if self.curRound == 0: self.setupStartOfMatch() else: self.notify.debug("self.curRound = %s" % self.curRound) self.timer = ToontownTimer.ToontownTimer() self.timer.hide() if self.timerStartTime != None: self.startTimer() self.showForceArrows(realPlayersOnly=True) self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0) self.localForceArrow().reparentTo(self.localTireNp()) self.localForceArrow().setY(IceGameGlobals.TireRadius) self.localTireNp().headsUp(self.target) self.notify.debug("self.localForceArrow() heading = %s" % self.localForceArrow().getH()) self.curHeading = self.localTireNp().getH() self.curForce = 25 self.updateLocalForceArrow() for avId in self.forceArrowDict: forceArrow = self.forceArrowDict[avId] forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0) tireNp = self.tireDict[avId]["tireNodePath"] forceArrow.reparentTo(tireNp) forceArrow.setY(IceGameGlobals.TireRadius) tireNp.headsUp(self.target) self.updateForceArrow(avId, tireNp.getH(), 25) taskMgr.add(self.__aimTask, self.uniqueName("aimtask")) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() self.sendForceArrowUpdateAsap = False return def exitInputChoice(self): if not self.controlKeyPressed: if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningIval = Sequence( Func(self.controlKeyWarningLabel.show), self.controlKeyWarningLabel.colorScaleInterval( 10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1) ), Func(self.controlKeyWarningLabel.hide), ) self.controlKeyWarningIval.start() if self.timer != None: self.timer.destroy() self.timer = None self.timerStartTime = None self.hideForceArrows() self.arrowRotateSound.stop() self.arrowUpSound.stop() self.arrowDownSound.stop() taskMgr.remove(self.uniqueName("aimtask")) return def enterWaitServerChoices(self): self.waitingMoveLabel.show() self.showForceArrows(True) def exitWaitServerChoices(self): self.waitingMoveLabel.hide() self.hideForceArrows() def enterMoveTires(self): for key in self.tireDict: body = self.tireDict[key]["tireBody"] body.setAngularVel(0, 0, 0) body.setLinearVel(0, 0, 0) for index in xrange(len(self.allTireInputs)): input = self.allTireInputs[index] avId = self.avIdList[index] body = self.getTireBody(avId) degs = input[1] + 90 tireNp = self.getTireNp(avId) tireH = tireNp.getH() self.notify.debug("tireH = %s" % tireH) radAngle = deg2Rad(degs) foo = NodePath("foo") dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0) self.notify.debug("dirVector is now=%s" % dirVector) inputForce = input[0] inputForce /= self.MaxLocalForce inputForce *= self.MaxPhysicsForce force = dirVector * inputForce self.notify.debug("adding force %s to %d" % (force, avId)) body.addForce(force) self.enableAllTireBodies() self.totalPhysicsSteps = 0 self.startSim() taskMgr.add(self.__moveTiresTask, self.uniqueName("moveTiresTtask")) def exitMoveTires(self): self.forceLocalToonToTire() self.disableAllTireBodies() self.stopSim() self.notify.debug("total Physics steps = %d" % self.totalPhysicsSteps) taskMgr.remove(self.uniqueName("moveTiresTtask")) def enterSynch(self): self.waitingSyncLabel.show() def exitSynch(self): self.waitingSyncLabel.hide() def enterScoring(self): sortedByDistance = [] for avId in self.avIdList: np = self.getTireNp(avId) pos = np.getPos() pos.setZ(0) sortedByDistance.append((avId, pos.length())) def compareDistance(x, y): if x[1] - y[1] > 0: return 1 elif x[1] - y[1] < 0: return -1 else: return 0 sortedByDistance.sort(cmp=compareDistance) self.scoreMovie = Sequence() curScale = 0.01 curTime = 0 self.scoreCircle.setScale(0.01) self.scoreCircle.show() self.notify.debug("newScores = %s" % self.newScores) circleStartTime = 0 for index in xrange(len(sortedByDistance)): distance = sortedByDistance[index][1] avId = sortedByDistance[index][0] scorePanelIndex = self.avIdList.index(avId) time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec if time < 0: time = 0.01 scaleXY = distance + IceGameGlobals.TireRadius self.notify.debug("circleStartTime = %s" % circleStartTime) self.scoreMovie.append( Parallel( LerpScaleInterval(self.scoreCircle, time, Point3(scaleXY, scaleXY, 1.0)), SoundInterval(self.scoreCircleSound, duration=time, startTime=circleStartTime), ) ) circleStartTime += time startScore = self.scorePanels[scorePanelIndex].getScore() destScore = self.newScores[scorePanelIndex] self.notify.debug("for avId %d, startScore=%d, newScores=%d" % (avId, startScore, destScore)) def increaseScores(t, scorePanelIndex=scorePanelIndex, startScore=startScore, destScore=destScore): oldScore = self.scorePanels[scorePanelIndex].getScore() diff = destScore - startScore newScore = int(startScore + diff * t) if newScore > oldScore: base.playSfx(self.countSound) self.scorePanels[scorePanelIndex].setScore(newScore) self.scores[scorePanelIndex] = newScore duration = (destScore - startScore) * IceGameGlobals.ScoreCountUpRate tireNp = self.tireDict[avId]["tireNodePath"] self.scoreMovie.append( Parallel( LerpFunctionInterval(increaseScores, duration), Sequence( LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), ), ) ) curScale += distance self.scoreMovie.append(Func(self.sendUpdate, "reportScoringMovieDone", [])) self.scoreMovie.start() def exitScoring(self): self.scoreMovie.finish() self.scoreMovie = None self.scoreCircle.hide() return def enterFinalResults(self): lerpTrack = Parallel() lerpDur = 0.5 tY = 0.6 bY = -0.05 lX = -0.5 cX = 0 rX = 0.5 scorePanelLocs = ( ((cX, bY),), ((lX, bY), (rX, bY)), ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY), (lX, bY), (rX, bY)), ) scorePanelLocs = scorePanelLocs[self.numPlayers - 1] for i in xrange(self.numPlayers): panel = self.scorePanels[i] pos = scorePanelLocs[i] panel.wrtReparentTo(aspect2d) lerpTrack.append( Parallel( LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType="easeInOut"), LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType="easeInOut"), ) ) self.showScoreTrack = Parallel( lerpTrack, Sequence(Wait(IceGameGlobals.ShowScoresDuration), Func(self.gameOver)) ) self.showScoreTrack.start() def exitFinalResults(self): self.showScoreTrack.pause() del self.showScoreTrack def enterCleanup(self): self.notify.debug("enterCleanup") if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() def exitCleanup(self): pass def __placeToon(self, avId): toon = self.getAvatar(avId) if toon: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def setupTire(self, avId, index): tireNp, tireBody, tireOdeGeom = self.createTire(index) self.tireDict[avId] = {"tireNodePath": tireNp, "tireBody": tireBody, "tireOdeGeom": tireOdeGeom} if avId <= 0: tireBlocker = tireNp.find("**/tireblockermesh") if not tireBlocker.isEmpty(): tireBlocker.hide() if avId == self.localAvId: tireNp = self.tireDict[avId]["tireNodePath"] self.treasureSphereName = "treasureCollider" self.treasureCollSphere = CollisionSphere(0, 0, 0, IceGameGlobals.TireRadius) self.treasureCollSphere.setTangible(0) self.treasureCollNode = CollisionNode(self.treasureSphereName) self.treasureCollNode.setFromCollideMask(ToontownGlobals.PieBitmask) self.treasureCollNode.addSolid(self.treasureCollSphere) self.treasureCollNodePath = tireNp.attachNewNode(self.treasureCollNode) self.treasureHandler = CollisionHandlerEvent() self.treasureHandler.addInPattern("%fn-intoTreasure") base.cTrav.addCollider(self.treasureCollNodePath, self.treasureHandler) eventName = "%s-intoTreasure" % self.treasureCollNodePath.getName() self.notify.debug("eventName = %s" % eventName) self.accept(eventName, self.toonHitSomething) def setupForceArrow(self, avId): arrow = loader.loadModel("phase_4/models/minigames/ice_game_arrow") priority = 0 if avId < 0: priority = -avId else: priority = self.avIdList.index(avId) if avId == self.localAvId: priority = 10 self.forceArrowDict[avId] = arrow def hideForceArrows(self): for forceArrow in self.forceArrowDict.values(): forceArrow.hide() def showForceArrows(self, realPlayersOnly=True): for avId in self.forceArrowDict: if realPlayersOnly: if avId > 0: self.forceArrowDict[avId].show() else: self.forceArrowDict[avId].hide() else: self.forceArrowDict[avId].show() def localForceArrow(self): if self.localAvId in self.forceArrowDict: return self.forceArrowDict[self.localAvId] else: return None return None def setChoices(self, input0, input1, input2, input3): pass def startDebugTask(self): taskMgr.add(self.debugTask, self.debugTaskName) def stopDebugTask(self): taskMgr.remove(self.debugTaskName) def debugTask(self, task): if self.canDrive and self.tireDict.has_key(localAvatar.doId): dt = globalClock.getDt() forceMove = 25000 forceMoveDt = forceMove tireBody = self.tireDict[localAvatar.doId]["tireBody"] if self.arrowKeys.upPressed() and not tireBody.isEnabled(): x = 0 y = 1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.downPressed() and not tireBody.isEnabled(): x = 0 y = -1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.leftPressed() and not tireBody.isEnabled(): x = -1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.rightPressed() and not tireBody.isEnabled(): x = 1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) return task.cont def __upArrowPressed(self): pass def __downArrowPressed(self): pass def __leftArrowPressed(self): pass def __rightArrowPressed(self): pass def __controlPressed(self): if self.gameFSM.getCurrentState().getName() == "inputChoice": self.sendForceArrowUpdateAsap = True self.updateLocalForceArrow() self.controlKeyPressed = True self.sendUpdate("setAvatarChoice", [self.curForce, self.curHeading]) self.gameFSM.request("waitServerChoices") def startTimer(self): now = globalClock.getFrameTime() elapsed = now - self.timerStartTime self.timer.posInTopRightCorner() self.timer.setTime(IceGameGlobals.InputTimeout) self.timer.countdown(IceGameGlobals.InputTimeout - elapsed, self.handleChoiceTimeout) self.timer.show() def setTimerStartTime(self, timestamp): if not self.hasLocalToon: return self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp) if self.timer != None: self.startTimer() return def handleChoiceTimeout(self): self.sendUpdate("setAvatarChoice", [0, 0]) self.gameFSM.request("waitServerChoices") def localTireNp(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]["tireNodePath"] return ret def localTireBody(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]["tireBody"] return ret def getTireBody(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]["tireBody"] return ret def getTireNp(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]["tireNodePath"] return ret def updateForceArrow(self, avId, curHeading, curForce): forceArrow = self.forceArrowDict[avId] tireNp = self.tireDict[avId]["tireNodePath"] tireNp.setH(curHeading) tireBody = self.tireDict[avId]["tireBody"] tireBody.setQuaternion(tireNp.getQuat()) self.notify.debug("curHeading = %s" % curHeading) yScale = curForce / 100.0 yScale *= 1 headY = yScale * 15 xScale = (yScale - 1) / 2.0 + 1.0 shaft = forceArrow.find("**/arrow_shaft") head = forceArrow.find("**/arrow_head") shaft.setScale(xScale, yScale, 1) head.setPos(0, headY, 0) head.setScale(xScale, xScale, 1) def updateLocalForceArrow(self): avId = self.localAvId self.b_setForceArrowInfo(avId, self.curHeading, self.curForce) def __aimTask(self, task): if not hasattr(self, "arrowKeys"): return task.done dt = globalClock.getDt() headingMomentumChange = dt * 60.0 forceMomentumChange = dt * 160.0 arrowUpdate = False arrowRotating = False arrowUp = False arrowDown = False if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce += self.forceMomentum * dt arrowUpdate = True if oldForce < self.MaxLocalForce: arrowUp = True elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce -= self.forceMomentum * dt arrowUpdate = True if oldForce > 0.01: arrowDown = True else: self.forceMomentum = 0 if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading += self.headingMomentum * dt arrowUpdate = True arrowRotating = True elif self.arrowKeys.rightPressed() and not self.arrowKeys.leftPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading -= self.headingMomentum * dt arrowUpdate = True arrowRotating = True else: self.headingMomentum = 0 if arrowUpdate: self.normalizeHeadingAndForce() self.updateLocalForceArrow() if arrowRotating: if not self.arrowRotateSound.status() == self.arrowRotateSound.PLAYING: base.playSfx(self.arrowRotateSound, looping=True) else: self.arrowRotateSound.stop() if arrowUp: if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING: base.playSfx(self.arrowUpSound, looping=False) else: self.arrowUpSound.stop() if arrowDown: if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING: base.playSfx(self.arrowDownSound, looping=False) else: self.arrowDownSound.stop() return task.cont def normalizeHeadingAndForce(self): if self.curForce > self.MaxLocalForce: self.curForce = self.MaxLocalForce if self.curForce < 0.01: self.curForce = 0.01 def setTireInputs(self, tireInputs): if not self.hasLocalToon: return self.allTireInputs = tireInputs self.gameFSM.request("moveTires") def enableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]["tireBody"].enable() def disableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]["tireBody"].disable() def areAllTiresDisabled(self): for avId in self.tireDict.keys(): if self.tireDict[avId]["tireBody"].isEnabled(): return False return True def __moveTiresTask(self, task): if self.areAllTiresDisabled(): self.sendTirePositions() self.gameFSM.request("synch") return task.done return task.cont def sendTirePositions(self): tirePositions = [] for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) self.sendUpdate("endingPositions", [tirePositions]) def setFinalPositions(self, finalPos): if not self.hasLocalToon: return for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) def updateInfoLabel(self): self.infoLabel["text"] = TTLocalizer.IceGameInfo % { "curMatch": self.curMatch + 1, "numMatch": IceGameGlobals.NumMatches, "curRound": self.curRound + 1, "numRound": IceGameGlobals.NumRounds, } def setMatchAndRound(self, match, round): if not self.hasLocalToon: return self.curMatch = match self.curRound = round self.updateInfoLabel() def setScores(self, match, round, scores): if not self.hasLocalToon: return self.newMatch = match self.newRound = round self.newScores = scores def setNewState(self, state): if not self.hasLocalToon: return self.notify.debug("setNewState gameFSM=%s newState=%s" % (self.gameFSM, state)) self.gameFSM.request(state) def putAllTiresInStartingPositions(self): for index in xrange(len(self.avIdList)): avId = self.avIdList[index] np = self.tireDict[avId]["tireNodePath"] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]["tireBody"] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) for index in xrange(len(self.avIdList), 4): avId = -index np = self.tireDict[avId]["tireNodePath"] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]["tireBody"] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) def b_setForceArrowInfo(self, avId, force, heading): self.setForceArrowInfo(avId, force, heading) self.d_setForceArrowInfo(avId, force, heading) def d_setForceArrowInfo(self, avId, force, heading): sendIt = False curTime = self.getCurrentGameTime() if self.sendForceArrowUpdateAsap: sendIt = True elif curTime - self.lastForceArrowUpdateTime > 0.2: sendIt = True if sendIt: self.sendUpdate("setForceArrowInfo", [avId, force, heading]) self.sendForceArrowUpdateAsap = False self.lastForceArrowUpdateTime = self.getCurrentGameTime() def setForceArrowInfo(self, avId, force, heading): if not self.hasLocalToon: return self.updateForceArrow(avId, force, heading) def setupStartOfMatch(self): self.putAllTiresInStartingPositions() szId = self.getSafezoneId() self.numTreasures = IceGameGlobals.NumTreasures[szId] if self.treasures: for treasure in self.treasures: treasure.destroy() self.treasures = [] index = 0 treasureMargin = IceGameGlobals.TireRadius + 1.0 while len(self.treasures) < self.numTreasures: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug("yPos=%s" % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newTreasure = IceTreasure.IceTreasure(self.treasureModel, pos, index, self.doId, penalty=False) goodSpot = True for obstacle in self.obstacles: if newTreasure.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break if goodSpot: for treasure in self.treasures: if newTreasure.nodePath.getDistance(treasure.nodePath) < treasureMargin: goodSpot = False break if goodSpot: self.treasures.append(newTreasure) index += 1 else: newTreasure.destroy() self.numPenalties = IceGameGlobals.NumPenalties[szId] if self.penalties: for penalty in self.penalties: penalty.destroy() self.penalties = [] index = 0 while len(self.penalties) < self.numPenalties: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug("yPos=%s" % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newPenalty = IceTreasure.IceTreasure(self.penaltyModel, pos, index, self.doId, penalty=True) goodSpot = True for obstacle in self.obstacles: if newPenalty.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break if goodSpot: for treasure in self.treasures: if newPenalty.nodePath.getDistance(treasure.nodePath) < treasureMargin: goodSpot = False break if goodSpot: for penalty in self.penalties: if newPenalty.nodePath.getDistance(penalty.nodePath) < treasureMargin: goodSpot = False break if goodSpot: self.penalties.append(newPenalty) index += 1 else: newPenalty.destroy() def toonHitSomething(self, entry): self.notify.debug("---- treasure Enter ---- ") self.notify.debug("%s" % entry) name = entry.getIntoNodePath().getName() parts = name.split("-") if len(parts) < 3: self.notify.debug("collided with %s, but returning" % name) return if not int(parts[1]) == self.doId: self.notify.debug("collided with %s, but doId doesn't match" % name) return treasureNum = int(parts[2]) if "penalty" in parts[0]: self.__penaltyGrabbed(treasureNum) else: self.__treasureGrabbed(treasureNum) def __treasureGrabbed(self, treasureNum): self.treasures[treasureNum].showGrab() self.treasureGrabSound.play() self.sendUpdate("claimTreasure", [treasureNum]) def setTreasureGrabbed(self, avId, treasureNum): if not self.hasLocalToon: return self.notify.debug("treasure %s grabbed by %s" % (treasureNum, avId)) if avId != self.localAvId: self.treasures[treasureNum].showGrab() i = self.avIdList.index(avId) self.scores[i] += 1 self.scorePanels[i].setScore(self.scores[i]) def __penaltyGrabbed(self, penaltyNum): self.penalties[penaltyNum].showGrab() self.sendUpdate("claimPenalty", [penaltyNum]) def setPenaltyGrabbed(self, avId, penaltyNum): if not self.hasLocalToon: return self.notify.debug("penalty %s grabbed by %s" % (penaltyNum, avId)) if avId != self.localAvId: self.penalties[penaltyNum].showGrab() i = self.avIdList.index(avId) self.scores[i] -= 1 self.scorePanels[i].setScore(self.scores[i]) def postStep(self): DistributedIceWorld.DistributedIceWorld.postStep(self) if not self.colCount: return for count in xrange(self.colCount): c0, c1 = self.getOrderedContacts(count) if c1 in self.tireCollideIds: tireIndex = self.tireCollideIds.index(c1) if c0 in self.tireCollideIds: self.tireSounds[tireIndex]["tireHit"].play() elif c0 == self.wallCollideId: self.tireSounds[tireIndex]["wallHit"].play() elif c0 == self.obstacleCollideId: self.tireSounds[tireIndex]["obstacleHit"].play() def forceLocalToonToTire(self): toon = localAvatar if toon and self.localAvId in self.tireDict: tireNp = self.tireDict[self.localAvId]["tireNodePath"] toon.reparentTo(tireNp) toon.setPosHpr(0, 0, 0, 0, 0, 0) toon.setY(1.0) toon.setZ(-3)
class DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBanquetTable') rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble('water-power-speed', 15) waterPowerExponent = base.config.GetDouble('water-power-exponent', 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = 'BanquetTableUpdateKeyPressRateTask' YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.97 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedBanquetTable') self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None return def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() return def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in list(self.dinerStatusIndicators.values()): indicator.delete() self.dinerStatusIndicators = {} for diner in list(self.diners.values()): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName('pitcherSmooth') self.pitcherAdviceName = self.uniqueName('pitcherAdvice') self.posHprBroadcastName = self.uniqueName('pitcherBroadcast') self.waterPowerTaskName = self.uniqueName('updateWaterPower') self.triggerName = self.uniqueName('trigger') self.watchControlsName = self.uniqueName('watchControls') def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == 'F': self.demand('Off') elif state == 'N': self.demand('On') elif state == 'I': self.demand('Inactive') elif state == 'R': self.demand('Free') elif state == 'C': self.demand('Controlled', avId) elif state == 'L': self.demand('Flat', avId) else: self.notify.error('Invalid state from AI: %s' % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in range(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel('phase_12/models/bossbotHQ/BanquetTableChairs') tableLocator = self.boss.geom.find('**/TableLocator_%d' % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find('**/Geometry') self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx('phase_4/audio/sfx/AA_squirt_seltzer_miss.ogg') self.hitBossSfx = loader.loadSfx('phase_5/audio/sfx/SA_watercooler_spray_only.ogg') self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx('phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.ogg') self.pitcherMoveSfx = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') def setupDiners(self): for i in range(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept='c') diner.setDNA(diner.dna) diner.nametag.setNametag2d(None) diner.nametag.setNametag3d(None) if self.useNewAnimations: diner.loop('sit', fromFrame=i) else: diner.pose('landing', 0) locator = self.tableGroup.find('**/chair_%d' % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode('correctHeading') self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode('sitLocator') base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': sitLocator.setPos(0.5, 3.65, -3.75) else: sitLocator.setZ(-2.4) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath('serviceLoc-%d-%d' % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find('**/joint_head') newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in range(self.numDiners): chairCol = self.tableGroup.find('**/collision_chair_%d' % (i + 1)) colName = 'ChairCol-%d-%d' % (self.index, i) chairCol.setTag('chairIndex', str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept('enter' + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag('chairIndex')) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find('**/tray') if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel(SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval(food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc)), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0))) intervalName = 'serveFood-%d-%d' % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in range(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request('Eating', eatingDuration) diner = self.diners[chairIndex] intervalName = 'eating-%d-%d' % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self = self, diner = diner): if self.serviceLocs[chairIndex].getNumChildren() < 1: return foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.15, -0.7, -0.4)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 (foodModel.setPos(Point3(0.1, -0.25, -0.31)),) else: scaleAdj = 0.8 (foodModel.setPos(Point3(-0.25, -0.85, -0.34)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self = self, diner = diner): if diner.getRightHand().getNumChildren() < 1: return foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 else: scakeAdj = 0.8 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence(ActorInterval(diner, 'sit', duration=waitTime), ActorInterval(diner, 'sit-eat-in', startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, 'sit-eat-in', startFrame=6, endFrame=32), ActorInterval(diner, 'sit-eat-loop', duration=loopDuration, loop=1), ActorInterval(diner, 'sit-eat-out', startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, 'sit-eat-out', startFrame=12, endFrame=21)) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = 'eating-%d-%d' % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Hungry', self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop('sit-hungry-left') else: diner.loop('sit-hungry-right') def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Angry') diner = self.diners[chairIndex] diner.loop('sit-angry') def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Dead') diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence(Func(self.notify.debug, 'before actorinterval sit-lose'), ActorInterval(diner, 'sit-lose'), Func(self.notify.debug, 'before deathSuit.setHpr'), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, 'before diner.hide'), Func(diner.hide), Func(self.notify.debug, 'before deathSuit.reparentTo'), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, 'befor ActorInterval lose'), ActorInterval(deathSuit, 'lose', duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, 'before remove deathsuit'), Func(removeDeathSuit, diner, deathSuit, name='remove-death-suit-%d-%d' % (chairIndex, self.index)), Func(self.notify.debug, 'diner.stash'), Func(diner.stash)) spinningSound = base.loader.loadSfx('phase_3.5/audio/sfx/Cog_Death.ogg') deathSound = base.loader.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.ogg') deathSoundTrack = Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.2, node=deathSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=0.8, node=deathSuit), SoundInterval(deathSound, volume=0.32, node=deathSuit)) intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in list(self.diners.values()): if not diner.isHidden(): diner.loop('sit', fromFrame=startFrame) startFrame += 1 def cleanupIntervals(self): for interval in list(self.activeIntervals.values()): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish = 1): if name in self.activeIntervals: ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if name in self.activeIntervals: del self.activeIntervals[name] else: self.notify.debug('interval: %s already cleared' % name) def finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in range(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in range(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.3) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3))) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 return def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag('tableIndex')) if self.state == 'Free' and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in range(8): chair = self.tableGroup.find('**/chair_%d' % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches('**/ChairCol*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches('**/collision_chair*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find('**/collision_table') colName = 'TableCol-%d' % self.index tableCol.setTag('tableIndex', str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept('enter' + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel('phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle') lampNode = self.tableGroup.find('**/lamp_med_5') pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find('**/bottle_locator') pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode('pitcherNode') self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.nozzle = self.waterPitcherModel.find('**/nozzle_tip') self.handLocator = self.waterPitcherModel.find('**/hand_locator') self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug('grabTrack=%s' % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self.__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence(self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode)) if self.TugOfWarControls: self.__spawnUpdateKeyPressRateTask() self.accept('exitCrane', self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore('exitCrane') if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug('nextState=%s' % nextState) if nextState == 'Flat': place = base.cr.playGame.getPlace() self.notify.debug('%s' % place.fsm) if self.avId == localAvatar.doId: self.__disableControlInterface() else: if self.toon and not self.toon.isDisabled(): self.toon.loop('neutral') self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self.__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() return def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') def makeToonGrabInterval(self, toon): toon.pose('leverNeutral', 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence(Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, 'neutral'), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), Parallel(ProjectileInterval(toon, duration=0.9, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition), LerpHprInterval(toon, 0.9, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.9, Point3(1, 1, destZScale))))), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, 'leverNeutral')) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode('temp1') temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode('temp2') temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug('creating zap interval instead') grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1))) else: grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), ProjectileInterval(toon, duration=0.9, startPos=startPos, endPos=endPos)))) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus = None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitPitcher) self.accept('escape', self.__exitPitcher) self.accept(base.JUMP, self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) self.accept(base.MOVE_UP, self.__upArrowKeyPressed) self.accept(base.MOVE_DOWN, self.__downArrowKeyPressed) taskMgr.add(self.__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self.__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupPitcherAdvice() self.ignore('escape') self.ignore(base.JUMP) self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.ignore(base.MOVE_UP) self.ignore(base.MOVE_DOWN) self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self.__killUpdateKeyPressRateTask() self.keyTTL = [] self.__setMoveSound(None) return def __displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel(text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel(relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupPitcherAdvice() return def __exitPitcher(self): self.showExiting() self.d_requestFree(False) def __controlPressed(self): self.__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self.__endFireWater() elif self.state == 'Controlled': self.__beginFireWater() def __controlReleased(self): if self.TugOfWarControls: pass elif self.state == 'Controlled': self.__endFireWater() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('setPitcherPos', [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def __watchControls(self, task): if self.arrowHorz: self.__movePitcher(self.arrowHorz) else: self.__setMoveSound(None) return Task.cont def __movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug('rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f' % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h)) limitH = h self.waterPitcherNode.setH(limitH) if xd: self.__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack(self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale = 1.0, vertScale = 1.0, parent = render): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp('spray') sprayScale = hidden.attachNewNode('spray-parent') sprayRot = hidden.attachNewNode('spray-rotate') spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target = target, origin = origin, horizScale = horizScale, vertScale = vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return if self.avId != base.localAvatar.doId: return tag = self.hitObject.getNetTag('pieCode') pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate('waterHitBoss', [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.8), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' self.keyTTL = [] def __beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateWaterPower, self.waterPowerTaskName) return def __endFireWater(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.waterPowerTaskName) messenger.send('wakeup') self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode('pitcherColNode')) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() return def __updateWaterPower(self, task): if not self.powerBar: print('### no power bar!!!') return task.done newPower = self.__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) return task.cont def __getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate('firingWater', [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.8) dScaleUp = 0.1 dHold = 0.3 dScaleDown = 0.1 horizScale = 0.1 vertScale = 0.1 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt = render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug('enterFlat %d' % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState('neutral') toon.setAnimState('neutral') toon.loop('leverNeutral') def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency)) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def __upArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(0) def __downArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(1) def __pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def __spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater(0.1, self.__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __updateKeyPressRateTask(self, task): if self.state not in 'Controlled': return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.1 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug('diffPower=%.2f keyRate = %d, newPower=%.2f' % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) self.__spawnUpdateKeyPressRateTask() return Task.done def __setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
class DistributedPairingGame(DistributedMinigame): # define constants that you won't want to tweak here TOON_SPEED = 11 #8 MAX_FRAME_MOVE = 1 # maximum movement in one frame MAX_FACE_UP_CARDS = 2 notify = directNotify.newCategory("DistributedPairingGame") bonusGlowTime = 0.5 # how many seconds does bonus stay on a card EndGameTaskName = 'endPairingGame' xCardInc = 4 cardsPerRow = 8 cardsPerCol = 5 def __init__(self, cr): DistributedMinigame.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM( 'DistributedPairingGame', [ State.State('off', self.enterOff, self.exitOff, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, []), ], # Initial State 'off', # Final State 'cleanup', ) # it's important for the final state to do cleanup; # on disconnect, the ClassicFSM will be forced into the # final state. All states (except 'off') should # be prepared to transition to 'cleanup' at any time. # Add our game ClassicFSM to the framework ClassicFSM self.addChildGameFSM(self.gameFSM) self.cameraTopView = (17.6, 6.18756, 43.9956, 0, -89, 0) #self.cameraThreeQuarterView = (13.8234, -8.93352, 33.4497, 0, -62.89, 0) self.cameraThreeQuarterView = (14.0, -8.93352, 33.4497, 0, -62.89, 0) self.deckSeed = 0 self.faceUpList = [] # which cards are face up self.localFaceUpList = [] # which cards did this local toon turn up self.inList = [] # which cards is the local toon in self.inactiveList = [] # which cards are out of play self.points = 0 self.flips = 0 self.matches = 0 self.yCardInc = 4 self.startingPositions = [ (0, 0, 0, -45), ((self.cardsPerRow - 1) * self.xCardInc, (self.cardsPerCol - 1) * self.yCardInc, 0, 135), ((self.cardsPerRow - 1) * self.xCardInc, 0, 0, 45), (0, (self.cardsPerCol - 1) * self.yCardInc, 0, -135), ] self.stageMin = Point2(0, 0) self.stageMax = Point2((self.cardsPerRow - 1) * self.xCardInc, (self.cardsPerCol - 1) * self.yCardInc) self.gameDuration = PairingGameGlobals.EasiestGameDuration def moveCameraToTop(self): camera.reparentTo(render) #p = self.cameraTopView p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def getTitle(self): return TTLocalizer.PairingGameTitle def getInstructions(self): if self.numPlayers > 1: return TTLocalizer.PairingGameInstructionsMulti else: return TTLocalizer.PairingGameInstructions def getMaxDuration(self): # how many seconds can this minigame possibly last (within reason)? # this is for debugging only return 0 def load(self): # load resources and create objects here self.notify.debug("load") DistributedMinigame.load(self) self.gameDuration = PairingGameGlobals.calcGameDuration( self.getDifficulty()) #self.gameBoard = loader.loadModel("phase_4/models/minigames/toon_cannon_gameground") self.gameBoard = loader.loadModel( "phase_4/models/minigames/memory_room") self.gameBoard.setPosHpr(0.5, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) #self.gameBoard.find('**/tree_ring').removeNode() #self.debugAxis = loader.loadModel('models/misc/xyzAxis') #self.debugAxis.reparentTo(self.gameBoard) self.deck = PairingGameGlobals.createDeck(self.deckSeed, self.numPlayers) self.notify.debug('%s' % self.deck.cards) testCard = self.getDeckOrderIndex(self.cardsPerCol - 1, 0) if not testCard > -1: self.yCardInc *= 1.25 self.cards = [] for index in xrange(len(self.deck.cards)): cardValue = self.deck.cards[index] oneCard = PairingGameCard.PairingGameCard(cardValue) oneCard.load() xPos, yPos = self.getCardPos(index) oneCard.setPos(xPos, yPos, 0) oneCard.reparentTo(render) self.notify.debug('%s' % oneCard.getPos()) self.notify.debug('suit %s rank %s value %s' % (oneCard.suit, oneCard.rank, oneCard.value)) self.accept('entercardCollision-%d' % oneCard.value, self.enterCard) self.accept('exitcardCollision-%d' % oneCard.value, self.exitCard) oneCard.turnDown(doInterval=False) self.cards.append(oneCard) self.bonusTraversal = range(len(self.cards)) self.bonusGlow = render.attachNewNode('bonusGlow') sign = loader.loadModel("phase_4/models/minigames/garden_sign_memory") # remove the bits we don't want sign.find('**/sign1').removeNode() sign.find('**/sign2').removeNode() sign.find('**/collision').removeNode() #sign.setTransparency(1) #sign.setColorScale(1,1,0,0.5) sign.setPos(0, 0, 0.05) sign.reparentTo(self.bonusGlow) self.bonusGlow.setScale(2.5) self.pointsFrame = DirectFrame( #parent = self.gui, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(-0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGamePoints, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGpointsFrame, text_pos=(-1.94, -0.1, 0.0)) self.pointsLabel = DirectLabel( parent=self.pointsFrame, relief=None, text='0', text_fg=VBase4(0, 0.5, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15), ) self.flipsFrame = DirectFrame( #parent = self.gui, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=GlobalDialogColor, geom_scale=(4, 1, 1), pos=(0.33, 0, 0.9), scale=0.1, text=TTLocalizer.PairingGameFlips, text_align=TextNode.ALeft, text_scale=TTLocalizer.DPGflipsFrame, text_pos=(-1.94, -0.1, 0.0)) self.flipsLabel = DirectLabel( parent=self.flipsFrame, relief=None, text='0', text_fg=VBase4(0, 1.0, 0, 1), text_align=TextNode.ARight, text_scale=0.7, pos=(1.82, 0, -0.15), ) # this will be used to generate textnodes self.__textGen = TextNode("ringGame") self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.sndPerfect = base.loadSfx( "phase_4/audio/sfx/MG_pairing_all_matched.mp3") self.calcBonusTraversal() self.music = base.loadMusic("phase_4/audio/bgm/MG_Pairing.mid") self.matchSfx = base.loadSfx("phase_4/audio/sfx/MG_pairing_match.mp3") self.matchWithBonusSfx = base.loadSfx( "phase_4/audio/sfx/MG_pairing_match_bonus_both.mp3") self.signalSfx = [] for i in range(4): self.signalSfx.append( base.loadSfx( "phase_4/audio/sfx/MG_pairing_jumping_signal.mp3")) self.bonusMovesSfx = base.loadSfx( "phase_4/audio/sfx/MG_pairing_bonus_moves.mp3") # WARNING DEBUG only, remove or else it will leak # base.minigame = self def unload(self): self.notify.debug("unload") DistributedMinigame.unload(self) # unload resources and delete objects from load() here # remove our game ClassicFSM from the framework ClassicFSM self.removeChildGameFSM(self.gameFSM) del self.gameFSM self.gameBoard.removeNode() del self.gameBoard for card in self.cards: card.unload() del card self.cards = [] self.pointsFrame.removeNode() del self.pointsFrame self.flipsFrame.removeNode() del self.flipsFrame del self.__textGen del self.sndPerfect self.bonusGlow.removeNode() del self.bonusGlow del self.music del self.matchSfx del self.matchWithBonusSfx for i in range(4): del self.signalSfx[0] self.signalSfx = [] del self.bonusMovesSfx def onstage(self): self.notify.debug("onstage") DistributedMinigame.onstage(self) # start up the minigame; parent things to render, start playing # music... # at this point we cannot yet show the remote players' toons self.gameBoard.reparentTo(render) for card in self.cards: card.reparentTo(render) lt = base.localAvatar lt.reparentTo(render) lt.hideName() self.__placeToon(self.localAvId) lt.setAnimState('Happy', 1.0) lt.setSpeed(0, 0) self.moveCameraToTop() def offstage(self): self.notify.debug("offstage") # stop the minigame; parent things to hidden, stop the # music... self.gameBoard.hide() for card in self.cards: card.hide() # the base class parents the toons to hidden, so consider # calling it last DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): """This will be called if an avatar exits unexpectedly""" self.notify.debug("handleDisabledAvatar") self.notify.debug("avatar " + str(avId) + " disabled") # clean up any references to the disabled avatar before he disappears # then call the base class DistributedMinigame.handleDisabledAvatar(self, avId) def setGameReady(self): if not self.hasLocalToon: return self.notify.debug("setGameReady") if DistributedMinigame.setGameReady(self): return # all of the remote toons have joined the game; # it's safe to show them now. for index in xrange(self.numPlayers): avId = self.avIdList[index] # Find the actual avatar in the cr toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self.__placeToon(avId) toon.setAnimState('Happy', 1.0) # Start the smoothing task. toon.startSmooth() toon.startLookAround() def setGameStart(self, timestamp): if not self.hasLocalToon: return self.notify.debug("setGameStart") # base class will cause gameFSM to enter initial state DistributedMinigame.setGameStart(self, timestamp) # all players have finished reading the rules, # and are ready to start playing. # make the remote toons stop looking around for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() # transition to the appropriate state self.gameFSM.request("play") # these are enter and exit functions for the game's # fsm (finite state machine) def isInPlayState(self): """Return true if we are in the play state.""" if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == 'play': return False return True def enterOff(self): self.notify.debug("enterOff") def exitOff(self): pass def enterPlay(self): self.notify.debug("enterPlay") # Start music base.playMusic(self.music, looping=1, volume=0.9) orthoDrive = OrthoDrive( self.TOON_SPEED, maxFrameMove=self.MAX_FRAME_MOVE, customCollisionCallback=self. __doPairingGameCollisions # self.__doMazeCollisions, ) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=not self.isSinglePlayer()) self.orthoWalk.start() # listen for key presses # We used to use the insert key for tossing pies. # Nowadays we use the delete key instead, for better # consistency with Macs (which lack an insert key). self.accept('insert', self.__flipKeyPressed) self.accept('delete', self.__flipKeyPressed) self.accept('time-control', self.__beginSignal) self.accept('time-control-up', self.__endSignal) self.bonusGlowIndex = 0 self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex] self.startBonusTask() self.timer = ToontownTimer.ToontownTimer() self.timer.posInTopRightCorner() self.timer.setTime(self.gameDuration) self.timer.countdown(self.gameDuration, self.timerExpired) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() # when the game is done, call gameOver() # self.gameOver() def exitPlay(self): # Stop music self.music.stop() self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk self.bonusGlow.hide() self.stopBonusTask() self.timer.stop() self.timer.destroy() del self.timer self.ignoreAll() if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() if hasattr(self, 'perfectIval'): self.perfectIval.pause() del self.perfectIval taskMgr.remove(self.EndGameTaskName) taskMgr.remove('pairGameContinueSignal') def enterCleanup(self): self.notify.debug("enterCleanup") def exitCleanup(self): pass def __placeToon(self, avId): """ places a toon in its starting position """ toon = self.getAvatar(avId) if self.numPlayers == 1: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) else: posIndex = self.avIdList.index(avId) pos = self.startingPositions[posIndex] toon.setPos(pos[0], pos[1], pos[2]) toon.setHpr(pos[3], 0, 0) def __doPairingGameCollisions(self, oldPos, newPos): x = bound(newPos[0], self.stageMin[0], self.stageMax[0]) y = bound(newPos[1], self.stageMin[1], self.stageMax[1]) newPos.setX(x) newPos.setY(y) if self.inList: newPos.setZ(0.15) else: newPos.setZ(0.0) #if we're moving also cancel out the signaling task if not oldPos == newPos: taskMgr.remove('pairGameContinueSignal') return newPos def getDeckOrderFromValue(self, value): for index in xrange(len(self.cards)): if self.cards[index].value == value: return index return -1 def getDeckOrderFromPairingGameCard(self, into): try: index = self.cards.index(into) except ValueError: index = -1 return index def enterCard(self, colEntry): intoName = colEntry.getIntoNodePath().getName() parts = intoName.split('-') value = int(parts[1]) self.notify.debug('entered cardValue %d' % value) deckOrder = self.getDeckOrderFromValue(value) if not deckOrder in self.inList: self.inList.append(deckOrder) def exitCard(self, colEntry): intoName = colEntry.getIntoNodePath().getName() parts = intoName.split('-') value = int(parts[1]) self.notify.debug('exited cardValue %d' % value) deckOrder = self.getDeckOrderFromValue(value) if deckOrder in self.inList: self.inList.remove(deckOrder) def handleMatch(self, cardA, cardB, withBonus): self.notify.debug('we got a match %d %d' % (cardA, cardB)) self.matches += 1 if cardA in self.faceUpList: self.faceUpList.remove(cardA) if cardB in self.faceUpList: self.faceUpList.remove(cardB) self.inactiveList.append(cardA) self.inactiveList.append(cardB) matchIval = Parallel() for card in [cardA, cardB]: self.cards[card].setTransparency(1) cardSeq = Sequence( LerpColorScaleInterval(self.cards[card], duration=1, colorScale=Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.cards[card].hide)) matchIval.append(cardSeq) if withBonus: matchIval.append( SoundInterval(self.matchWithBonusSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240)) else: matchIval.append( SoundInterval(self.matchSfx, node=self.cards[card], listenerNode=base.localAvatar, cutOff=240)) matchIval.start() # report we're done if all cards are matched if len(self.inactiveList) == len(self.cards): self.sendUpdate('reportDone') def turnUpCard(self, deckOrder): self.cards[deckOrder].turnUp() self.faceUpList.append(deckOrder) def turnDownCard(self, deckOrder): self.cards[deckOrder].turnDown() if deckOrder in self.faceUpList: self.faceUpList.remove(deckOrder) def __flipKeyPressed(self): if self.inList: shortestDistance = 10000 cardToFlip = -1 for deckOrder in self.inList: dist = base.localAvatar.getDistance(self.cards[deckOrder]) if dist < shortestDistance: shortestDistance = dist cardToFlip = deckOrder deckOrderIndex = cardToFlip # self.inList[-1] card = self.cards[deckOrderIndex] if card.isFaceDown() and not deckOrderIndex in self.inactiveList: #self.turnUpCard(deckOrderIndex) self.sendUpdate('openCardRequest', [deckOrderIndex, self.bonusGlowCard]) elif card.isFaceUp() and deckOrderIndex in self.faceUpList: pass #make sure this is the latest card #self.faceUpList.remove(deckOrderIndex) #self.faceUpList.append(deckOrderIndex) def moveBonusGlowTask(self, task): """ move the bonus glow based on the game time to keep 2 clients in sync """ if len(self.cards) == 0: return Task.done curT = self.getCurrentGameTime() intTime = int(curT / self.bonusGlowTime) newIndex = intTime % len(self.cards) if not newIndex == self.bonusGlowIndex: self.bonusGlowIndex = newIndex self.bonusGlowCard = self.bonusTraversal[self.bonusGlowIndex] card = self.cards[self.bonusGlowCard] self.bonusGlow.setPos(card.getPos()) base.playSfx(self.bonusMovesSfx, node=card, volume=0.25) return Task.cont def timerExpired(self): self.sendUpdate('reportDone') pass def setDeckSeed(self, deckSeed): if not self.hasLocalToon: return self.deckSeed = deckSeed def updateFlipText(self): self.flipsLabel['text'] = str(self.flips) lowFlipModifier = PairingGameGlobals.calcLowFlipModifier( self.matches, self.flips) red = 1.0 - lowFlipModifier green = lowFlipModifier self.flipsLabel['text_fg'] = Vec4(red, green, 0, 1.0) def openCardResult(self, cardToTurnUp, avId, matchingCard, points, cardsToTurnDown): if not self.hasLocalToon: return assert self.notify.debugStateCall() if not self.isInPlayState(): return if avId == base.localAvatar.doId: self.localFaceUpList.append(cardToTurnUp) self.turnUpCard(cardToTurnUp) gotBonus = False if points - self.points > 1: gotBonus = True if matchingCard > -1: self.handleMatch(cardToTurnUp, matchingCard, gotBonus) self.flips += 1 self.updateFlipText() self.points = points self.pointsLabel['text'] = str(self.points) for card in cardsToTurnDown: self.turnDownCard(card) def startBonusTask(self): taskMgr.add(self.moveBonusGlowTask, self.taskName("moveBonusGlowTask")) def stopBonusTask(self): taskMgr.remove(self.taskName("moveBonusGlowTask")) def setEveryoneDone(self): if not self.hasLocalToon: return if self.gameFSM.getCurrentState().getName() != 'play': self.notify.warning('ignoring setEveryoneDone msg') return self.notify.debug('setEveryoneDone') def endGame(task, self=self): if not PairingGameGlobals.EndlessGame: self.gameOver() return Task.done # hide the timer self.timer.hide() # hide the bonus self.bonusGlow.hide() # if it was a perfect game, let the players know if len(self.inactiveList) == len(self.cards): self.notify.debug("perfect game!") perfectTextSubnode = hidden.attachNewNode( self.__genText(TTLocalizer.PairingGamePerfect)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) # offset the subnode so that the text is centered on both axes # we need the parent node so that the text will scale correctly frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2. perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, .1, .1, 1) def fadeFunc(t, text=perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text=perfectText): text.removeNode() textTrack = Sequence( Func(perfectText.reparentTo, aspect2d), Parallel( LerpScaleInterval(perfectText, duration=.5, scale=.3, startScale=0.), LerpFunctionInterval( fadeFunc, fromData=0., toData=1., duration=.5, )), Wait(2.), Parallel( LerpScaleInterval(perfectText, duration=.5, scale=1.), LerpFunctionInterval(fadeFunc, fromData=1., toData=0., duration=.5, blendType="easeIn"), ), Func(destroyText), WaitInterval(.5), Func(endGame, None), ) soundTrack = SoundInterval(self.sndPerfect) self.perfectIval = Parallel(textTrack, soundTrack) self.perfectIval.start() else: taskMgr.doMethodLater(1, endGame, self.EndGameTaskName) def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def b_setSignaling(self, avId): self.setSignaling(avId) self.sendUpdate('setSignaling', [self.localAvId]) def setSignaling(self, avId): if not self.hasLocalToon: return avIndex = self.avIdList.index(avId) av = base.cr.doId2do.get(avId) if av and (avIndex >= 0) and hasattr(self, 'signalSfx') and self.signalSfx: base.playSfx(self.signalSfx[avIndex], node=av) def __beginSignal(self, mouseParam): self.notify.debug('beginSignal') base.localAvatar.b_setEmoteState(1, 1.0) self.b_setSignaling(self.localAvId) # we get the time of the jump animation from base.localAvatar.animPanel() taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal') def __endSignal(self, mouseParam): self.notify.debug('endSignal') base.localAvatar.b_setEmoteState(-1, 1.0) taskMgr.remove('pairGameContinueSignal') def __continueSignal(self, task): base.localAvatar.b_setEmoteState(1, 1.0) self.b_setSignaling(self.localAvId) taskMgr.doMethodLater(1.67, self.__continueSignal, 'pairGameContinueSignal') def getCardPos(self, deckOrderIndex): col = deckOrderIndex % self.cardsPerRow row = deckOrderIndex / self.cardsPerRow x = col * self.xCardInc y = row * self.yCardInc return x, y def getDeckOrderIndex(self, row, col): """ returns the card at a given row, and column, or -1 if a card is not there """ retval = row * self.cardsPerRow retval += col if retval >= len(self.deck.cards): retval = -1 return retval def calcBonusTraversal(self): self.bonusTraversal = [] halfRow = self.cardsPerRow / 2 if self.cardsPerRow % 2: halfRow += 1 for i in xrange(halfRow): for j in xrange(2): col = i + j * halfRow for row in xrange(self.cardsPerCol): card = self.getDeckOrderIndex(row, col) if card > -1: self.bonusTraversal.append(card)
class DistributedCogThiefGame(DistributedMinigame): notify = directNotify.newCategory('DistributedCogThiefGame') ToonSpeed = CTGG.ToonSpeed StageHalfWidth = 200.0 StageHalfHeight = 100.0 BarrelScale = 0.3 TOON_Z = 0 UPDATE_SUITS_TASK = 'CogThiefGameUpdateSuitsTask' REWARD_COUNTDOWN_TASK = 'cogThiefGameRewardCountdown' ControlKeyLimitTime = 1.0 def __init__(self, cr): DistributedMinigame.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM('DistributedCogThiefGame', [ State.State('off', self.enterOff, self.exitOff, ['play']), State.State('play', self.enterPlay, self.exitPlay, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, []) ], 'off', 'cleanup') self.addChildGameFSM(self.gameFSM) toon = base.localAvatar camera.reparentTo(toon) camera.setPos(0, -15, 5) camera.setHpr(0, -5, 0) self.barrels = [] self.cogInfo = {} self.lastTimeControlPressed = 0 self.stolenBarrels = [] self.useOrthoWalk = config.GetBool('cog-thief-ortho', 0) self.resultIval = None self.gameIsEnding = False self.__textGen = TextNode('cogThiefGame') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) return def getTitle(self): return TTLocalizer.CogThiefGameTitle def getInstructions(self): return TTLocalizer.CogThiefGameInstructions def getMaxDuration(self): return 0 def load(self): self.notify.debug('load') DistributedMinigame.load(self) self.music = base.loader.loadMusic('phase_4/audio/bgm/MG_CogThief.ogg') self.initCogInfo() for barrelIndex in range(CTGG.NumBarrels): barrel = loader.loadModel( 'phase_4/models/minigames/cogthief_game_gagTank') barrel.setPos(CTGG.BarrelStartingPositions[barrelIndex]) barrel.setScale(self.BarrelScale) barrel.reparentTo(render) barrel.setTag('barrelIndex', str(barrelIndex)) collSphere = CollisionSphere(0, 0, 0, 4) collSphere.setTangible(0) name = 'BarrelSphere-%d' % barrelIndex collSphereName = self.uniqueName(name) collNode = CollisionNode(collSphereName) collNode.setFromCollideMask(CTGG.BarrelBitmask) collNode.addSolid(collSphere) colNp = barrel.attachNewNode(collNode) handler = CollisionHandlerEvent() handler.setInPattern('barrelHit-%fn') base.cTrav.addCollider(colNp, handler) self.accept('barrelHit-' + collSphereName, self.handleEnterBarrel) nodeToHide = '**/gagMoneyTen' if barrelIndex % 2: nodeToHide = '**/gagMoneyFive' iconToHide = barrel.find(nodeToHide) if not iconToHide.isEmpty(): iconToHide.hide() self.barrels.append(barrel) self.gameBoard = loader.loadModel( 'phase_8/models/minigames/tag_arena_DG') self.sky = loader.loadModel('phase_3.5/models/props/TT_sky') self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.sky.setPosHpr(0, 0, -47, 0, 0, 0) self.sky.setScale(1.0) self.toonSDs = {} avId = self.localAvId toonSD = CogThiefGameToonSD.CogThiefGameToonSD(avId, self) self.toonSDs[avId] = toonSD toonSD.load() self.loadCogs() self.toonHitTracks = {} self.toonPieTracks = {} self.sndOof = base.loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndRewardTick = base.loader.loadSfx( 'phase_3.5/audio/sfx/tick_counter.ogg') self.sndPerfect = base.loader.loadSfx( 'phase_4/audio/sfx/ring_perfect.ogg') self.timer = ToontownTimer.ToontownTimer() self.timer.posInTopRightCorner() self.timer.hide() purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui') self.jarImage = purchaseModels.find('**/Jar') self.jarImage.reparentTo(hidden) self.rewardPanel = DirectLabel(parent=hidden, relief=None, pos=(-0.173, -1.2, -0.55), scale=0.65, text='', text_scale=0.2, text_fg=(0.95, 0.95, 0, 1), text_pos=(0, -0.13), text_font=ToontownGlobals.getSignFont(), image=self.jarImage) self.rewardPanelTitle = DirectLabel(parent=self.rewardPanel, relief=None, pos=(0, 0, 0.06), scale=0.08, text=TTLocalizer.CannonGameReward, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1)) return def unload(self): self.notify.debug('unload') DistributedMinigame.unload(self) del self.music self.removeChildGameFSM(self.gameFSM) del self.gameFSM self.gameBoard.removeNode() self.sky.removeNode() del self.gameBoard for barrel in self.barrels: barrel.removeNode() del self.barrels for avId in self.toonSDs.keys(): toonSD = self.toonSDs[avId] toonSD.unload() del self.toonSDs self.timer.destroy() del self.timer self.rewardPanel.destroy() del self.rewardPanel self.jarImage.removeNode() del self.jarImage del self.sndRewardTick def onstage(self): self.notify.debug('onstage') DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) self.sky.reparentTo(render) lt = base.localAvatar lt.reparentTo(render) self.__placeToon(self.localAvId) lt.setSpeed(0, 0) toonSD = self.toonSDs[self.localAvId] toonSD.enter() toonSD.fsm.request('normal') self.stopGameWalk() for cogIndex in xrange(self.getNumCogs()): suit = self.cogInfo[cogIndex]['suit'].suit pos = self.cogInfo[cogIndex]['pos'] suit.reparentTo(self.gameBoard) suit.setPos(pos) for avId in self.avIdList: self.toonHitTracks[avId] = Wait(0.1) self.toonRNGs = [] for i in xrange(self.numPlayers): self.toonRNGs.append(RandomNumGen.RandomNumGen(self.randomNumGen)) self.sndTable = { 'hitBySuit': [None] * self.numPlayers, 'falling': [None] * self.numPlayers } for i in xrange(self.numPlayers): self.sndTable['hitBySuit'][i] = base.loader.loadSfx( 'phase_4/audio/sfx/MG_Tag_C.ogg') self.sndTable['falling'][i] = base.loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_whizz.ogg') base.playMusic(self.music, looping=1, volume=0.8) return def offstage(self): self.notify.debug('offstage') self.gameBoard.hide() self.music.stop() for barrel in self.barrels: barrel.hide() for avId in self.toonSDs.keys(): self.toonSDs[avId].exit() for avId in self.avIdList: av = self.getAvatar(avId) if av: av.resetLOD() self.timer.reparentTo(hidden) self.rewardPanel.reparentTo(hidden) DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug('handleDisabledAvatar') self.notify.debug('avatar ' + str(avId) + ' disabled') self.toonSDs[avId].exit(unexpectedExit=True) del self.toonSDs[avId] DistributedMinigame.handleDisabledAvatar(self, avId) def setGameReady(self): if not self.hasLocalToon: return self.notify.debug('setGameReady') if DistributedMinigame.setGameReady(self): return for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self.__placeToon(avId) toon.useLOD(1000) toonSD = CogThiefGameToonSD.CogThiefGameToonSD(avId, self) self.toonSDs[avId] = toonSD toonSD.load() toonSD.enter() toonSD.fsm.request('normal') toon.startSmooth() def setGameStart(self, timestamp): if not self.hasLocalToon: return self.notify.debug('setGameStart') DistributedMinigame.setGameStart(self, timestamp) if not config.GetBool('cog-thief-endless', 0): self.timer.show() self.timer.countdown(CTGG.GameTime, self.__gameTimerExpired) self.clockStopTime = None self.rewardPanel.reparentTo(base.a2dTopRight) self.scoreMult = MinigameGlobals.getScoreMult(self.cr.playGame.hood.id) self.__startRewardCountdown() self.gameFSM.request('play') return def enterOff(self): self.notify.debug('enterOff') def exitOff(self): pass def enterPlay(self): self.notify.debug('enterPlay') self.startGameWalk() self.spawnUpdateSuitsTask() self.accept('delete', self.controlKeyPressed) self.accept('insert', self.controlKeyPressed) self.accept('alt', self.controlKeyPressed) self.pieHandler = CollisionHandlerEvent() self.pieHandler.setInPattern('pieHit-%fn') def exitPlay(self): self.ignore('control') if self.resultIval and self.resultIval.isPlaying(): self.resultIval.finish() self.resultIval = None return def enterCleanup(self): self.__killRewardCountdown() if hasattr(self, 'jarIval'): self.jarIval.finish() del self.jarIval for key in self.toonHitTracks: ival = self.toonHitTracks[key] if ival.isPlaying(): ival.finish() self.toonHitTracks = {} for key in self.toonPieTracks: ival = self.toonPieTracks[key] if ival.isPlaying(): ival.finish() self.toonPieTracks = {} for key in self.cogInfo: cogThief = self.cogInfo[key]['suit'] cogThief.cleanup() self.removeUpdateSuitsTask() self.notify.debug('enterCleanup') def exitCleanup(self): pass def __placeToon(self, avId): toon = self.getAvatar(avId) if toon: index = self.avIdList.index(avId) toon.setPos(CTGG.ToonStartingPositions[index]) toon.setHpr(CTGG.ToonStartingRotations[index]) def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraTopView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) camera.setZ(camera.getZ() + config.GetFloat('cog-thief-z-camera-adjust', 0.0)) def destroyGameWalk(self): self.notify.debug('destroyOrthoWalk') if self.useOrthoWalk: self.gameWalk.destroy() del self.gameWalk else: self.notify.debug('TODO destroyGameWalk') def initGameWalk(self): self.notify.debug('startOrthoWalk') if self.useOrthoWalk: def doCollisions(oldPos, newPos, self=self): x = bound(newPos[0], CTGG.StageHalfWidth, -CTGG.StageHalfWidth) y = bound(newPos[1], CTGG.StageHalfHeight, -CTGG.StageHalfHeight) newPos.setX(x) newPos.setY(y) return newPos orthoDrive = OrthoDrive(self.ToonSpeed, customCollisionCallback=doCollisions, instantTurn=True) self.gameWalk = OrthoWalk(orthoDrive, broadcast=not self.isSinglePlayer()) else: self.gameWalk = CogThiefWalk.CogThiefWalk('walkDone') forwardSpeed = self.ToonSpeed / 2.0 base.mouseInterfaceNode.setForwardSpeed(forwardSpeed) multiplier = forwardSpeed / ToontownGlobals.ToonForwardSpeed base.mouseInterfaceNode.setRotateSpeed( ToontownGlobals.ToonRotateSpeed * 4) def initCogInfo(self): for cogIndex in xrange(self.getNumCogs()): self.cogInfo[cogIndex] = { 'pos': Point3(CTGG.CogStartingPositions[cogIndex]), 'goal': CTGG.NoGoal, 'goalId': CTGG.InvalidGoalId, 'suit': None } return def loadCogs(self): suitTypes = ['ds', 'ac', 'bc', 'ms'] for suitIndex in xrange(self.getNumCogs()): st = base.cr.newsManager.getInvadingSuit() if not st: st = self.randomNumGen.choice(suitTypes) suit = CogThief.CogThief(suitIndex, st, self, self.getCogSpeed()) self.cogInfo[suitIndex]['suit'] = suit def handleEnterSphere(self, colEntry): if self.gameIsEnding: return intoName = colEntry.getIntoNodePath().getName() fromName = colEntry.getFromNodePath().getName() debugInto = intoName.split('/') debugFrom = fromName.split('/') self.notify.debug( 'handleEnterSphere gametime=%s %s into %s' % (self.getCurrentGameTime(), debugFrom[(-1)], debugInto[(-1)])) intoName = colEntry.getIntoNodePath().getName() if 'CogThiefSphere' in intoName: parts = intoName.split('-') suitNum = int(parts[1]) self.localToonHitBySuit(suitNum) def localToonHitBySuit(self, suitNum): self.notify.debug('localToonHitBySuit %d' % suitNum) timestamp = globalClockDelta.localToNetworkTime( globalClock.getFrameTime(), bits=32) pos = self.cogInfo[suitNum]['suit'].suit.getPos() self.sendUpdate( 'hitBySuit', [self.localAvId, timestamp, suitNum, pos[0], pos[1], pos[2]]) self.showToonHitBySuit(self.localAvId, timestamp) self.makeSuitRespondToToonHit(timestamp, suitNum) def hitBySuit(self, avId, timestamp, suitNum, x, y, z): if not self.hasLocalToon: return if self.gameFSM.getCurrentState().getName() not in ('play', ): self.notify.warning('ignoring msg: av %s hit by suit' % avId) return if self.gameIsEnding: return self.notify.debug('avatar ' + ` avId ` + ' hit by a suit') if avId != self.localAvId: self.showToonHitBySuit(avId, timestamp) self.makeSuitRespondToToonHit(timestamp, suitNum) def showToonHitBySuit(self, avId, timestamp): toon = self.getAvatar(avId) if toon == None: return rng = self.toonRNGs[self.avIdList.index(avId)] curPos = toon.getPos(render) oldTrack = self.toonHitTracks[avId] if oldTrack.isPlaying(): oldTrack.finish() toon.setPos(curPos) toon.setZ(self.TOON_Z) parentNode = render.attachNewNode('mazeFlyToonParent-' + ` avId `) parentNode.setPos(toon.getPos()) toon.reparentTo(parentNode) toon.setPos(0, 0, 0) startPos = parentNode.getPos() dropShadow = toon.dropShadow.copyTo(parentNode) dropShadow.setScale(toon.dropShadow.getScale(render)) trajectory = Trajectory.Trajectory(0, Point3(0, 0, 0), Point3(0, 0, 50), gravMult=1.0) oldFlyDur = trajectory.calcTimeOfImpactOnPlane(0.0) trajectory = Trajectory.Trajectory(0, Point3(0, 0, 0), Point3(0, 0, 40), gravMult=1.0) flyDur = trajectory.calcTimeOfImpactOnPlane(0.0) avIndex = self.avIdList.index(avId) endPos = CTGG.ToonStartingPositions[avIndex] def flyFunc(t, trajectory, startPos=startPos, endPos=endPos, dur=flyDur, moveNode=parentNode, flyNode=toon): u = t / dur moveNode.setX(startPos[0] + u * (endPos[0] - startPos[0])) moveNode.setY(startPos[1] + u * (endPos[1] - startPos[1])) flyNode.setPos(trajectory.getPos(t)) flyTrack = Sequence(LerpFunctionInterval(flyFunc, fromData=0.0, toData=flyDur, duration=flyDur, extraArgs=[trajectory]), name=toon.uniqueName('hitBySuit-fly')) geomNode = toon.getGeomNode() startHpr = geomNode.getHpr() destHpr = Point3(startHpr) hRot = rng.randrange(1, 8) if rng.choice([0, 1]): hRot = -hRot destHpr.setX(destHpr[0] + hRot * 360) spinHTrack = Sequence(LerpHprInterval(geomNode, flyDur, destHpr, startHpr=startHpr), Func(geomNode.setHpr, startHpr), name=toon.uniqueName('hitBySuit-spinH')) parent = geomNode.getParent() rotNode = parent.attachNewNode('rotNode') geomNode.reparentTo(rotNode) rotNode.setZ(toon.getHeight() / 2.0) oldGeomNodeZ = geomNode.getZ() geomNode.setZ(-toon.getHeight() / 2.0) startHpr = rotNode.getHpr() destHpr = Point3(startHpr) pRot = rng.randrange(1, 3) if rng.choice([0, 1]): pRot = -pRot destHpr.setY(destHpr[1] + pRot * 360) spinPTrack = Sequence(LerpHprInterval(rotNode, flyDur, destHpr, startHpr=startHpr), Func(rotNode.setHpr, startHpr), name=toon.uniqueName('hitBySuit-spinP')) i = self.avIdList.index(avId) soundTrack = Sequence(Func(base.playSfx, self.sndTable['hitBySuit'][i]), Wait(flyDur * (2.0 / 3.0)), SoundInterval(self.sndTable['falling'][i], duration=flyDur * (1.0 / 3.0)), name=toon.uniqueName('hitBySuit-soundTrack')) def preFunc(self=self, avId=avId, toon=toon, dropShadow=dropShadow): forwardSpeed = toon.forwardSpeed rotateSpeed = toon.rotateSpeed if avId == self.localAvId: self.stopGameWalk() else: toon.stopSmooth() if forwardSpeed or rotateSpeed: toon.setSpeed(forwardSpeed, rotateSpeed) toon.dropShadow.hide() def postFunc(self=self, avId=avId, oldGeomNodeZ=oldGeomNodeZ, dropShadow=dropShadow, parentNode=parentNode): if avId == self.localAvId: base.localAvatar.setPos(endPos) if hasattr(self, 'gameWalk'): toon = base.localAvatar toon.setSpeed(0, 0) self.startGameWalk() dropShadow.removeNode() del dropShadow toon = self.getAvatar(avId) if toon: toon.dropShadow.show() geomNode = toon.getGeomNode() rotNode = geomNode.getParent() baseNode = rotNode.getParent() geomNode.reparentTo(baseNode) rotNode.removeNode() del rotNode geomNode.setZ(oldGeomNodeZ) if toon: toon.reparentTo(render) toon.setPos(endPos) parentNode.removeNode() del parentNode if avId != self.localAvId: if toon: toon.startSmooth() preFunc() slipBack = Parallel( Sequence(ActorInterval(toon, 'slip-backward', endFrame=24), ActorInterval(toon, 'slip-backward', startFrame=24))) if toon.doId == self.localAvId: slipBack.append(SoundInterval(self.sndOof)) hitTrack = Sequence(Parallel(flyTrack, spinHTrack, spinPTrack, soundTrack), slipBack, Func(postFunc), name=toon.uniqueName('hitBySuit')) self.notify.debug('hitTrack duration = %s' % hitTrack.getDuration()) self.toonHitTracks[avId] = hitTrack hitTrack.start(globalClockDelta.localElapsedTime(timestamp)) return def updateSuitGoal(self, timestamp, inResponseToClientStamp, suitNum, goalType, goalId, x, y, z): if not self.hasLocalToon: return self.notify.debug( 'updateSuitGoal gameTime=%s timeStamp=%s cog=%s goal=%s goalId=%s (%.1f, %.1f,%.1f)' % (self.getCurrentGameTime(), timestamp, suitNum, CTGG.GoalStr[goalType], goalId, x, y, z)) cog = self.cogInfo[suitNum] cog['goal'] = goalType cog['goalId'] = goalId newPos = Point3(x, y, z) cog['pos'] = newPos suit = cog['suit'] suit.updateGoal(timestamp, inResponseToClientStamp, goalType, goalId, newPos) def spawnUpdateSuitsTask(self): self.notify.debug('spawnUpdateSuitsTask') for cogIndex in self.cogInfo: suit = self.cogInfo[cogIndex]['suit'] suit.gameStart(self.gameStartTime) taskMgr.remove(self.UPDATE_SUITS_TASK) taskMgr.add(self.updateSuitsTask, self.UPDATE_SUITS_TASK) def removeUpdateSuitsTask(self): taskMgr.remove(self.UPDATE_SUITS_TASK) def updateSuitsTask(self, task): if self.gameIsEnding: return task.done for cogIndex in self.cogInfo: suit = self.cogInfo[cogIndex]['suit'] suit.think() return task.cont def makeSuitRespondToToonHit(self, timestamp, suitNum): cog = self.cogInfo[suitNum]['suit'] cog.respondToToonHit(timestamp) def handleEnterBarrel(self, colEntry): if self.gameIsEnding: return intoName = colEntry.getIntoNodePath().getName() fromName = colEntry.getFromNodePath().getName() debugInto = intoName.split('/') debugFrom = fromName.split('/') self.notify.debug( 'handleEnterBarrel gameTime=%s %s into %s' % (self.getCurrentGameTime(), debugFrom[(-1)], debugInto[(-1)])) if 'CogThiefSphere' in intoName: parts = intoName.split('-') cogIndex = int(parts[1]) barrelName = colEntry.getFromNodePath().getName() barrelParts = barrelName.split('-') barrelIndex = int(barrelParts[1]) cog = self.cogInfo[cogIndex]['suit'] if cog.barrel == CTGG.NoBarrelCarried and barrelIndex not in self.stolenBarrels: timestamp = globalClockDelta.localToNetworkTime( globalClock.getFrameTime(), bits=32) if cog.suit: cogPos = cog.suit.getPos() collisionPos = colEntry.getContactPos(render) if (cogPos - collisionPos).length() > 4: import pdb pdb.set_trace() self.sendUpdate('cogHitBarrel', [ timestamp, cogIndex, barrelIndex, cogPos[0], cogPos[1], cogPos[2] ]) def makeCogCarryBarrel(self, timestamp, inResponseToClientStamp, cogIndex, barrelIndex, x, y, z): if not self.hasLocalToon: return if self.gameIsEnding: return self.notify.debug( 'makeCogCarryBarrel gameTime=%s timeStamp=%s cog=%s barrel=%s (%.1f, %.1f,%.1f)' % (self.getCurrentGameTime(), timestamp, cogIndex, barrelIndex, x, y, z)) barrel = self.barrels[barrelIndex] self.notify.debug('barrelPos= %s' % barrel.getPos()) cog = self.cogInfo[cogIndex]['suit'] cogPos = Point3(x, y, z) cog.makeCogCarryBarrel(timestamp, inResponseToClientStamp, barrel, barrelIndex, cogPos) def makeCogDropBarrel(self, timestamp, inResponseToClientStamp, cogIndex, barrelIndex, x, y, z): if not self.hasLocalToon: return self.notify.debug( 'makeCogDropBarrel gameTime=%s timeStamp=%s cog=%s barrel=%s (%.1f, %.1f,%.1f)' % (self.getCurrentGameTime(), timestamp, cogIndex, barrelIndex, x, y, z)) barrel = self.barrels[barrelIndex] self.notify.debug('barrelPos= %s' % barrel.getPos()) cog = self.cogInfo[cogIndex]['suit'] cogPos = Point3(x, y, z) cog.makeCogDropBarrel(timestamp, inResponseToClientStamp, barrel, barrelIndex, cogPos) def controlKeyPressed(self): if self.isToonPlayingHitTrack(self.localAvId): return if self.gameIsEnding: return if self.getCurrentGameTime( ) - self.lastTimeControlPressed > self.ControlKeyLimitTime: self.lastTimeControlPressed = self.getCurrentGameTime() self.notify.debug('controlKeyPressed') toonSD = self.toonSDs[self.localAvId] curState = toonSD.fsm.getCurrentState().getName() toon = self.getAvatar(self.localAvId) timestamp = globalClockDelta.localToNetworkTime( globalClock.getFrameTime(), bits=32) pos = toon.getPos() heading = toon.getH() self.sendUpdate( 'throwingPie', [self.localAvId, timestamp, heading, pos[0], pos[1], pos[2]]) self.showToonThrowingPie(self.localAvId, timestamp, heading, pos) def throwingPie(self, avId, timestamp, heading, x, y, z): if not self.hasLocalToon: return if self.gameFSM.getCurrentState().getName() not in ('play', ): self.notify.warning('ignoring msg: av %s hit by suit' % avId) return self.notify.debug('avatar ' + ` avId ` + ' throwing pie') if avId != self.localAvId: pos = Point3(x, y, z) self.showToonThrowingPie(avId, timestamp, heading, pos) def showToonThrowingPie(self, avId, timestamp, heading, pos): toon = self.getAvatar(avId) if toon: tossTrack, pieTrack, flyPie = self.getTossPieInterval( toon, pos[0], pos[1], pos[2], heading, 0, 0, 0) def removePieFromTraverser(flyPie=flyPie): if base.cTrav: if flyPie: base.cTrav.removeCollider(flyPie) if avId == self.localAvId: flyPie.setTag('throwerId', str(avId)) collSphere = CollisionSphere(0, 0, 0, 0.5) collSphere.setTangible(0) name = 'PieSphere-%d' % avId collSphereName = self.uniqueName(name) collNode = CollisionNode(collSphereName) collNode.setFromCollideMask(ToontownGlobals.PieBitmask) collNode.addSolid(collSphere) colNp = flyPie.attachNewNode(collNode) colNp.show() base.cTrav.addCollider(colNp, self.pieHandler) self.accept('pieHit-' + collSphereName, self.handlePieHitting) def matchRunningAnim(toon=toon): toon.playingAnim = None toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed) return newTossTrack = Sequence(tossTrack, Func(matchRunningAnim)) pieTrack = Parallel(newTossTrack, pieTrack) elapsedTime = globalClockDelta.localElapsedTime(timestamp) if elapsedTime < 16.0 / 24.0: elapsedTime = 16.0 / 24.0 pieTrack.start(elapsedTime) self.toonPieTracks[avId] = pieTrack def getTossPieInterval(self, toon, x, y, z, h, p, r, power, beginFlyIval=Sequence()): from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps pie = toon.getPieModel() pie.setScale(0.9) flyPie = pie.copyTo(NodePath('a')) pieName = ToontownBattleGlobals.pieNames[toon.pieType] pieType = BattleProps.globalPropPool.getPropType(pieName) animPie = Sequence() if pieType == 'actor': animPie = ActorInterval(pie, pieName, startFrame=48) sound = loader.loadSfx('phase_3.5/audio/sfx/AA_pie_throw_only.ogg') t = power / 100.0 dist = 100 - 70 * t time = 1 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(toon=toon, relVel=relVel): return render.getRelativeVector(toon, relVel) * 0.6 toss = Track( (0, Sequence( Func(toon.setPosHpr, x, y, z, h, p, r), Func(pie.reparentTo, toon.rightHand), Func(pie.setPosHpr, 0, 0, 0, 0, 0, 0), Parallel( ActorInterval( toon, 'throw', startFrame=48, partName='torso'), animPie), Func(toon.loop, 'neutral'))), (16.0 / 24.0, Func(pie.detachNode))) fly = Track( (14.0 / 24.0, SoundInterval(sound, node=toon)), (16.0 / 24.0, Sequence( Func(flyPie.reparentTo, render), Func(flyPie.setPosHpr, toon, 0.52, 0.97, 2.24, 0, -45, 0), beginFlyIval, ProjectileInterval(flyPie, startVel=getVelocity, duration=6), Func(flyPie.detachNode)))) return (toss, fly, flyPie) def handlePieHitting(self, colEntry): if self.gameIsEnding: return into = colEntry.getIntoNodePath() intoName = into.getName() if 'CogThiefPieSphere' in intoName: timestamp = globalClockDelta.localToNetworkTime( globalClock.getFrameTime(), bits=32) parts = intoName.split('-') suitNum = int(parts[1]) pos = self.cogInfo[suitNum]['suit'].suit.getPos() if pos in CTGG.CogStartingPositions: self.notify.debug('Cog %d hit at starting pos %s, ignoring' % (suitNum, pos)) else: self.sendUpdate('pieHitSuit', [ self.localAvId, timestamp, suitNum, pos[0], pos[1], pos[2] ]) self.makeSuitRespondToPieHit(timestamp, suitNum) def pieHitSuit(self, avId, timestamp, suitNum, x, y, z): if not self.hasLocalToon: return if self.gameFSM.getCurrentState().getName() not in ('play', ): self.notify.warning('ignoring msg: av %s hit by suit' % avId) return if self.gameIsEnding: return self.notify.debug('avatar ' + ` avId ` + ' hit by a suit') if avId != self.localAvId: self.makeSuitRespondToPieHit(timestamp, suitNum) def makeSuitRespondToPieHit(self, timestamp, suitNum): cog = self.cogInfo[suitNum]['suit'] cog.respondToPieHit(timestamp) def sendCogAtReturnPos(self, cogIndex, barrelIndex): timestamp = globalClockDelta.localToNetworkTime( globalClock.getFrameTime(), bits=32) self.sendUpdate('cogAtReturnPos', [timestamp, cogIndex, barrelIndex]) def markBarrelStolen(self, timestamp, inResponseToClientStamp, barrelIndex): if not self.hasLocalToon: return if barrelIndex not in self.stolenBarrels: self.stolenBarrels.append(barrelIndex) barrel = self.barrels[barrelIndex] barrel.hide() if config.GetBool('cog-thief-check-barrels', 1): if not config.GetBool('cog-thief-endless', 0): if len(self.stolenBarrels) == len(self.barrels): localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) gameTime = self.local2GameTime(localStamp) self.clockStopTime = gameTime self.notify.debug('clockStopTime = %s' % gameTime) score = int(self.scoreMult * CTGG.calcScore(gameTime) + 0.5) self.rewardPanel['text'] = str(score) self.showResults() def __gameTimerExpired(self): self.notify.debug('game timer expired') self.showResults() def __startRewardCountdown(self): taskMgr.remove(self.REWARD_COUNTDOWN_TASK) taskMgr.add(self.__updateRewardCountdown, self.REWARD_COUNTDOWN_TASK) def __killRewardCountdown(self): taskMgr.remove(self.REWARD_COUNTDOWN_TASK) def __updateRewardCountdown(self, task): curTime = self.getCurrentGameTime() if self.clockStopTime is not None: if self.clockStopTime < curTime: self.notify.debug('self.clockStopTime < curTime %s %s' % (self.clockStopTime, curTime)) self.__killRewardCountdown() curTime = self.clockStopTime if curTime > CTGG.GameTime: curTime = CTGG.GameTime score = int(self.scoreMult * CTGG.calcScore(curTime) + 0.5) if not hasattr(task, 'curScore'): task.curScore = score result = Task.cont if hasattr(self, 'rewardPanel'): self.rewardPanel['text'] = str(score) if task.curScore != score: if hasattr(self, 'jarIval'): self.jarIval.finish() s = self.rewardPanel.getScale() self.jarIval = Parallel(Sequence( self.rewardPanel.scaleInterval(0.15, s * 3.0 / 4.0, blendType='easeOut'), self.rewardPanel.scaleInterval(0.15, s, blendType='easeIn')), SoundInterval(self.sndRewardTick), name='cogThiefGameRewardJarThrob') self.jarIval.start() task.curScore = score else: result = Task.done return result def startGameWalk(self): if self.useOrthoWalk: self.gameWalk.start() else: self.gameWalk.enter() self.gameWalk.fsm.request('walking') def stopGameWalk(self): if self.useOrthoWalk: self.gameWalk.stop() else: self.gameWalk.exit() def getCogThief(self, cogIndex): return self.cogInfo[cogIndex]['suit'] def isToonPlayingHitTrack(self, avId): if avId in self.toonHitTracks: track = self.toonHitTracks[avId] if track.isPlaying(): return True return False def getNumCogs(self): result = config.GetInt('cog-thief-num-cogs', 0) if not result: safezone = self.getSafezoneId() result = CTGG.calculateCogs(self.numPlayers, safezone) return result def getCogSpeed(self): result = 6.0 safezone = self.getSafezoneId() result = CTGG.calculateCogSpeed(self.numPlayers, safezone) return result def showResults(self): if not self.gameIsEnding: self.gameIsEnding = True for barrel in self.barrels: barrel.wrtReparentTo(render) for key in self.cogInfo: thief = self.cogInfo[key]['suit'] thief.suit.setPos(100, 0, 0) thief.suit.hide() self.__killRewardCountdown() self.stopGameWalk() numBarrelsSaved = len(self.barrels) - len(self.stolenBarrels) resultStr = '' if numBarrelsSaved == len(self.barrels): resultStr = TTLocalizer.CogThiefPerfect else: if numBarrelsSaved > 1: resultStr = TTLocalizer.CogThiefBarrelsSaved % { 'num': numBarrelsSaved } else: if numBarrelsSaved == 1: resultStr = TTLocalizer.CogThiefBarrelSaved % { 'num': numBarrelsSaved } else: resultStr = TTLocalizer.CogThiefNoBarrelsSaved perfectTextSubnode = hidden.attachNewNode( self.__genText(resultStr)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text=perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text=perfectText): text.removeNode() def safeGameOver(self=self): if not self.frameworkFSM.isInternalStateInFlux(): self.gameOver() textTrack = Sequence( Func(perfectText.reparentTo, aspect2d), Parallel( LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel( LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5), Func(safeGameOver)) if numBarrelsSaved == len(self.barrels): soundTrack = SoundInterval(self.sndPerfect) else: soundTrack = Sequence() self.resultIval = Parallel(textTrack, soundTrack) self.resultIval.start() if config.GetBool('want-blueprint4-ARG', False): MinigameGlobals.generateDebugARGPhrase() def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def getIntroTrack(self): base.camera.setPosHpr(0, -13.66, 13.59, 0, -51.6, 0) result = Sequence( Wait(2), LerpPosHprInterval(base.camera, 13, Point3(self.cameraTopView[0], self.cameraTopView[1], self.cameraTopView[2]), Point3(self.cameraTopView[3], self.cameraTopView[4], self.cameraTopView[5]), blendType='easeIn')) return result
class IceTreasure(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory('IceTreasure') RADIUS = 1.0 def __init__(self, model, pos, serialNum, gameId, penalty=False): self.serialNum = serialNum self.penalty = penalty center = model.getBounds().getCenter() center = Point3(0, 0, 0) self.nodePath = model.copyTo(render) self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.nodePath.setZ(0) self.notify.debug('newPos = %s' % self.nodePath.getPos()) if self.penalty: self.sphereName = 'penaltySphere-%s-%s' % (gameId, self.serialNum) else: self.sphereName = 'treasureSphere-%s-%s' % (gameId, self.serialNum) self.collSphere = CollisionSphere(center[0], center[1], center[2], self.RADIUS) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.sphereName) self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = render.attachNewNode(self.collNode) self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.collNodePath.hide() self.track = None if self.penalty: self.tip = self.nodePath.find('**/fusetip') sparks = BattleParticles.createParticleEffect(file='icetnt') self.sparksEffect = sparks sparks.start(self.tip) self.penaltyGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.penaltyGrabSound.setVolume(0.75) kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach') kaboomAttachPoint.setZ(3) self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.reparentTo(kaboomAttachPoint) self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() def destroy(self): self.ignoreAll() if self.penalty: self.sparksEffect.cleanup() if self.track: self.track.finish() self.nodePath.removeNode() del self.nodePath del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def showGrab(self): self.nodePath.hide() self.collNodePath.hide() self.collNode.setIntoCollideMask(BitMask32(0)) if self.penalty: self.track = Parallel( SoundInterval(self.penaltyGrabSound), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), blendType='easeOut'), Func(self.kaboom.hide))) self.track.start()
class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIceWorld.DistributedIceWorld): notify = directNotify.newCategory('DistributedIceGame') MaxLocalForce = 100 MaxPhysicsForce = 25000 def __init__(self, cr): DistributedMinigame.DistributedMinigame.__init__(self, cr) DistributedIceWorld.DistributedIceWorld.__init__(self, cr) self.gameFSM = ClassicFSM.ClassicFSM('DistributedIceGame', [ State.State('off', self.enterOff, self.exitOff, ['inputChoice']), State.State( 'inputChoice', self.enterInputChoice, self.exitInputChoice, ['waitServerChoices', 'moveTires', 'displayVotes', 'cleanup']), State.State('waitServerChoices', self.enterWaitServerChoices, self.exitWaitServerChoices, ['moveTires', 'cleanup']), State.State('moveTires', self.enterMoveTires, self.exitMoveTires, ['synch', 'cleanup']), State.State('synch', self.enterSynch, self.exitSynch, ['inputChoice', 'scoring', 'cleanup']), State.State('scoring', self.enterScoring, self.exitScoring, ['cleanup', 'finalResults', 'inputChoice']), State.State('finalResults', self.enterFinalResults, self.exitFinalResults, ['cleanup']), State.State('cleanup', self.enterCleanup, self.exitCleanup, []) ], 'off', 'cleanup') self.addChildGameFSM(self.gameFSM) self.cameraThreeQuarterView = (0, -22, 45, 0, -62.890000000000001, 0) self.tireDict = {} self.forceArrowDict = {} self.canDrive = False self.timer = None self.timerStartTime = None self.curForce = 0 self.curHeading = 0 self.headingMomentum = 0.0 self.forceMomentum = 0.0 self.allTireInputs = None self.curRound = 0 self.curMatch = 0 self.controlKeyWarningLabel = DirectLabel( text=TTLocalizer.IceGameControlKeyWarning, text_fg=VBase4(1, 0, 0, 1), relief=None, pos=(0.0, 0, 0), scale=0.14999999999999999) self.controlKeyWarningLabel.hide() self.waitingMoveLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForPlayersToFinishMove, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.59999999999999998, 0, -0.75), scale=0.074999999999999997) self.waitingMoveLabel.hide() self.waitingSyncLabel = DirectLabel( text=TTLocalizer.IceGameWaitingForAISync, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.59999999999999998, 0, -0.75), scale=0.074999999999999997) self.waitingSyncLabel.hide() self.infoLabel = DirectLabel(text='', text_fg=VBase4(0, 0, 0, 1), relief=None, pos=(0.0, 0, 0.69999999999999996), scale=0.074999999999999997) self.updateInfoLabel() self.lastForceArrowUpdateTime = 0 self.sendForceArrowUpdateAsap = False self.treasures = [] self.penalties = [] self.obstacles = [] self.controlKeyPressed = False self.controlKeyWarningIval = None def delete(self): DistributedIceWorld.DistributedIceWorld.delete(self) DistributedMinigame.DistributedMinigame.delete(self) if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningLabel.destroy() del self.controlKeyWarningLabel self.waitingMoveLabel.destroy() del self.waitingMoveLabel self.waitingSyncLabel.destroy() del self.waitingSyncLabel self.infoLabel.destroy() del self.infoLabel for treasure in self.treasures: treasure.destroy() del self.treasures for penalty in self.penalties: penalty.destroy() del self.penalties for obstacle in self.obstacles: obstacle.removeNode() del self.obstacles del self.gameFSM def announceGenerate(self): DistributedMinigame.DistributedMinigame.announceGenerate(self) DistributedIceWorld.DistributedIceWorld.announceGenerate(self) self.debugTaskName = self.uniqueName('debugTask') def getTitle(self): return TTLocalizer.IceGameTitle def getInstructions(self): szId = self.getSafezoneId() numPenalties = IceGameGlobals.NumPenalties[szId] result = TTLocalizer.IceGameInstructions if numPenalties == 0: result = TTLocalizer.IceGameInstructionsNoTnt return result def getMaxDuration(self): return 0 def load(self): self.notify.debug('load') DistributedMinigame.DistributedMinigame.load(self) self.music = base.loadMusic('phase_4/audio/bgm/MG_IceGame.mid') self.gameBoard = loader.loadModel( 'phase_4/models/minigames/ice_game_icerink') background = loader.loadModel('phase_4/models/minigames/ice_game_2d') background.reparentTo(self.gameBoard) self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0) self.gameBoard.setScale(1.0) self.setupSimulation() index = 0 for avId in self.avIdList: self.setupTire(avId, index) self.setupForceArrow(avId) index += 1 for index in xrange(len(self.avIdList), 4): self.setupTire(-index, index) self.setupForceArrow(-index) self.showForceArrows(realPlayersOnly=True) self.westWallModel = NodePath() if not self.westWallModel.isEmpty(): self.westWallModel.reparentTo(self.gameBoard) self.westWallModel.setPos(IceGameGlobals.MinWall[0], IceGameGlobals.MinWall[1], 0) self.westWallModel.setScale(4) self.eastWallModel = NodePath() if not self.eastWallModel.isEmpty(): self.eastWallModel.reparentTo(self.gameBoard) self.eastWallModel.setPos(IceGameGlobals.MaxWall[0], IceGameGlobals.MaxWall[1], 0) self.eastWallModel.setScale(4) self.eastWallModel.setH(180) self.arrowKeys = ArrowKeys.ArrowKeys() self.target = loader.loadModel('phase_3/models/misc/sphere') self.target.setScale(0.01) self.target.reparentTo(self.gameBoard) self.target.setPos(0, 0, 0) self.scoreCircle = loader.loadModel( 'phase_4/models/minigames/ice_game_score_circle') self.scoreCircle.setScale(0.01) self.scoreCircle.reparentTo(self.gameBoard) self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0) self.scoreCircle.setAlphaScale(0.5) self.scoreCircle.setTransparency(1) self.scoreCircle.hide() self.treasureModel = loader.loadModel( 'phase_4/models/minigames/ice_game_barrel') self.penaltyModel = loader.loadModel( 'phase_4/models/minigames/ice_game_tnt2') self.penaltyModel.setScale(0.75, 0.75, 0.69999999999999996) szId = self.getSafezoneId() obstacles = IceGameGlobals.Obstacles[szId] index = 0 cubicObstacle = IceGameGlobals.ObstacleShapes[szId] for pos in obstacles: newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius) newObstacle = self.createObstacle(newPos, index, cubicObstacle) self.obstacles.append(newObstacle) index += 1 self.countSound = loader.loadSfx( 'phase_3.5/audio/sfx/tick_counter.mp3') self.treasureGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_vine_game_bananas.mp3') self.penaltyGrabSound = loader.loadSfx( 'phase_4/audio/sfx/MG_cannon_fire_alt.mp3') self.tireSounds = [] for tireIndex in xrange(4): tireHit = loader.loadSfx( 'phase_4/audio/sfx/Golf_Hit_Barrier_1.mp3') wallHit = loader.loadSfx('phase_4/audio/sfx/MG_maze_pickup.mp3') obstacleHit = loader.loadSfx( 'phase_4/audio/sfx/Golf_Hit_Barrier_2.mp3') self.tireSounds.append({ 'tireHit': tireHit, 'wallHit': wallHit, 'obstacleHit': obstacleHit }) self.arrowRotateSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_rotate.wav') self.arrowUpSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.mp3') self.arrowDownSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.mp3') self.scoreCircleSound = loader.loadSfx( 'phase_4/audio/sfx/MG_sfx_ice_scoring_1.mp3') def unload(self): self.notify.debug('unload') DistributedMinigame.DistributedMinigame.unload(self) del self.music self.gameBoard.removeNode() del self.gameBoard for forceArrow in self.forceArrowDict.values(): forceArrow.removeNode() del self.forceArrowDict self.scoreCircle.removeNode() del self.scoreCircle del self.countSound def onstage(self): self.notify.debug('onstage') DistributedMinigame.DistributedMinigame.onstage(self) self.gameBoard.reparentTo(render) self._DistributedIceGame__placeToon(self.localAvId) self.moveCameraToTop() self.scorePanels = [] base.playMusic(self.music, looping=1, volume=0.80000000000000004) def offstage(self): self.notify.debug('offstage') self.music.stop() self.gameBoard.hide() self.infoLabel.hide() for avId in self.tireDict: self.tireDict[avId]['tireNodePath'].hide() for panel in self.scorePanels: panel.cleanup() del self.scorePanels for obstacle in self.obstacles: obstacle.hide() for treasure in self.treasures: treasure.nodePath.hide() for penalty in self.penalties: penalty.nodePath.hide() for avId in self.avIdList: av = self.getAvatar(avId) if av: av.dropShadow.show() av.resetLOD() continue taskMgr.remove(self.uniqueName('aimtask')) self.arrowKeys.destroy() del self.arrowKeys DistributedMinigame.DistributedMinigame.offstage(self) def handleDisabledAvatar(self, avId): self.notify.debug('handleDisabledAvatar') self.notify.debug('avatar ' + str(avId) + ' disabled') DistributedMinigame.DistributedMinigame.handleDisabledAvatar( self, avId) def setGameReady(self): if not self.hasLocalToon: return None self.notify.debug('setGameReady') if DistributedMinigame.DistributedMinigame.setGameReady(self): return None for index in xrange(self.numPlayers): avId = self.avIdList[index] toon = self.getAvatar(avId) if toon: toon.reparentTo(render) self._DistributedIceGame__placeToon(avId) toon.forwardSpeed = 0 toon.rotateSpeed = False toon.dropShadow.hide() toon.setAnimState('Sit') if avId in self.tireDict: tireNp = self.tireDict[avId]['tireNodePath'] toon.reparentTo(tireNp) toon.setY(1.0) toon.setZ(-3) toon.startLookAround() continue def setGameStart(self, timestamp): if not self.hasLocalToon: return None self.notify.debug('setGameStart') DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp) for avId in self.remoteAvIdList: toon = self.getAvatar(avId) if toon: toon.stopLookAround() continue self.scores = [0] * self.numPlayers spacing = 0.40000000000000002 for i in xrange(self.numPlayers): avId = self.avIdList[i] avName = self.getAvatarName(avId) scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel( avId, avName) scorePanel.setScale(0.90000000000000002) scorePanel.setPos(0.75 - spacing * (self.numPlayers - 1 - i), 0.0, 0.875) scorePanel.makeTransparent(0.75) self.scorePanels.append(scorePanel) self.arrowKeys.setPressHandlers([ self._DistributedIceGame__upArrowPressed, self._DistributedIceGame__downArrowPressed, self._DistributedIceGame__leftArrowPressed, self._DistributedIceGame__rightArrowPressed, self._DistributedIceGame__controlPressed ]) def isInPlayState(self): if not self.gameFSM.getCurrentState(): return False if not self.gameFSM.getCurrentState().getName() == 'play': return False return True def enterOff(self): self.notify.debug('enterOff') def exitOff(self): pass def enterInputChoice(self): self.notify.debug('enterInputChoice') self.forceLocalToonToTire() self.controlKeyPressed = False if self.curRound == 0: self.setupStartOfMatch() else: self.notify.debug('self.curRound = %s' % self.curRound) self.timer = ToontownTimer.ToontownTimer() self.timer.hide() if self.timerStartTime != None: self.startTimer() self.showForceArrows(realPlayersOnly=True) self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0) self.localForceArrow().reparentTo(self.localTireNp()) self.localForceArrow().setY(IceGameGlobals.TireRadius) self.localTireNp().headsUp(self.target) self.notify.debug('self.localForceArrow() heading = %s' % self.localForceArrow().getH()) self.curHeading = self.localTireNp().getH() self.curForce = 25 self.updateLocalForceArrow() for avId in self.forceArrowDict: forceArrow = self.forceArrowDict[avId] forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0) tireNp = self.tireDict[avId]['tireNodePath'] forceArrow.reparentTo(tireNp) forceArrow.setY(IceGameGlobals.TireRadius) tireNp.headsUp(self.target) self.updateForceArrow(avId, tireNp.getH(), 25) taskMgr.add(self._DistributedIceGame__aimTask, self.uniqueName('aimtask')) if base.localAvatar.laffMeter: base.localAvatar.laffMeter.stop() self.sendForceArrowUpdateAsap = False def exitInputChoice(self): if not self.controlKeyPressed: if self.controlKeyWarningIval: self.controlKeyWarningIval.finish() self.controlKeyWarningIval = None self.controlKeyWarningIval = Sequence( Func(self.controlKeyWarningLabel.show), self.controlKeyWarningLabel.colorScaleInterval( 10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1)), Func(self.controlKeyWarningLabel.hide)) self.controlKeyWarningIval.start() if self.timer != None: self.timer.destroy() self.timer = None self.timerStartTime = None self.hideForceArrows() self.arrowRotateSound.stop() self.arrowUpSound.stop() self.arrowDownSound.stop() taskMgr.remove(self.uniqueName('aimtask')) def enterWaitServerChoices(self): self.waitingMoveLabel.show() self.showForceArrows(True) def exitWaitServerChoices(self): self.waitingMoveLabel.hide() self.hideForceArrows() def enterMoveTires(self): for key in self.tireDict: body = self.tireDict[key]['tireBody'] body.setAngularVel(0, 0, 0) body.setLinearVel(0, 0, 0) for index in xrange(len(self.allTireInputs)): input = self.allTireInputs[index] avId = self.avIdList[index] body = self.getTireBody(avId) degs = input[1] + 90 tireNp = self.getTireNp(avId) tireH = tireNp.getH() self.notify.debug('tireH = %s' % tireH) radAngle = deg2Rad(degs) foo = NodePath('foo') dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0) self.notify.debug('dirVector is now=%s' % dirVector) inputForce = input[0] inputForce /= self.MaxLocalForce inputForce *= self.MaxPhysicsForce force = dirVector * inputForce self.notify.debug('adding force %s to %d' % (force, avId)) body.addForce(force) self.enableAllTireBodies() self.totalPhysicsSteps = 0 self.startSim() taskMgr.add(self._DistributedIceGame__moveTiresTask, self.uniqueName('moveTiresTtask')) def exitMoveTires(self): self.forceLocalToonToTire() self.disableAllTireBodies() self.stopSim() self.notify.debug('total Physics steps = %d' % self.totalPhysicsSteps) taskMgr.remove(self.uniqueName('moveTiresTtask')) def enterSynch(self): self.waitingSyncLabel.show() def exitSynch(self): self.waitingSyncLabel.hide() def enterScoring(self): sortedByDistance = [] for avId in self.avIdList: np = self.getTireNp(avId) pos = np.getPos() pos.setZ(0) sortedByDistance.append((avId, pos.length())) def compareDistance(x, y): if x[1] - y[1] > 0: return 1 elif x[1] - y[1] < 0: return -1 else: return 0 sortedByDistance.sort(cmp=compareDistance) self.scoreMovie = Sequence() curScale = 0.01 curTime = 0 self.scoreCircle.setScale(0.01) self.scoreCircle.show() self.notify.debug('newScores = %s' % self.newScores) circleStartTime = 0 for index in xrange(len(sortedByDistance)): distance = sortedByDistance[index][1] avId = sortedByDistance[index][0] scorePanelIndex = self.avIdList.index(avId) time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec if time < 0: time = 0.01 scaleXY = distance + IceGameGlobals.TireRadius self.notify.debug('circleStartTime = %s' % circleStartTime) self.scoreMovie.append( Parallel( LerpScaleInterval(self.scoreCircle, time, Point3(scaleXY, scaleXY, 1.0)), SoundInterval(self.scoreCircleSound, duration=time, startTime=circleStartTime))) circleStartTime += time startScore = self.scorePanels[scorePanelIndex].getScore() destScore = self.newScores[scorePanelIndex] self.notify.debug('for avId %d, startScore=%d, newScores=%d' % (avId, startScore, destScore)) def increaseScores(t, scorePanelIndex=scorePanelIndex, startScore=startScore, destScore=destScore): oldScore = self.scorePanels[scorePanelIndex].getScore() diff = destScore - startScore newScore = int(startScore + diff * t) if newScore > oldScore: base.playSfx(self.countSound) self.scorePanels[scorePanelIndex].setScore(newScore) self.scores[scorePanelIndex] = newScore duration = (destScore - startScore) * IceGameGlobals.ScoreCountUpRate tireNp = self.tireDict[avId]['tireNodePath'] self.scoreMovie.append( Parallel( LerpFunctionInterval(increaseScores, duration), Sequence( LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)), LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1))))) curScale += distance self.scoreMovie.append( Func(self.sendUpdate, 'reportScoringMovieDone', [])) self.scoreMovie.start() def exitScoring(self): self.scoreMovie.finish() self.scoreMovie = None self.scoreCircle.hide() def enterFinalResults(self): lerpTrack = Parallel() lerpDur = 0.5 tY = 0.59999999999999998 bY = -0.050000000000000003 lX = -0.5 cX = 0 rX = 0.5 scorePanelLocs = (((cX, bY), ), ((lX, bY), (rX, bY)), ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY), (lX, bY), (rX, bY))) scorePanelLocs = scorePanelLocs[self.numPlayers - 1] for i in xrange(self.numPlayers): panel = self.scorePanels[i] pos = scorePanelLocs[i] lerpTrack.append( Parallel( LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType='easeInOut'), LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType='easeInOut'))) self.showScoreTrack = Parallel( lerpTrack, Sequence(Wait(IceGameGlobals.ShowScoresDuration), Func(self.gameOver))) self.showScoreTrack.start() def exitFinalResults(self): self.showScoreTrack.pause() del self.showScoreTrack def enterCleanup(self): self.notify.debug('enterCleanup') if base.localAvatar.laffMeter: base.localAvatar.laffMeter.start() def exitCleanup(self): pass def _DistributedIceGame__placeToon(self, avId): toon = self.getAvatar(avId) if toon: toon.setPos(0, 0, 0) toon.setHpr(0, 0, 0) def moveCameraToTop(self): camera.reparentTo(render) p = self.cameraThreeQuarterView camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5]) def setupTire(self, avId, index): (tireNp, tireBody, tireOdeGeom) = self.createTire(index) self.tireDict[avId] = { 'tireNodePath': tireNp, 'tireBody': tireBody, 'tireOdeGeom': tireOdeGeom } if avId <= 0: tireBlocker = tireNp.find('**/tireblockermesh') if not tireBlocker.isEmpty(): tireBlocker.hide() if avId == self.localAvId: tireNp = self.tireDict[avId]['tireNodePath'] self.treasureSphereName = 'treasureCollider' self.treasureCollSphere = CollisionSphere( 0, 0, 0, IceGameGlobals.TireRadius) self.treasureCollSphere.setTangible(0) self.treasureCollNode = CollisionNode(self.treasureSphereName) self.treasureCollNode.setFromCollideMask( ToontownGlobals.PieBitmask) self.treasureCollNode.addSolid(self.treasureCollSphere) self.treasureCollNodePath = tireNp.attachNewNode( self.treasureCollNode) self.treasureHandler = CollisionHandlerEvent() self.treasureHandler.addInPattern('%fn-intoTreasure') base.cTrav.addCollider(self.treasureCollNodePath, self.treasureHandler) eventName = '%s-intoTreasure' % self.treasureCollNodePath.getName() self.notify.debug('eventName = %s' % eventName) self.accept(eventName, self.toonHitSomething) def setupForceArrow(self, avId): arrow = loader.loadModel('phase_4/models/minigames/ice_game_arrow') priority = 0 if avId < 0: priority = -avId else: priority = self.avIdList.index(avId) if avId == self.localAvId: priority = 10 self.forceArrowDict[avId] = arrow def hideForceArrows(self): for forceArrow in self.forceArrowDict.values(): forceArrow.hide() def showForceArrows(self, realPlayersOnly=True): for avId in self.forceArrowDict: if realPlayersOnly: if avId > 0: self.forceArrowDict[avId].show() else: self.forceArrowDict[avId].hide() avId > 0 self.forceArrowDict[avId].show() def localForceArrow(self): if self.localAvId in self.forceArrowDict: return self.forceArrowDict[self.localAvId] else: return None def setChoices(self, input0, input1, input2, input3): pass def startDebugTask(self): taskMgr.add(self.debugTask, self.debugTaskName) def stopDebugTask(self): taskMgr.remove(self.debugTaskName) def debugTask(self, task): if self.canDrive and self.tireDict.has_key(localAvatar.doId): dt = globalClock.getDt() forceMove = 25000 forceMoveDt = forceMove tireBody = self.tireDict[localAvatar.doId]['tireBody'] if self.arrowKeys.upPressed() and not tireBody.isEnabled(): x = 0 y = 1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.downPressed() and not tireBody.isEnabled(): x = 0 y = -1 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.leftPressed() and not tireBody.isEnabled(): x = -1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) if self.arrowKeys.rightPressed() and not tireBody.isEnabled(): x = 1 y = 0 tireBody.enable() tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0)) return task.cont def _DistributedIceGame__upArrowPressed(self): pass def _DistributedIceGame__downArrowPressed(self): pass def _DistributedIceGame__leftArrowPressed(self): pass def _DistributedIceGame__rightArrowPressed(self): pass def _DistributedIceGame__controlPressed(self): if self.gameFSM.getCurrentState().getName() == 'inputChoice': self.sendForceArrowUpdateAsap = True self.updateLocalForceArrow() self.controlKeyPressed = True self.sendUpdate('setAvatarChoice', [self.curForce, self.curHeading]) self.gameFSM.request('waitServerChoices') def startTimer(self): now = globalClock.getFrameTime() elapsed = now - self.timerStartTime self.timer.posInTopRightCorner() self.timer.setTime(IceGameGlobals.InputTimeout) self.timer.countdown(IceGameGlobals.InputTimeout - elapsed, self.handleChoiceTimeout) self.timer.show() def setTimerStartTime(self, timestamp): if not self.hasLocalToon: return None self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp) if self.timer != None: self.startTimer() def handleChoiceTimeout(self): self.sendUpdate('setAvatarChoice', [0, 0]) self.gameFSM.request('waitServerChoices') def localTireNp(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]['tireNodePath'] return ret def localTireBody(self): ret = None if self.localAvId in self.tireDict: ret = self.tireDict[self.localAvId]['tireBody'] return ret def getTireBody(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]['tireBody'] return ret def getTireNp(self, avId): ret = None if avId in self.tireDict: ret = self.tireDict[avId]['tireNodePath'] return ret def updateForceArrow(self, avId, curHeading, curForce): forceArrow = self.forceArrowDict[avId] tireNp = self.tireDict[avId]['tireNodePath'] tireNp.setH(curHeading) tireBody = self.tireDict[avId]['tireBody'] tireBody.setQuaternion(tireNp.getQuat()) self.notify.debug('curHeading = %s' % curHeading) yScale = curForce / 100.0 yScale *= 1 headY = yScale * 15 xScale = (yScale - 1) / 2.0 + 1.0 shaft = forceArrow.find('**/arrow_shaft') head = forceArrow.find('**/arrow_head') shaft.setScale(xScale, yScale, 1) head.setPos(0, headY, 0) head.setScale(xScale, xScale, 1) def updateLocalForceArrow(self): avId = self.localAvId self.b_setForceArrowInfo(avId, self.curHeading, self.curForce) def _DistributedIceGame__aimTask(self, task): if not hasattr(self, 'arrowKeys'): return task.done dt = globalClock.getDt() headingMomentumChange = dt * 60.0 forceMomentumChange = dt * 160.0 arrowUpdate = False arrowRotating = False arrowUp = False arrowDown = False if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce += self.forceMomentum * dt arrowUpdate = True if oldForce < self.MaxLocalForce: arrowUp = True elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed(): self.forceMomentum += forceMomentumChange if self.forceMomentum < 0: self.forceMomentum = 0 if self.forceMomentum > 50: self.forceMomentum = 50 oldForce = self.curForce self.curForce -= self.forceMomentum * dt arrowUpdate = True if oldForce > 0.01: arrowDown = True else: self.forceMomentum = 0 if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading += self.headingMomentum * dt arrowUpdate = True arrowRotating = True elif self.arrowKeys.rightPressed( ) and not self.arrowKeys.leftPressed(): self.headingMomentum += headingMomentumChange if self.headingMomentum < 0: self.headingMomentum = 0 if self.headingMomentum > 50: self.headingMomentum = 50 self.curHeading -= self.headingMomentum * dt arrowUpdate = True arrowRotating = True else: self.headingMomentum = 0 if arrowUpdate: self.normalizeHeadingAndForce() self.updateLocalForceArrow() if arrowRotating: if not self.arrowRotateSound.status( ) == self.arrowRotateSound.PLAYING: base.playSfx(self.arrowRotateSound, looping=True) else: self.arrowRotateSound.stop() if arrowUp: if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING: base.playSfx(self.arrowUpSound, looping=False) else: self.arrowUpSound.stop() if arrowDown: if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING: base.playSfx(self.arrowDownSound, looping=False) else: self.arrowDownSound.stop() return task.cont def normalizeHeadingAndForce(self): if self.curForce > self.MaxLocalForce: self.curForce = self.MaxLocalForce if self.curForce < 0.01: self.curForce = 0.01 def setTireInputs(self, tireInputs): if not self.hasLocalToon: return None self.allTireInputs = tireInputs self.gameFSM.request('moveTires') def enableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]['tireBody'].enable() def disableAllTireBodies(self): for avId in self.tireDict.keys(): self.tireDict[avId]['tireBody'].disable() def areAllTiresDisabled(self): for avId in self.tireDict.keys(): if self.tireDict[avId]['tireBody'].isEnabled(): return False continue return True def _DistributedIceGame__moveTiresTask(self, task): if self.areAllTiresDisabled(): self.sendTirePositions() self.gameFSM.request('synch') return task.done return task.cont def sendTirePositions(self): tirePositions = [] for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) pos = Point3(tire.getPosition()) tirePositions.append([pos[0], pos[1], pos[2]]) self.sendUpdate('endingPositions', [tirePositions]) def setFinalPositions(self, finalPos): if not self.hasLocalToon: return None for index in xrange(len(self.avIdList)): avId = self.avIdList[index] tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) for index in xrange(len(self.avIdList), 4): avId = -index tire = self.getTireBody(avId) np = self.getTireNp(avId) pos = finalPos[index] tire.setPosition(pos[0], pos[1], pos[2]) np.setPos(pos[0], pos[1], pos[2]) def updateInfoLabel(self): self.infoLabel['text'] = TTLocalizer.IceGameInfo % { 'curMatch': self.curMatch + 1, 'numMatch': IceGameGlobals.NumMatches, 'curRound': self.curRound + 1, 'numRound': IceGameGlobals.NumRounds } def setMatchAndRound(self, match, round): if not self.hasLocalToon: return None self.curMatch = match self.curRound = round self.updateInfoLabel() def setScores(self, match, round, scores): if not self.hasLocalToon: return None self.newMatch = match self.newRound = round self.newScores = scores def setNewState(self, state): if not self.hasLocalToon: return None self.notify.debug('setNewState gameFSM=%s newState=%s' % (self.gameFSM, state)) self.gameFSM.request(state) def putAllTiresInStartingPositions(self): for index in xrange(len(self.avIdList)): avId = self.avIdList[index] np = self.tireDict[avId]['tireNodePath'] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]['tireBody'] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) for index in xrange(len(self.avIdList), 4): avId = -index np = self.tireDict[avId]['tireNodePath'] np.setPos(IceGameGlobals.StartingPositions[index]) self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos)) np.setHpr(0, 0, 0) quat = np.getQuat() body = self.tireDict[avId]['tireBody'] body.setPosition(IceGameGlobals.StartingPositions[index]) body.setQuaternion(quat) def b_setForceArrowInfo(self, avId, force, heading): self.setForceArrowInfo(avId, force, heading) self.d_setForceArrowInfo(avId, force, heading) def d_setForceArrowInfo(self, avId, force, heading): sendIt = False curTime = self.getCurrentGameTime() if self.sendForceArrowUpdateAsap: sendIt = True elif curTime - self.lastForceArrowUpdateTime > 0.20000000000000001: sendIt = True if sendIt: self.sendUpdate('setForceArrowInfo', [avId, force, heading]) self.sendForceArrowUpdateAsap = False self.lastForceArrowUpdateTime = self.getCurrentGameTime() def setForceArrowInfo(self, avId, force, heading): if not self.hasLocalToon: return None self.updateForceArrow(avId, force, heading) def setupStartOfMatch(self): self.putAllTiresInStartingPositions() szId = self.getSafezoneId() self.numTreasures = IceGameGlobals.NumTreasures[szId] if self.treasures: for treasure in self.treasures: treasure.destroy() self.treasures = [] index = 0 treasureMargin = IceGameGlobals.TireRadius + 1.0 while len(self.treasures) < self.numTreasures: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug('yPos=%s' % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newTreasure = IceTreasure.IceTreasure(self.treasureModel, pos, index, self.doId, penalty=False) goodSpot = True for obstacle in self.obstacles: if newTreasure.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break continue if goodSpot: for treasure in self.treasures: if newTreasure.nodePath.getDistance( treasure.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: self.treasures.append(newTreasure) index += 1 continue newTreasure.destroy() self.numPenalties = IceGameGlobals.NumPenalties[szId] if self.penalties: for penalty in self.penalties: penalty.destroy() self.penalties = [] index = 0 while len(self.penalties) < self.numPenalties: xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5) yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5) self.notify.debug('yPos=%s' % yPos) pos = Point3(xPos, yPos, IceGameGlobals.TireRadius) newPenalty = IceTreasure.IceTreasure(self.penaltyModel, pos, index, self.doId, penalty=True) goodSpot = True for obstacle in self.obstacles: if newPenalty.nodePath.getDistance(obstacle) < treasureMargin: goodSpot = False break continue if goodSpot: for treasure in self.treasures: if newPenalty.nodePath.getDistance( treasure.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: for penalty in self.penalties: if newPenalty.nodePath.getDistance( penalty.nodePath) < treasureMargin: goodSpot = False break continue if goodSpot: self.penalties.append(newPenalty) index += 1 continue newPenalty.destroy() def toonHitSomething(self, entry): self.notify.debug('---- treasure Enter ---- ') self.notify.debug('%s' % entry) name = entry.getIntoNodePath().getName() parts = name.split('-') if len(parts) < 3: self.notify.debug('collided with %s, but returning' % name) return None if not int(parts[1]) == self.doId: self.notify.debug("collided with %s, but doId doesn't match" % name) return None treasureNum = int(parts[2]) if 'penalty' in parts[0]: self._DistributedIceGame__penaltyGrabbed(treasureNum) else: self._DistributedIceGame__treasureGrabbed(treasureNum) def _DistributedIceGame__treasureGrabbed(self, treasureNum): self.treasures[treasureNum].showGrab() self.treasureGrabSound.play() self.sendUpdate('claimTreasure', [treasureNum]) def setTreasureGrabbed(self, avId, treasureNum): if not self.hasLocalToon: return None self.notify.debug('treasure %s grabbed by %s' % (treasureNum, avId)) if avId != self.localAvId: self.treasures[treasureNum].showGrab() i = self.avIdList.index(avId) self.scores[i] += 1 self.scorePanels[i].setScore(self.scores[i]) def _DistributedIceGame__penaltyGrabbed(self, penaltyNum): self.penalties[penaltyNum].showGrab() self.sendUpdate('claimPenalty', [penaltyNum]) def setPenaltyGrabbed(self, avId, penaltyNum): if not self.hasLocalToon: return None self.notify.debug('penalty %s grabbed by %s' % (penaltyNum, avId)) if avId != self.localAvId: self.penalties[penaltyNum].showGrab() i = self.avIdList.index(avId) self.scores[i] -= 1 self.scorePanels[i].setScore(self.scores[i]) def postStep(self): DistributedIceWorld.DistributedIceWorld.postStep(self) for count in range(self.colCount): (c0, c1) = self.getOrderedContacts(count) if c1 in self.tireCollideIds: tireIndex = self.tireCollideIds.index(c1) if c0 in self.tireCollideIds: self.tireSounds[tireIndex]['tireHit'].play() elif c0 == self.wallCollideId: self.tireSounds[tireIndex]['wallHit'].play() elif c0 == self.obstacleCollideId: self.tireSounds[tireIndex]['obstacleHit'].play() c0 in self.tireCollideIds def forceLocalToonToTire(self): toon = localAvatar if toon and self.localAvId in self.tireDict: tireNp = self.tireDict[self.localAvId]['tireNodePath'] toon.reparentTo(tireNp) toon.setPosHpr(0, 0, 0, 0, 0, 0) toon.setY(1.0) toon.setZ(-3)
class DistributedNPCToon(DistributedToon): notify = directNotify.newCategory('DistributedNPCToon') def __init__(self, cr): DistributedToon.__init__(self, cr) self.collisionNodePath = None self.cameraTrack = None self.originIndex = None self.npcId = None self.currentChatIndex = 0 self.chatArray = None return def setLoadout(self, foo): pass def lookAtAvatar(self, avId): av = self.cr.doId2do.get(avId) if av: self.headsUp(av) def setNpcId(self, id): self.npcId = id def getNpcId(self): return self.npcId def setOriginIndex(self, index): self.originIndex = index def getOriginIndex(self): return self.originIndex def __setupCollisions(self): sphere = CollisionSphere(0, 0, 0, 4) sphere.setTangible(0) collisionNode = CollisionNode(self.uniqueName('NPCToonSphere')) collisionNode.addSolid(sphere) collisionNode.setCollideMask(CIGlobals.WallBitmask) self.collisionNodePath = self.attachNewNode(collisionNode) self.collisionNodePath.setY(1.5) def __removeCollisions(self): if self.collisionNodePath: self.collisionNodePath.removeNode() self.collisionNodePath = None return def handleEnterCollision(self, entry): self.cr.playGame.getPlace().fsm.request('stop') base.localAvatar.stopSmartCamera() self.sendUpdate('requestEnter', []) def doCameraNPCInteraction(self): currCamPos = camera.getPos() currCamHpr = camera.getHpr() camera.setX(camera.getX() + 5) camera.setY(camera.getY() + 5) camera.headsUp(self) newCamPos = camera.getPos() newCamHpr = camera.getHpr() camera.setPos(currCamPos) camera.setHpr(currCamHpr) self.cameraTrack = Parallel(LerpPosInterval(camera, duration=1.0, pos=newCamPos, startPos=currCamPos, blendType='easeOut'), LerpQuatInterval(camera, duration=1.0, quat=newCamHpr, startHpr=currCamHpr, blendType='easeOut')) self.cameraTrack.start() def stopCameraTrack(self): if self.cameraTrack: self.cameraTrack.finish() self.cameraTrack = None return def oneChatThenExit(self): self.acceptOnce('mouse1-up', self.d_requestExit) def enterAccepted(self): self.doCameraNPCInteraction() questData = base.localAvatar.questManager.getQuestAndIdWhereCurrentObjectiveIsToVisit(self.npcId) if questData: quest = questData[1] self.currentQuestObjective = quest.currentObjectiveIndex self.currentQuestId = questData[0] self.currentChatIndex = 0 if CIGlobals.NPCToonDict[self.npcId][3] == CIGlobals.NPC_REGULAR: self.doNPCChat(array=Quests.QuestNPCDialogue) def doNPCChat(self, array = Quests.QuestNPCDialogue, chat = None): if array and not chat: self.chatArray = array self.b_setChat(array[self.currentQuestId][self.currentQuestObjective][self.currentChatIndex]) self.currentChatIndex += 1 Sequence(Wait(0.1), Func(self.acceptOnce, 'mouse1-up', self.doNextNPCChat)).start() elif chat and not array: self.b_setChat(chat) Sequence(Wait(0.1), Func(self.acceptOnce, 'mouse1-up', self.d_requestExit)).start() def d_requestExit(self): self.sendUpdate('requestExit', []) def doNextNPCChat(self): if self.currentChatIndex >= len(self.chatArray[self.currentQuestId][self.currentQuestObjective]): self.chatArray = None self.d_requestExit() else: self.doNPCChat(self.chatArray) return def rejectEnter(self): self.exitAccepted() def exitAccepted(self): self.stopCameraTrack() self.cr.playGame.getPlace().fsm.request('walk') self.acceptCollisions() def acceptCollisions(self): self.acceptOnce('enter' + self.uniqueName('NPCToonSphere'), self.handleEnterCollision) def ignoreCollisions(self): self.ignore('enter' + self.uniqueName('NPCToonSphere')) def __npcOriginPoll(self, task): if task.time > 4.0: self.notify.warning('Giving up waiting for npc origin after %d seconds. Will parent to render.' % task.time) self.reparentTo(render) return task.done npcOrigin = render.find('**/npc_origin_' + str(self.originIndex)) if not npcOrigin.isEmpty(): self.reparentTo(npcOrigin) return task.done return task.cont def startNPCOriginPoll(self): base.taskMgr.add(self.__npcOriginPoll, self.uniqueName('NPCOriginPoll')) def stopNPCOriginPoll(self): base.taskMgr.remove(self.uniqueName('NPCOriginPoll')) def announceGenerate(self): DistributedToon.announceGenerate(self) self.startLookAround() self.__setupCollisions() npcOrigin = render.find('**/npc_origin_' + str(self.originIndex)) if not npcOrigin.isEmpty(): self.reparentTo(npcOrigin) else: self.startNPCOriginPoll() self.acceptCollisions() self.nameTag.setClickable(0) def disable(self): self.ignore('mouse1-up') self.stopLookAround() self.stopNPCOriginPoll() self.chatArray = None self.originIndex = None self.npcId = None self.stopCameraTrack() self.ignoreCollisions() self.__removeCollisions() DistributedToon.disable(self) return
class SquirtingFlower(SquirtGag): def __init__(self): SquirtGag.__init__(self, CIGlobals.SquirtFlower, GagGlobals.getProp(3.5, 'button'), 3, GagGlobals.FLOWER_HIT_SFX, GagGlobals.FLOWER_HIT_SFX, GagGlobals.NULL_SFX, None, 0, 0, 0) self.setImage('phase_3.5/maps/squirting-flower.png') self.flower = None self.flowerScale = 1.5 self.track = Parallel() self.timeout = 4.0 self.sprayRotation = Vec3(0, 20, 0) return def start(self): SquirtGag.start(self) self.buildFlower() self.build() self.equip() if self.isLocal(): self.startTimeout() self.origin = self.getSprayStartPos() def attachFlower(): flowerJoint = self.avatar.find('**/def_joint_attachFlower') if flowerJoint.isEmpty(): flowerJoint = self.avatar.find('**/joint_attachFlower') self.flower.reparentTo(flowerJoint) self.flower.setY(self.flower.getY()) totalAnimationTime = 2.5 flowerAppear = 1.0 flowerScaleTime = 0.5 animTrack = ActorInterval(self.avatar, 'push-button') self.track.append(animTrack) flowerTrack = Sequence(Func(attachFlower), Wait(flowerAppear), LerpScaleInterval(self.flower, flowerScaleTime, 1.5, startScale=GagGlobals.PNT3NEAR0), Wait(totalAnimationTime - flowerScaleTime - flowerAppear)) flowerTrack.append(Func(self.release)) flowerTrack.append(LerpScaleInterval(self.flower, flowerScaleTime, GagGlobals.PNT3NEAR0)) flowerTrack.append(LerpScaleInterval(self.gag, flowerScaleTime, GagGlobals.PNT3NEAR0)) flowerTrack.append(Func(self.unEquip)) self.track.append(flowerTrack) self.track.start() def getSprayStartPos(self): if not self.avatar.isEmpty() and not self.flower.isEmpty(): self.avatar.update(0) return self.flower.getPos(render) def release(self): SquirtGag.release(self) if not self.avatar.isEmpty() and self.gag: self.sprayJoint = self.flower.find('**/joint_attachSpray') self.sprayRange = self.avatar.getPos(render) + Point3(0, GagGlobals.SELTZER_RANGE, 0) self.doSpray(0.2, 0.2, 0.1, horizScale=0.3, vertScale=0.3) if self.isLocal(): base.localAvatar.sendUpdate('usedGag', [self.id]) def unEquip(self): SquirtGag.unEquip(self) self.cleanup() self.reset() def cleanup(self): if self.flower: self.flower.removeNode() self.flower = None if self.track: self.track.pause() self.track = Parallel() return def setHandJoint(self): if self.avatar: self.handJoint = self.avatar.find('**/def_joint_left_hold') if not self.handJoint: print self.avatar.findAllMatches('**/*joint*') def buildFlower(self): if self.flower: self.flower.removeNode() self.flower = None self.flower = loader.loadModel(GagGlobals.getProp(3.5, 'squirting-flower')) self.flower.setScale(GagGlobals.PNT3NEAR0) return
def start(self): SoundGag.start(self) INSTRUMENT_SCALE_MODIFIER = 0.5 delayTime = 2.45 delayUntilAppearSound = 1.0 tracks = Parallel() instrMin = Vec3(0.001, 0.001, 0.001) instrMax = Vec3(0.65, 0.65, 0.65) instrMax *= INSTRUMENT_SCALE_MODIFIER instrStretch = Vec3(0.6, 1.1, 0.6) instrStretch *= INSTRUMENT_SCALE_MODIFIER def setInstrumentStats(): self.gag.setPos(-1.1, -1.4, 0.1) self.gag.setHpr(145, 0, 0) self.gag.setScale(instrMin) megaphoneShow = Sequence( Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats)) grow = self.getScaleIntervals(self.gag, duration=0.2, startScale=instrMin, endScale=instrMax) instrumentAppear = grow stretchInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrMax, endScale=instrStretch, blendType='easeOut') backInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrStretch, endScale=instrMax, blendType='easeIn') stretchMega = self.getScaleBlendIntervals( self.megaphone, duration=0.2, startScale=self.megaphone.getScale(), endScale=0.9, blendType='easeOut') backMega = self.getScaleBlendIntervals( self.megaphone, duration=0.2, startScale=0.9, endScale=self.megaphone.getScale(), blendType='easeIn') attackTrack = Parallel(Sequence(stretchInstr, backInstr), Sequence(stretchMega, backMega)) megaphoneTrack = Sequence( megaphoneShow, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), instrumentAppear) tracks.append(megaphoneTrack) tracks.append(ActorInterval(self.avatar, 'sound')) instrumentshrink = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax, endScale=instrMin) soundTrack = Sequence( Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Wait(0.2), instrumentshrink, Func(self.damageCogsNearby), Wait(0.4), Func(self.finish))) tracks.append(soundTrack) tracks.start() self.tracks = tracks