import random from pandac.PandaModules import * from direct.interval.IntervalGlobal import Sequence, Func, Parallel, Wait, LerpHprInterval, LerpScaleInterval, LerpFunctionInterval from otp.otpbase import OTPGlobals from toontown.toonbase import ToontownGlobals from CogdoGameGatherable import CogdoGameGatherable, CogdoMemo import CogdoFlyingGameGlobals as Globals import CogdoUtil from direct.particles import ParticleEffect from direct.particles import Particles from direct.particles import ForceGroup class CogdoFlyingGatherableFactory: def __init__(self): self._serialNum = -1 self._memoModel = CogdoUtil.loadModel('memo', 'shared').find('**/memo') self._propellerModel = CogdoUtil.loadFlyingModel('propellers').find('**/mesh') self._powerUpModels = {} for type, modelName in Globals.Level.PowerupType2Model.items(): model = CogdoUtil.loadFlyingModel(modelName).find('**/' + Globals.Level.PowerupType2Node[type]) self._powerUpModels[type] = model model.setTransparency(True) model.setScale(0.5) def createMemo(self): self._serialNum += 1 return CogdoFlyingMemo(self._serialNum, self._memoModel) def createPropeller(self): self._serialNum += 1 return CogdoFlyingPropeller(self._serialNum, self._propellerModel) def createPowerup(self, type): self._serialNum += 1 return CogdoFlyingPowerup(self._serialNum, type, self._powerUpModels[type]) def createSparkles(self, color1, color2, amp): self.f = ParticleEffect.ParticleEffect('particleEffect_sparkles') p0 = Particles.Particles('particles-1') p0.setFactory('PointParticleFactory') p0.setRenderer('SparkleParticleRenderer') p0.setEmitter('RingEmitter') p0.setPoolSize(15) p0.setBirthRate(0.1) p0.setLitterSize(100) p0.setLitterSpread(0) p0.factory.setLifespanBase(0.6) p0.factory.setLifespanSpread(0.1) p0.factory.setMassBase(1.0) p0.factory.setMassSpread(0.0) p0.factory.setTerminalVelocityBase(3.0) p0.factory.setTerminalVelocitySpread(1.0) p0.renderer.setAlphaMode(BaseParticleRenderer.PRALPHAOUT) p0.renderer.setUserAlpha(1.0) p0.renderer.setCenterColor(color1) p0.renderer.setEdgeColor(color2) p0.renderer.setBirthRadius(0.3) p0.renderer.setDeathRadius(0.3) p0.renderer.setLifeScale(SparkleParticleRenderer.SPNOSCALE) p0.emitter.setEmissionType(BaseParticleEmitter.ETRADIATE) p0.emitter.setAmplitude(0) p0.emitter.setAmplitudeSpread(0) f0 = ForceGroup.ForceGroup('Gravity') force0 = LinearVectorForce(Vec3(0.0, 0.0, -10.0), 1.0, 0) force0.setVectorMasks(1, 1, 1) force0.setActive(1) f0.addForce(force0) self.f.addForceGroup(f0) p0.emitter.setRadius(2.0) self.f.addParticles(p0) self.f.setPos(0, 0, 0) self.f.setHpr(0, random.random() * 180, random.random() * 180) return self.f def destroy(self): self._memoModel.removeNode() del self._memoModel self._propellerModel.removeNode() del self._propellerModel for model in self._powerUpModels.values(): model.removeNode() del self._powerUpModels if Globals.Level.AddSparkleToPowerups: self.f.cleanup() del self.f class CogdoFlyingGatherableBase: def __init__(self, type): self.type = type self.initFlash() def initFlash(self): model = CogdoUtil.loadFlyingModel('gatherableFlash_card') texName = Globals.Level.GatherableType2TextureName[self.type] tex = model.findTexture(texName) tex.setWrapU(Texture.WMRepeat) tex.setWrapV(Texture.WMRepeat) del model self.ts = TextureStage('ts') self.ts.setMode(TextureStage.MCombine) self.ts.setSort(1) self.ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSConstant, TextureStage.COSrcColor) self.ts.setCombineAlpha(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcAlpha, TextureStage.CSTexture, TextureStage.COSrcAlpha, TextureStage.CSConstant, TextureStage.COSrcAlpha) self._model.setTexture(self.ts, tex) dur = Globals.Gameplay.GatherableFlashTime self.flashLoop = Sequence(LerpFunctionInterval(self.setTextureAlphaFunc, fromData=1.0, toData=0.25, duration=dur / 2.0, blendType='easeInOut'), LerpFunctionInterval(self.setTextureAlphaFunc, fromData=0.25, toData=1.0, duration=dur / 2.0, blendType='easeInOut'), Wait(1.0), name='%s.flashLoop-%s' % (self.__class__.__name__, self.serialNum)) def show(self): self.enableFlash() def hide(self): self.disableFlash() def enable(self): pass def disable(self): pass def enableFlash(self): self.flashLoop.loop() def disableFlash(self): self.flashLoop.clearToInitial() def destroy(self): self.disableFlash() del self.flashLoop del self.ts def setTextureAlphaFunc(self, value): self.ts.setColor(Vec4(value, value, value, value)) def isPowerUp(self): return False class CogdoFlyingGatherable(CogdoGameGatherable, CogdoFlyingGatherableBase): def __init__(self, type, serialNum, modelToInstance, triggerRadius, animate = True): CogdoGameGatherable.__init__(self, serialNum, modelToInstance, triggerRadius, animate=animate) CogdoFlyingGatherableBase.__init__(self, type) def enable(self): CogdoGameGatherable.enable(self) CogdoFlyingGatherableBase.enable(self) def disable(self): CogdoGameGatherable.disable(self) CogdoFlyingGatherableBase.disable(self) def show(self): CogdoGameGatherable.show(self) CogdoFlyingGatherableBase.show(self) def hide(self): CogdoGameGatherable.hide(self) CogdoFlyingGatherableBase.hide(self) def destroy(self): CogdoGameGatherable.destroy(self) CogdoFlyingGatherableBase.destroy(self) class CogdoFlyingMemo(CogdoFlyingGatherableBase, CogdoMemo): def __init__(self, serialNum, model): CogdoMemo.__init__(self, serialNum, triggerRadius=Globals.Gameplay.MemoCollisionRadius, spinRate=Globals.Gameplay.MemoSpinRate, model=model) CogdoFlyingGatherableBase.__init__(self, Globals.Level.GatherableTypes.Memo) self.floatTimer = 0.0 self.floatSpeed = 1.0 self.floatDuration = 2.0 def _handleEnterCollision(self, collEntry): CogdoGameGatherable._handleEnterCollision(self, collEntry) def enable(self): CogdoFlyingGatherableBase.enable(self) CogdoMemo.enable(self) def disable(self): CogdoFlyingGatherableBase.disable(self) CogdoMemo.disable(self) def show(self): CogdoFlyingGatherableBase.show(self) CogdoMemo.show(self) def hide(self): CogdoFlyingGatherableBase.hide(self) CogdoMemo.hide(self) def destroy(self): CogdoFlyingGatherableBase.destroy(self) CogdoMemo.destroy(self) def update(self, dt): self.floatTimer += dt if self.floatTimer < self.floatDuration: self.setPos(self.getPos() + Vec3(0, 0, dt * self.floatSpeed)) elif self.floatTimer < self.floatDuration * 2.0: self.setPos(self.getPos() - Vec3(0, 0, dt * self.floatSpeed)) else: self.floatTimer = 0.0 self.floatSpeed = random.uniform(0.5, 1.0) self.floatDuration = random.uniform(1.9, 2.1) class CogdoFlyingPowerup(CogdoFlyingGatherable): def __init__(self, serialNum, powerupType, model): self._pickedUpList = [] self._isToonLocal = False CogdoFlyingGatherable.__init__(self, powerupType, serialNum, model, Globals.Gameplay.MemoCollisionRadius) self.initInterval() def initInterval(self): bouncePercent = 1.2 scale = self._model.getScale() shrinkPowerupLerp = LerpScaleInterval(self._model, 0.5, 0.0, startScale=0.0, blendType='easeInOut') growPowerupLerp = LerpScaleInterval(self._model, 0.5, scale * bouncePercent, startScale=0.0, blendType='easeInOut') bouncePowerupLerp = LerpScaleInterval(self._model, 0.25, scale, startScale=scale * bouncePercent, blendType='easeInOut') self.pickUpSeq = Sequence(Func(self.updateLerpStartScale, shrinkPowerupLerp, self._model), shrinkPowerupLerp, Func(self.ghostPowerup), growPowerupLerp, bouncePowerupLerp, name='%s.pickUpSeq-%s' % (self.__class__.__name__, self.serialNum)) def isPowerUp(self): return True def updateLerpStartScale(self, lerp, nodepath): lerp.setStartScale(nodepath.getScale()) def wasPickedUpByToon(self, toon): if toon.doId in self._pickedUpList: return True return False def ghostPowerup(self): if self._isToonLocal: self._model.setAlphaScale(0.5) if Globals.Level.AddSparkleToPowerups: self.f = self.find('**/particleEffect_sparkles') if not self.f.isEmpty(): self.f.hide() def pickUp(self, toon, elapsedSeconds = 0.0): if self.wasPickedUpByToon(toon) == True: return self._pickedUpList.append(toon.doId) self._isToonLocal = toon.isLocal() if self._animate: self.pickUpSeq.clearToInitial() self.pickUpSeq.start() else: self.ghostPowerup() def destroy(self): del self._pickedUpList[:] self.pickUpSeq.clearToInitial() del self.pickUpSeq CogdoFlyingGatherable.destroy(self) def update(self, dt): self._model.setH(self._model.getH() + Globals.Gameplay.MemoSpinRate * dt) class CogdoFlyingPropeller(CogdoFlyingGatherable): def __init__(self, serialNum, model): CogdoFlyingGatherable.__init__(self, Globals.Level.GatherableTypes.Propeller, serialNum, model, Globals.Gameplay.PropellerCollisionRadius, animate=False) self.activePropellers = [] self.usedPropellers = [] propellers = self._model.findAllMatches('**/propeller*') for prop in propellers: self.activePropellers.append(prop) self.initIntervals() def initIntervals(self): self.animatedPropellerIval = Parallel(name='%s.object-%i-animatePropellerIval' % (self.__class__.__name__, self.serialNum)) for propeller in self.activePropellers: self.animatedPropellerIval.append(LerpHprInterval(propeller, duration=Globals.Level.PropellerSpinDuration, startHpr=Vec3(0.0, 0.0, 0.0), hpr=Vec3(360.0, 0.0, 0.0))) def show(self): self.animatedPropellerIval.loop() CogdoFlyingGatherable.show(self) def hide(self): self.animatedPropellerIval.clearToInitial() CogdoFlyingGatherable.hide(self) def destroy(self): taskMgr.removeTasksMatching('propeller-respawn-*') self.animatedPropellerIval.clearToInitial() del self.animatedPropellerIval CogdoFlyingGatherable.destroy(self) def pickUp(self, toon, elapsedSeconds = 0.0): prop = self.removePropeller() if prop != None: respawnTime = Globals.Gameplay.PropellerRespawnTime if elapsedSeconds < respawnTime: taskMgr.doMethodLater(respawnTime - elapsedSeconds, self.addPropeller, 'propeller-respawn-%i' % self.serialNum, extraArgs=[prop]) else: self.addPropeller(prop) else: self.disable() return def addPropeller(self, prop): if len(self.usedPropellers) > 0: if len(self.activePropellers) == 0: self.enable() self.usedPropellers.remove(prop) prop.show() self.activePropellers.append(prop) self._wasPickedUp = False def removePropeller(self): if len(self.activePropellers) > 0: prop = self.activePropellers.pop() prop.hide() self.usedPropellers.append(prop) if len(self.activePropellers) == 0: self._wasPickedUp = True return prop return None def isPropeller(self): if len(self.activePropellers) > 0: return True else: return False class CogdoFlyingLevelFog: def __init__(self, level, color = Globals.Level.FogColor): self._level = level self.color = color self.defaultFar = None fogDistance = self._level.quadLengthUnits * max(1, self._level.quadVisibiltyAhead * 0.2) self.fog = Fog('RenderFog') self.fog.setColor(self.color) self.fog.setLinearRange(fogDistance * Globals.Level.RenderFogStartFactor, fogDistance) self._visible = False self._clearColor = Vec4(base.win.getClearColor()) self._clearColor.setW(1.0) self.defaultFar = base.camLens.getFar() base.camLens.setFar(Globals.Camera.GameCameraFar) base.setBackgroundColor(self.color) def destroy(self): self.setVisible(False) if hasattr(self, 'fog'): del self.fog if self.defaultFar is not None: base.camLens.setFar(self.defaultFar) def isVisible(self): return self._visible def setVisible(self, visible): self._visible = visible if self._visible: base.win.setClearColor(self.color) render.setFog(self.fog) else: base.win.setClearColor(self._clearColor) render.clearFog() class CogdoFlyingPlatform: CeilingCollName = 'col_ceiling' FloorCollName = 'col_floor' def __init__(self, model, type = Globals.Level.PlatformTypes.Platform, parent = None): self._model = model self._type = type if parent is not None: self._model.reparentTo(parent) self._initCollisions() return def __str__(self): return '<%s model=%s, type=%s>' % (self.__class__.__name__, self._model, self._type) def destroy(self): self._floorColl.clearPythonTag('platform') self._model.removeNode() del self._model del self._type del self._floorColl del self._ceilingColl def onstage(self): self._model.unstash() def offstage(self): self._model.stash() def _initCollisions(self): self._floorColl = self._model.find('**/*%s' % CogdoFlyingPlatform.FloorCollName) self._floorColl.setName(CogdoFlyingPlatform.FloorCollName) self._floorColl.node().setIntoCollideMask(ToontownGlobals.FloorEventBitmask | OTPGlobals.FloorBitmask) self._floorColl.setPythonTag('platform', self) self._ceilingColl = self._model.find('**/*%s' % CogdoFlyingPlatform.CeilingCollName) self._ceilingColl.setName(CogdoFlyingPlatform.CeilingCollName) self._ceilingColl.node().setIntoCollideMask(ToontownGlobals.CeilingBitmask) def getType(self): return self._type def getName(self): return self._model.getName() def getModel(self): return self._model def isStartPlatform(self): return self._type == Globals.Level.PlatformTypes.StartPlatform def isEndPlatform(self): return self._type == Globals.Level.PlatformTypes.EndPlatform def isStartOrEndPlatform(self): return self.isStartPlatform() or self.isEndPlatform() def getSpawnPosForPlayer(self, playerNum, parent): offset = Globals.Level.PlatformType2SpawnOffset[self._type] spawnLoc = self._model.find('**/spawn_loc') x = (playerNum - 2.0) % 2 * offset y = (playerNum - 1.0) % 2 * offset if not spawnLoc.isEmpty(): spawnPos = spawnLoc.getPos(parent) + Vec3(x, y, 0.0) else: spawnPos = self._floorColl.getPos(parent) + Vec3(x, y, 0.0) return spawnPos @staticmethod def getFromNode(node): return node.getPythonTag('platform')