class HtmlView(DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("HtmlView") useHalfTexture = base.config.GetBool("news-half-texture", 0) def __init__(self, parent=aspect2d): """Properly initialize ourself.""" #AwWebViewListener.AwWebViewListener.__init__(self) self.parent = parent self.mx = 0 self.my = 0 self.htmlFile = "index.html" self.transparency = False # this is important looks weird if it's true global GlobalWebcore if GlobalWebcore: # we get a C++ crash if we construct webcore a second time pass else: GlobalWebcore = AwWebCore(AwWebCore.LOGVERBOSE, True, AwWebCore.PFBGRA) GlobalWebcore.setBaseDirectory('.') for errResponse in range(400, 600): GlobalWebcore.setCustomResponsePage(errResponse, "error.html") self.webView = GlobalWebcore.createWebView(WEB_WIDTH, WEB_HEIGHT, self.transparency, False, 70) #self.webView.setListener(self) #self.webView.setCallback("requestFPS"); frameName = '' inGameNewsUrl = self.getInGameNewsUrl() #self.webView.loadURL2(inGameNewsUrl) self.imgBuffer = array.array('B') for i in range(WEB_WIDTH * WEB_HEIGHT): self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(0) self.imgBuffer.append(255) if self.useHalfTexture: self.leftBuffer = array.array('B') for i in range(WEB_HALF_WIDTH * WEB_HEIGHT): self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(0) self.leftBuffer.append(255) self.rightBuffer = array.array('B') for i in range(WEB_HALF_WIDTH * WEB_HEIGHT): self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(0) self.rightBuffer.append(255) self.setupTexture() if self.useHalfTexture: self.setupHalfTextures() #self.interval = LerpHprInterval(self.quad, 2, Vec3(360, 0, 0), Vec3(0, 0, 0)) #self.accept("escape", sys.exit, [0]) #self.accept("w", self.writeTex) self.accept("mouse1", self.mouseDown, [AwWebView.LEFTMOUSEBTN]) self.accept("mouse3", self.mouseDown, [AwWebView.RIGHTMOUSEBTN]) self.accept("mouse1-up", self.mouseUp, [AwWebView.LEFTMOUSEBTN]) self.accept("mouse3-up", self.mouseUp, [AwWebView.RIGHTMOUSEBTN]) #self.accept("f1", self.toggleRotation) #self.accept("f2", self.toggleTransparency) #self.accept("f3", self.reload) #self.accept("f4", self.zoomIn) #self.accept("f5", self.zoomOut) #taskMgr.doMethodLater(1.0, self.update, 'HtmlViewUpdateTask') # we get a problem if a mid-frame hearbeat fires of this task in conjunction with igLoop #taskMgr.add(self.update, 'HtmlViewUpdateTask', priority = 51) #taskMgr.add(self.update, 'HtmlViewUpdateTask') #base.newsFrame = self def getInGameNewsUrl(self): """Get the appropriate URL to use if we are in test, qa, or live.""" # First if all else fails, we hard code the live news url result = base.config.GetString( "fallback-news-url", "http://cdn.toontown.disney.go.com/toontown/en/gamenews/") # next check if we have an override, say they want to url to point to a file in their harddisk override = base.config.GetString("in-game-news-url", "") if override: self.notify.info( "got an override url, using %s for in a game news" % override) result = override else: try: launcherUrl = base.launcher.getValue("GAME_IN_GAME_NEWS_URL", "") if launcherUrl: result = launcherUrl self.notify.info( "got GAME_IN_GAME_NEWS_URL from launcher using %s" % result) else: self.notify.info( "blank GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) except: self.notify.warning( "got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s" % result) return result def setupTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH_PIXELS / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT_PIXELS) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(-htmlWidth / 2.0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) bottomRightX = (WEB_WIDTH_PIXELS) / float(WEB_WIDTH + 1) bottomRightY = WEB_HEIGHT_PIXELS / float(WEB_HEIGHT + 1) #cm.setUvRange(Point2(0,0), Point2(bottomRightX, bottomRightY)) cm.setUvRange(Point2(0, 1 - bottomRightY), Point2(bottomRightX, 1)) card = cm.generate() self.quad = NodePath(card) self.quad.reparentTo(self.parent) self.guiTex = Texture("guiTex") self.guiTex.setupTexture(Texture.TT2dTexture, WEB_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.guiTex.setMinfilter(Texture.FTLinear) self.guiTex.setKeepRamImage(True) self.guiTex.makeRamImage() self.guiTex.setWrapU(Texture.WMRepeat) self.guiTex.setWrapV(Texture.WMRepeat) ts = TextureStage('webTS') self.quad.setTexture(ts, self.guiTex) self.quad.setTexScale(ts, 1.0, -1.0) self.quad.setTransparency(0) self.quad.setTwoSided(True) self.quad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 self.calcMouseLimits() def setupHalfTextures(self): self.setupLeftTexture() self.setupRightTexture() self.fullPnmImage = PNMImage(WEB_WIDTH, WEB_HEIGHT, 4) self.leftPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) self.rightPnmImage = PNMImage(WEB_HALF_WIDTH, WEB_HEIGHT, 4) def setupLeftTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(-htmlWidth / 2.0, 0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.leftQuad = NodePath(card) self.leftQuad.reparentTo(self.parent) self.leftGuiTex = Texture("guiTex") self.leftGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.leftGuiTex.setKeepRamImage(True) self.leftGuiTex.makeRamImage() self.leftGuiTex.setWrapU(Texture.WMClamp) self.leftGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('leftWebTS') self.leftQuad.setTexture(ts, self.leftGuiTex) self.leftQuad.setTexScale(ts, 1.0, -1.0) self.leftQuad.setTransparency(0) self.leftQuad.setTwoSided(True) self.leftQuad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 def setupRightTexture(self): cm = CardMaker('quadMaker') cm.setColor(1.0, 1.0, 1.0, 1.0) aspect = base.camLens.getAspectRatio() htmlWidth = 2.0 * aspect * WEB_WIDTH / float(WIN_WIDTH) htmlHeight = 2.0 * float(WEB_HEIGHT) / float(WIN_HEIGHT) # the html area will be center aligned and vertically top aligned #cm.setFrame(-htmlWidth/2.0, htmlWidth/2.0, 1.0 - htmlHeight, 1.0) cm.setFrame(0, htmlWidth / 2.0, -htmlHeight / 2.0, htmlHeight / 2.0) card = cm.generate() self.rightQuad = NodePath(card) self.rightQuad.reparentTo(self.parent) self.rightGuiTex = Texture("guiTex") self.rightGuiTex.setupTexture(Texture.TT2dTexture, WEB_HALF_WIDTH, WEB_HEIGHT, 1, Texture.TUnsignedByte, Texture.FRgba) self.rightGuiTex.setKeepRamImage(True) self.rightGuiTex.makeRamImage() self.rightGuiTex.setWrapU(Texture.WMClamp) self.rightGuiTex.setWrapV(Texture.WMClamp) ts = TextureStage('rightWebTS') self.rightQuad.setTexture(ts, self.rightGuiTex) self.rightQuad.setTexScale(ts, 1.0, -1.0) self.rightQuad.setTransparency(0) self.rightQuad.setTwoSided(True) self.rightQuad.setColor(1.0, 1.0, 1.0, 1.0) #self.quad.setZ(0.1) # shtickerbook is moved up by 0.1 def calcMouseLimits(self): ll = Point3() ur = Point3() self.quad.calcTightBounds(ll, ur) self.notify.debug("ll=%s ur=%s" % (ll, ur)) # we need to get our relative position to aspect2d, since shtiker books is shifted offset = self.quad.getPos(aspect2d) self.notify.debug("offset = %s " % offset) ll.setZ(ll.getZ() + offset.getZ()) ur.setZ(ur.getZ() + offset.getZ()) self.notify.debug("new LL=%s, UR=%s" % (ll, ur)) relPointll = self.quad.getRelativePoint(aspect2d, ll) self.notify.debug("relPoint = %s" % relPointll) self.mouseLL = (aspect2d.getScale()[0] * ll[0], aspect2d.getScale()[2] * ll[2]) self.mouseUR = (aspect2d.getScale()[0] * ur[0], aspect2d.getScale()[2] * ur[2]) self.notify.debug("original mouseLL=%s, mouseUR=%s" % (self.mouseLL, self.mouseUR)) def writeTex(self, filename="guiText.png"): self.notify.debug("writing texture") self.guiTex.generateRamMipmapImages() self.guiTex.write(filename) def toggleRotation(self): if self.interval.isPlaying(): self.interval.finish() else: self.interval.loop() def mouseDown(self, button): messenger.send('wakeup') self.webView.injectMouseDown(button) def mouseUp(self, button): self.webView.injectMouseUp(button) def reload(self): pass #self.webView.loadFile(self.htmlFile, '') def zoomIn(self): self.webView.zoomIn() def zoomOut(self): self.webView.zoomOut() def toggleTransparency(self): self.transparency = not self.transparency self.webView.setTransparent(self.transparency) def update(self, task): global GlobalWebcore if base.mouseWatcherNode.hasMouse(): x, y = self._translateRelativeCoordinates( base.mouseWatcherNode.getMouseX(), base.mouseWatcherNode.getMouseY()) #self.notify.debug('got mouse move %d %d' % (x,y)) #self.webView.injectMouseMove(x, y) if (self.mx - x) != 0 or (self.my - y) != 0: self.webView.injectMouseMove(x, y) #self.notify.debug('injecting mouse move %d %d' % (x,y)) self.mx, self.my = x, y if self.webView.isDirty(): #self.notify.debug("webview is dirty") self.webView.render(self.imgBuffer.buffer_info()[0], WEB_WIDTH * 4, 4) #Texture.setTexturesPower2(AutoTextureScale.ATSUp) Texture.setTexturesPower2(2) #self.notify.debug("about to modify ram image") textureBuffer = self.guiTex.modifyRamImage() #import pdb; pdb.set_trace() #self.notify.debug("about to call textureBuffer.setData") textureBuffer.setData(self.imgBuffer.tostring()) #self.notify.debug("done calling setData") if self.useHalfTexture: # TODO check with DRose, this feels inefficient self.guiTex.store(self.fullPnmImage) self.leftPnmImage.copySubImage(self.fullPnmImage, 0, 0, 0, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.rightPnmImage.copySubImage(self.fullPnmImage, 0, 0, WEB_HALF_WIDTH, 0, WEB_HALF_WIDTH, WEB_HEIGHT) self.leftGuiTex.load(self.leftPnmImage) self.rightGuiTex.load(self.rightPnmImage) self.quad.hide() #Texture.setTexturesPower2(AutoTextureScale.ATSDown) Texture.setTexturesPower2(1) GlobalWebcore.update() return Task.cont def _translateRelativeCoordinates(self, x, y): sx = int((x - self.mouseLL[0]) / (self.mouseUR[0] - self.mouseLL[0]) * WEB_WIDTH_PIXELS) sy = WEB_HEIGHT_PIXELS - int( (y - self.mouseLL[1]) / (self.mouseUR[1] - self.mouseLL[1]) * WEB_HEIGHT_PIXELS) return sx, sy def unload(self): """Clean up everything, especially the awesomium bits.""" self.ignoreAll() self.webView.destroy() self.webView = None #global GlobalWebcore #GlobalWebcore = None pass # --------------------[ WebViewListener implementation ]-------------------------- def onCallback(self, name, args): assert self.notify.debugStateCall(self) if name == "requestFPS": #self.webView.setProperty( "fps", JSValue("%.1f" % (1.0 / globalClock.getDt())) ) #self.webView.executeJavascript("updateFPS()", "") pass def onBeginNavigation(self, url, frameName): assert self.notify.debugStateCall(self) pass def onBeginLoading(self, url, frameName, statusCode, mimeType): assert self.notify.debugStateCall(self) pass def onFinishLoading(self): assert self.notify.debugStateCall(self) self.notify.debug("finished loading") pass def onReceiveTitle(self, title, frameName): assert self.notify.debugStateCall(self) pass def onChangeTooltip(self, tooltip): assert self.notify.debugStateCall(self) pass def onChangeCursor(self, cursor): assert self.notify.debugStateCall(self) pass def onChangeKeyboardFocus(self, isFocused): assert self.notify.debugStateCall(self) pass def onChangeTargetURL(self, url): assert self.notify.debugStateCall(self) pass
class PartyCog(FSM): notify = directNotify.newCategory("PartyCog") HpTextGenerator = TextNode("HpTextGenerator") hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, "PartyCogFSM-%d" % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request("Down") def load(self): self.root = NodePath("PartyCog-%d" % self.id) self.root.reparentTo(self.parentNode) path = "phase_13/models/parties/cogPinata_" self.actor = Actor( path + "actor", { "idle": path + "idle_anim", "down": path + "down_anim", "up": path + "up_anim", "bodyHitBack": path + "bodyHitBack_anim", "bodyHitFront": path + "bodyHitFront_anim", "headHitBack": path + "headHitBack_anim", "headHitFront": path + "headHitFront_anim", }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode("temphead") self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode("PartyCog-%d-Body-Collision" % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode("PartyCog-%d-Head-Collision" % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) # Cog's Left Arm self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode("PartyCog-%d-Arm1-Collision" % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) # Cog's Right Arm self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode("PartyCog-%d-Arm2-Collision" % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.mp3') self.hole = loader.loadModel("phase_13/models/parties/cogPinataHole") self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin("ground", 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request("Off") self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound #=============================================================================== # FSM States #=============================================================================== def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, "PartyCog.update-%d" % self.id) def exitActive(self): taskMgr.remove("PartyCog.update-%d" % self.id) taskMgr.remove("PartyCog.bounceTask-%d" % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType="easeInOut") self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == "Off": self.actor.pose("down", self.actor.getNumFrames("down") - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "down", loop=0), ), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "up", loop=0), ), Func(self.actor.loop, "idle"), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def filterDown(self, request, args): if request == "Down": return None else: return self.defaultFilter(request, args) #------------------------------------------------------------------------------ def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) # if self.id == 0: # print angle return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, "PartyCog.bounceTask-%d" % self.id) def bounce(self, task): #self.root.setH(self.root.getH() - self.rotateSpeed) self.root.setZ((math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight) + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): """The toon hit us, react appropriately.""" assert (self.notify.debugStateCall(self)) if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) 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 clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() def __showSplat(self, position, direction, hot=False): """Show the splat graphic and sound.""" if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: #self.splat.setColorScale(Vec4(0.0, 0.0, 50.0, 1.0)) self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = "HitFront" else: facing = "HitBack" else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) #self.splat.setColorScale(Vec4(1.0, 0.6, 0.08, 1.0)) if self.currentFacing > 0.0: facing = "HitBack" else: facing = "HitFront" if hot: targetscale = 0.75 part = "head" else: targetscale = 0.5 part = "body" def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, "idle"), ) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType="easeOut"), Wait(0.175), ), Sequence( Wait(0.1), LerpFunc( setSplatAlpha, duration=1.0, #0.4, fromData=1.0, toData=0.0, blendType="easeOut"))), Func(self.splat.cleanup), Func(self.splat.removeNode), )) self.kaboomTrack.start() def showHitScore(self, number, scale=1): """ Shows the hit score. Borrowed from otp.avatar.DistributedAvatar.showHpText """ if number <= 0: return # Get rid of the number if it is already there. if self.hpText: self.hideHitScore() # Set the font self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) # Show both negative and positive signs if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText("+" + str(number)) # No shadow self.HpTextGenerator.clearShadow() # Center the number self.HpTextGenerator.setAlign(TextNode.ACenter) # Red, always #if number < 0: r = 1 #0.9 g = 1 #0 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() # Put the hpText over the head of the avatar self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) # Make sure it is a billboard self.hpText.setBillboardPointEye() # Render it after other things in the scene. self.hpText.setBin('fixed', 100) # Initial position ... Center of the body... the "tan tien" self.hpText.setPos(self.root, 0, 0, self.height / 2) # Black magic from the early days of Panda3D, later replaced by a Sequence seq = Task.sequence( # Fly the number out of the character self.hpText.lerpPos(Point3( self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), 0.25, blendType='easeOut'), Task.pause(0.25), # Fade the number self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), # Get rid of the number Task.Task(self.__hideHitScoreTask)) taskMgr.add(seq, "PartyCogHpText" + str(self.id)) def __hideHitScoreTask(self, task): self.hideHitScore() return Task.done def hideHitScore(self): if self.hpText: taskMgr.remove("PartyCogHpText" + str(self.id)) self.hpText.removeNode() self.hpText = None def getHeadLocation(self): (self.actor.getJoints(jointName="head")[0]).getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) #print self.head_locator.getZ() return self.head_locator.getZ(self.root)
class PartyCogActivityLocalPlayer(PartyCogActivityPlayer): """Cog Activity Player model for the local Avatar. Has Input and GUI.""" def __init__(self, activity, position, team, exitActivityCallback=None): PartyCogActivityPlayer.__init__(self, activity, base.localAvatar, position, team) self.input = PartyCogActivityInput(exitActivityCallback) self.gui = PartyCogActivityGui() self.throwPiePrevTime = 0 self.lastMoved = 0 if base.localAvatar: self.prevPos = base.localAvatar.getPos() self.cameraManager = None self.control = None # Used for throw-spam checking. self.consecutiveShortThrows = 0 def destroy(self): if self.enabled: self.disable() if self.cameraManager is not None: self.cameraManager.setEnabled(False) self.cameraManager.destroy() del self.cameraManager del self.gui del self.input if self.control is not None: self.control.destroy() del self.control PartyCogActivityPlayer.destroy(self) def _initOrthoWalk(self): orthoDrive = OrthoDrive( 9.778, # run speed = run frames (15) / fps (24fps) * avg. run speed (14.667 ft./s) customCollisionCallback=self.activity.view.checkOrthoDriveCollision ) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True) def _destroyOrthoWalk(self): self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk def getPieThrowingPower(self, time): elapsed = max(time - self.input.throwPiePressedStartTime, 0.0) # Convert CogActivityPowerMeterTime to periods/sec. for easier understanding of the tweak value. w = 1.0 / PartyGlobals.CogActivityPowerMeterTime * 2.0 * math.pi # Convert elapsed time into power integer in the range [0 100]. power = int(round(-math.cos(w * elapsed) * 50.0 + 50.0)) assert 0 <= power <= 100 return power def isShortThrow(self, time): """ Returns True if the throw button was held for a very short time. """ elapsed = max(time - self.input.throwPiePressedStartTime, 0.0) return elapsed <= PartyGlobals.CogActivityShortThrowTime def checkForThrowSpam(self, time): """ Returns True if the player appears to be spamming the throw button. It probably means that they don't understand the press and hold scheme. """ if self.isShortThrow(time): self.consecutiveShortThrows += 1 else: self.consecutiveShortThrows = 0 return self.consecutiveShortThrows >= PartyGlobals.CogActivityShortThrowSpam def _startUpdateTask(self): task = Task(self._updateTask) task.lastPositionBroadcastTime = 0.0 self.throwPiePrevTime = 0 taskMgr.add(task, UPDATE_TASK_NAME) def _stopUpdateTask(self): taskMgr.remove(UPDATE_TASK_NAME) def _updateTask(self, task): self._update() if base.localAvatar.getPos() != self.prevPos: self.prevPos = base.localAvatar.getPos() self.lastMoved = self.activity.getCurrentActivityTime() if max((self.activity.getCurrentActivityTime() - self.lastMoved), 0) > PartyGlobals.ToonMoveIdleThreshold: self.gui.showMoveControls() if max( (self.activity.getCurrentActivityTime() - self.throwPiePrevTime), 0) > PartyGlobals.ToonAttackIdleThreshold: self.gui.showAttackControls() if self.input.throwPieWasReleased: if self.checkForThrowSpam(globalClock.getFrameTime()): self.gui.showSpamWarning() self.input.throwPieWasReleased = False self.throwPie(self.getPieThrowingPower(globalClock.getFrameTime())) return Task.cont def throwPie(self, piePower): """Make the toon fire when the player presses the control key.""" if not self.activity.isState("Active"): return if self.activity.getCurrentActivityTime( ) - self.throwPiePrevTime > THROW_PIE_LIMIT_TIME: assert (self.activity.notify.debug("LocalPlayer throwPie %d" % piePower)) self.throwPiePrevTime = self.activity.getCurrentActivityTime() self.activity.b_pieThrow(self.toon, piePower) def _update(self): self.control.update() def getLookat(self, whosLooking, refNode=None): if refNode is None: refNode = render dist = 5.0 oldParent = self.tempNP.getParent() self.tempNP.reparentTo(whosLooking) self.tempNP.setPos(0.0, dist, 0.0) pos = self.tempNP.getPos(refNode) self.tempNP.reparentTo(oldParent) return pos def entersActivity(self): base.cr.playGame.getPlace().setState("activity") PartyCogActivityPlayer.entersActivity(self) self.gui.disableToontownHUD() self.cameraManager = CameraManager(camera) self.tempNP = NodePath("temp") self.lookAtMyTeam() self.control = StrafingControl(self) def exitsActivity(self): PartyCogActivityPlayer.exitsActivity(self) self.gui.enableToontownHUD() self.cameraManager.setEnabled(False) self.tempNP.removeNode() self.tempNP = None # Hacky: Don't enter walk state when reward GUI is visible. (Reward GUI 'ok' goes to walk.) # Mind that players can exit by hopping off, being booted when other players leave, or by # letting time run down (see reward screen). if not aspect2d.find("**/JellybeanRewardGui*"): base.cr.playGame.getPlace().setState("walk") else: # Simply start broadcasting the toon's position. self.toon.startPosHprBroadcast() def getRunToStartPositionIval(self): targetH = self.locator.getH() travelVec = self.position - self.toon.getPos(self.activity.root) duration = travelVec.length() / 9.778 startH = 0.0 if travelVec.getY() < 0.0: startH = 180.0 return Sequence( Func(self.toon.startPosHprBroadcast, 0.1), Func(self.toon.b_setAnimState, "run"), Parallel( self.toon.hprInterval( 0.5, VBase3(startH, 0.0, 0.0), other=self.activity.root, ), self.toon.posInterval(duration, self.position, other=self.activity.root), ), Func(self.toon.b_setAnimState, "neutral"), self.toon.hprInterval(0.25, VBase3(targetH, 0.0, 0.0), other=self.activity.root), Func(self.toon.stopPosHprBroadcast), ) def enable(self): if self.enabled: return PartyCogActivityPlayer.enable(self) self.toon.b_setAnimState("Happy") self._initOrthoWalk() self.orthoWalk.start() self.orthoWalking = True self.input.enable() self.gui.disableToontownHUD() self.gui.load() self.gui.setScore(0) self.gui.showScore() self.gui.setTeam(self.team) self.gui.startTrackingCogs(self.activity.view.cogManager.cogs) self.control.enable() self._startUpdateTask() def disable(self): if not self.enabled: return self._stopUpdateTask() self.toon.b_setAnimState("neutral") PartyCogActivityPlayer.disable(self) self.orthoWalking = False self.orthoWalk.stop() self._destroyOrthoWalk() self.input.disable() self._aimMode = False self.cameraManager.setEnabled(False) self.gui.hide() self.gui.stopTrackingCogs() self.gui.unload() def updateScore(self): self.gui.setScore(self.score) def b_updateToonPosition(self): self.updateToonPosition() self.d_updateToonPosition() def d_updateToonPosition(self): self.toon.d_setPos(self.toon.getX(), self.toon.getY(), self.toon.getZ()) self.toon.d_setH(self.toon.getH()) def lookAtArena(self): self.cameraManager.setEnabled(True) self.cameraManager.setTargetPos( self.activity.view.arena.find( "**/conclusionCamPos_locator").getPos(render)) self.cameraManager.setTargetLookAtPos( self.activity.view.arena.find( "**/conclusionCamAim_locator").getPos(render)) def lookAtMyTeam(self): activityView = self.activity.view arena = activityView.arena pos = activityView.teamCamPosLocators[self.team].getPos() aim = activityView.teamCamAimLocators[self.team].getPos() camera.wrtReparentTo(arena) self.cameraManager.setPos(camera.getPos(render)) self.tempNP.reparentTo(arena) self.tempNP.setPos(arena, pos) self.cameraManager.setTargetPos(self.tempNP.getPos(render)) self.cameraManager.setLookAtPos(self.getLookat(camera)) self.tempNP.reparentTo(arena) self.tempNP.setPos(arena, aim) self.cameraManager.setTargetLookAtPos(self.tempNP.getPos(render)) self.cameraManager.setEnabled(True) camera.setP(0.0) camera.setR(0.0)
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ( (levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]), ) self._lookAtZ = self._toon.getHeight( ) + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt=0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / ( maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[ 1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E**(dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr( smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if np not in nodesInBetween: nodesInBetween[np] = np.getParent() for np in list(nodesInBetween.keys()): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: np.find('**/*Floor').hide() for np, parent in list(self._betweenCamAndToon.items()): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween
class CameraManager: nextID = 0 def __init__(self, cameraNP): self.cameraNP = cameraNP self.id = CameraManager.nextID CameraManager.nextID += 1 self.otherNP = render self.lookAtNP = NodePath("CameraManager%d.lookAtNP" % self.id) self.lookAtEnabled = False self.targetPos = Point3(0.0, 0.0, 0.0) self.targetLookAtPos = Point3(0.0, 1.0, 0.0) self.enabled = False self.rate = 10.0 def destroy(self): if self.enabled: self.setEnabled(False) self.lookAtNP.removeNode() del self.lookAtNP del self.targetPos del self.targetLookAtPos del self.otherNP def setEnabled(self, enabled): if enabled != self.enabled: if enabled: taskMgr.add(self.updateTask, "CameraManager%d.update" % self.id) else: taskMgr.remove("CameraManager%d.update" % self.id) self.enabled = enabled def setTargetPos(self, p): self.targetPos = p def setPos(self, p): self.targetPos = p self.cameraNP.setPos(self.otherNP, p) def setTargetLookAtPos(self, p): self.lookAtEnabled = True self.targetLookAtPos = p def setLookAtPos(self, p): self.lookAtEnabled = True self.targetLookAtPos = p self.lookAtNP.setPos(p) def setHpr(self, hpr): self.lookAtEnabled = False self.cameraNP.setHpr(self.otherNP, hpr) def updateTask(self, task): # position newCameraPos = self.rateInterpolate(self.cameraNP.getPos(self.otherNP), self.targetPos) self.cameraNP.setPos(self.otherNP, newCameraPos) # look at if self.lookAtEnabled: newLookAtPos = self.rateInterpolate( self.lookAtNP.getPos(self.otherNP), self.targetLookAtPos) self.lookAtNP.setPos(self.otherNP, newLookAtPos) self.cameraNP.lookAt(self.lookAtNP) return task.cont def rateInterpolate(self, currentPos, targetPos): dt = globalClock.getDt() vec = currentPos - targetPos return targetPos + vec * (inverse_e**(dt * self.rate))