264 lines
12 KiB
Python
264 lines
12 KiB
Python
from pandac.PandaModules import Point3, VBase4
|
|
from direct.fsm.FSM import FSM
|
|
from direct.interval.IntervalGlobal import Sequence, Parallel, ActorInterval, Func, Wait, ParticleInterval, Track, LerpColorScaleInterval, LerpScaleInterval, LerpHprInterval
|
|
from direct.task.Task import Task
|
|
from toontown.battle import BattleParticles
|
|
from toontown.battle import MovieUtil
|
|
from toontown.minigame.MazeSuit import MazeSuit
|
|
from CogdoMazeGameObjects import CogdoMazeSplattable
|
|
import CogdoMazeGameGlobals as Globals
|
|
import random
|
|
|
|
class CogdoMazeSuit(MazeSuit, FSM, CogdoMazeSplattable):
|
|
GagHitEventName = 'CogdoMazeSuit_GagHit'
|
|
DeathEventName = 'CogdoMazeSuit_Death'
|
|
ThinkEventName = 'CogdoMazeSuit_Think'
|
|
|
|
def __init__(self, serialNum, maze, randomNumGen, difficulty, startTile, cogdoSuitType, walkAnimName = None):
|
|
data = Globals.SuitData[cogdoSuitType]
|
|
MazeSuit.__init__(self, serialNum, maze, randomNumGen, data['cellWalkPeriod'], difficulty, data['dnaName'], startTile=startTile, walkSameDirectionProb=Globals.SuitWalkSameDirectionProb, walkTurnAroundProb=Globals.SuitWalkTurnAroundProb, uniqueRandomNumGen=False, walkAnimName=walkAnimName)
|
|
FSM.__init__(self, 'CogdoMazeSuit')
|
|
CogdoMazeSplattable.__init__(self, self.suit, '%s-%i' % (Globals.SuitCollisionName, self.serialNum), 1.5)
|
|
if data.has_key('scale'):
|
|
self.suit.setScale(data['scale'])
|
|
self.hp = data['hp']
|
|
self.type = cogdoSuitType
|
|
self.memos = data['memos']
|
|
self.deathSuit = self.suit.getLoseActor()
|
|
self.deathSuit.pose('lose', 0)
|
|
BattleParticles.loadParticles()
|
|
self._initSfx()
|
|
|
|
def _initSfx(self):
|
|
audioMgr = base.cogdoGameAudioMgr
|
|
self._deathSoundIval = Sequence(audioMgr.createSfxIval('cogSpin', duration=1.6, startTime=0.6, volume=0.8, source=self.deathSuit), audioMgr.createSfxIval('cogDeath', volume=0.32, source=self.deathSuit))
|
|
|
|
def _destroySfx(self):
|
|
if self._deathSoundIval.isPlaying():
|
|
self._deathSoundIval.finish()
|
|
del self._deathSoundIval
|
|
|
|
def destroy(self):
|
|
BattleParticles.unloadParticles()
|
|
self.ignoreAll()
|
|
self._destroySfx()
|
|
CogdoMazeSplattable.destroy(self)
|
|
MazeSuit.destroy(self)
|
|
|
|
def handleEnterSphere(self, collEntry):
|
|
messenger.send(self.COLLISION_EVENT_NAME, [self.type, self.serialNum])
|
|
|
|
def gameStart(self, gameStartTime):
|
|
MazeSuit.gameStart(self, gameStartTime)
|
|
self.accept(Globals.GagCollisionName + '-into-' + self.gagCollisionName, self.handleGagHit)
|
|
messenger.send(self.ThinkEventName, [self, self.TX, self.TY])
|
|
|
|
def initCollisions(self):
|
|
MazeSuit.initCollisions(self)
|
|
self.collNodePath.setScale(0.75)
|
|
self.accept(self.uniqueName('again' + self.COLL_SPHERE_NAME), self.handleEnterSphere)
|
|
|
|
def think(self, curTic, curT, unwalkables):
|
|
MazeSuit.think(self, curTic, curT, unwalkables)
|
|
messenger.send(self.ThinkEventName, [self, self.TX, self.TY])
|
|
|
|
def handleGagHit(self, collEntry):
|
|
gagNodePath = collEntry.getFromNodePath().getParent()
|
|
messenger.send(self.GagHitEventName, [self.type, self.serialNum, gagNodePath])
|
|
|
|
def _getSuitAnimationIval(self, animName, startFrame = 0, duration = 1, partName = None, nextState = None):
|
|
totalFrames = self.suit.getNumFrames(animName)
|
|
frames = totalFrames - 1 - startFrame
|
|
frameRate = self.suit.getFrameRate(animName)
|
|
newRate = frames / duration
|
|
playRate = newRate / frameRate
|
|
ival = Sequence(ActorInterval(self.suit, animName, startTime=startFrame / newRate, endTime=totalFrames / newRate, playRate=playRate, partName=partName))
|
|
if nextState is not None:
|
|
|
|
def done():
|
|
self.request(nextState)
|
|
|
|
ival.append(Func(done))
|
|
return ival
|
|
|
|
def hitByGag(self):
|
|
self.hp = self.hp - 1
|
|
self.doSplat()
|
|
if self.hp <= 0:
|
|
self.explode()
|
|
|
|
def explode(self):
|
|
self.doDeathTrack()
|
|
messenger.send(self.DeathEventName, [self.type, self.serialNum])
|
|
|
|
def doDeathTrack(self):
|
|
|
|
def removeDeathSuit(suit, deathSuit):
|
|
if not deathSuit.isEmpty():
|
|
deathSuit.detachNode()
|
|
suit.cleanupLoseActor()
|
|
|
|
self.deathSuit.reparentTo(self.suit.getParent())
|
|
self.deathSuit.setScale(self.suit.getScale())
|
|
self.deathSuit.setPos(render, self.suit.getPos(render))
|
|
self.deathSuit.setHpr(render, self.suit.getHpr(render))
|
|
self.suit.hide()
|
|
self.collNodePath.reparentTo(self.deathSuit)
|
|
gearPoint = Point3(0, 0, self.suit.height / 2.0 + 2.0)
|
|
smallGears = BattleParticles.createParticleEffect(file='gearExplosionSmall')
|
|
singleGear = BattleParticles.createParticleEffect('GearExplosion', numParticles=1)
|
|
smallGearExplosion = BattleParticles.createParticleEffect('GearExplosion', numParticles=10)
|
|
bigGearExplosion = BattleParticles.createParticleEffect('BigGearExplosion', numParticles=30)
|
|
smallGears.setPos(gearPoint)
|
|
singleGear.setPos(gearPoint)
|
|
smallGearExplosion.setPos(gearPoint)
|
|
bigGearExplosion.setPos(gearPoint)
|
|
smallGears.setDepthWrite(False)
|
|
singleGear.setDepthWrite(False)
|
|
smallGearExplosion.setDepthWrite(False)
|
|
bigGearExplosion.setDepthWrite(False)
|
|
suitTrack = Sequence(Func(self.collNodePath.stash), ActorInterval(self.deathSuit, 'lose', startFrame=80, endFrame=140), Func(removeDeathSuit, self.suit, self.deathSuit, name='remove-death-suit'))
|
|
explosionTrack = Sequence(Wait(1.5), MovieUtil.createKapowExplosionTrack(self.deathSuit, explosionPoint=gearPoint))
|
|
gears1Track = Sequence(ParticleInterval(smallGears, self.deathSuit, worldRelative=0, duration=4.3, cleanup=True), name='gears1Track')
|
|
gears2MTrack = Track((0.0, explosionTrack), (0.7, ParticleInterval(singleGear, self.deathSuit, worldRelative=0, duration=5.7, cleanup=True)), (5.2, ParticleInterval(smallGearExplosion, self.deathSuit, worldRelative=0, duration=1.2, cleanup=True)), (5.4, ParticleInterval(bigGearExplosion, self.deathSuit, worldRelative=0, duration=1.0, cleanup=True)), name='gears2MTrack')
|
|
|
|
def removeParticle(particle):
|
|
if particle and hasattr(particle, 'renderParent'):
|
|
particle.cleanup()
|
|
del particle
|
|
|
|
removeParticles = Sequence(Func(removeParticle, smallGears), Func(removeParticle, singleGear), Func(removeParticle, smallGearExplosion), Func(removeParticle, bigGearExplosion))
|
|
self.deathTrack = Sequence(Parallel(suitTrack, gears2MTrack, gears1Track, self._deathSoundIval), removeParticles)
|
|
self.deathTrack.start()
|
|
|
|
|
|
class CogdoMazeSlowMinionSuit(CogdoMazeSuit):
|
|
|
|
def __init__(self, serialNum, maze, randomNumGen, difficulty, startTile = None):
|
|
CogdoMazeSuit.__init__(self, serialNum, maze, randomNumGen, difficulty, startTile, Globals.SuitTypes.SlowMinion)
|
|
self.defaultTransitions = {'Off': ['Normal'],
|
|
'Normal': ['Attack', 'Off'],
|
|
'Attack': ['Normal']}
|
|
|
|
def gameStart(self, gameStartTime):
|
|
CogdoMazeSuit.gameStart(self, gameStartTime)
|
|
self.request('Normal')
|
|
|
|
def enterNormal(self):
|
|
self.startWalkAnim()
|
|
|
|
def exitNormal(self):
|
|
pass
|
|
|
|
def enterAttack(self, elapsedTime):
|
|
self._attackIval = self._getSuitAnimationIval('finger-wag', duration=2.0, nextState='Normal')
|
|
self._attackIval.start(elapsedTime)
|
|
|
|
def filterAttack(self, request, args):
|
|
if request == 'Attack':
|
|
return None
|
|
else:
|
|
return self.defaultFilter(request, args)
|
|
return None
|
|
|
|
def exitAttack(self):
|
|
self._attackIval.pause()
|
|
del self._attackIval
|
|
|
|
|
|
class CogdoMazeFastMinionSuit(CogdoMazeSuit):
|
|
|
|
def __init__(self, serialNum, maze, randomNumGen, difficulty, startTile = None):
|
|
CogdoMazeSuit.__init__(self, serialNum, maze, randomNumGen, difficulty, startTile, Globals.SuitTypes.FastMinion)
|
|
|
|
|
|
class CogdoMazeBossSuit(CogdoMazeSuit):
|
|
BlinkTaskName = 'CogdoMazeBossBlinkTask'
|
|
ShakeTaskName = 'CogdoMazeBossShakeTask'
|
|
StartWalkTaskName = 'CogdoMazeBossStartWalkTask'
|
|
ShakeEventName = 'CogdoMazeSuitShake'
|
|
|
|
def __init__(self, serialNum, maze, randomNumGen, difficulty, startTile = None):
|
|
CogdoMazeSuit.__init__(self, serialNum, maze, randomNumGen, difficulty, startTile, Globals.SuitTypes.Boss, walkAnimName='stomp')
|
|
self.dropTimer = 0
|
|
self._walkSpeed = float(self.maze.cellWidth) / self.cellWalkDuration * 0.5
|
|
|
|
def _initSfx(self):
|
|
CogdoMazeSuit._initSfx(self)
|
|
audioMgr = base.cogdoGameAudioMgr
|
|
self._stompSfxIval = audioMgr.createSfxIval('cogStomp', source=self.suit, cutoff=Globals.BossStompSfxCutoff, volume=0.3)
|
|
self._hitSfx = audioMgr.createSfx('bossCogAngry', self.suit)
|
|
|
|
def _destroySfx(self):
|
|
del self._hitSfx
|
|
if self._stompSfxIval.isPlaying():
|
|
self._stompSfxIval.finish()
|
|
del self._stompSfxIval
|
|
CogdoMazeSuit._destroySfx(self)
|
|
|
|
def spin(self):
|
|
part = self.suit
|
|
time = Globals.BossSpinTime
|
|
degrees = 360 * Globals.BossSpinCount
|
|
spinIval = LerpHprInterval(part, time, (self.suit.getH() + degrees, 0, 0), blendType='easeOut')
|
|
spinIval.start()
|
|
|
|
def hitByGag(self):
|
|
if self.hp >= 2:
|
|
self._hitSfx.play()
|
|
self.spin()
|
|
self.suit.setColorScale(Globals.BlinkColor)
|
|
self.__startBlinkTask()
|
|
elif self.hp == 1:
|
|
self.__stopBlinkTask()
|
|
CogdoMazeSuit.hitByGag(self)
|
|
|
|
def gameStart(self, gameStartTime):
|
|
CogdoMazeSuit.gameStart(self, gameStartTime)
|
|
|
|
def startWalkAnim(self):
|
|
self.suit.loop(self._walkAnimName, fromFrame=43, toFrame=81)
|
|
self.suit.setPlayRate(self._walkSpeed * Globals.BossCogStompAnimationPlayrateFactor, self._walkAnimName)
|
|
self.__startShakeTask()
|
|
|
|
def destroy(self):
|
|
CogdoMazeSuit.destroy(self)
|
|
self.__stopShakeTask()
|
|
self.__stopBlinkTask()
|
|
|
|
def pickRandomValidSpot(self, r = 5):
|
|
validSpots = []
|
|
for x in range(self.TX - r, self.TX + r):
|
|
for y in range(self.TY - r, self.TY + r):
|
|
if self.maze.isWalkable(x, y):
|
|
validSpots.append([x, y])
|
|
|
|
return self.rng.choice(validSpots)
|
|
|
|
def __startShakeTask(self):
|
|
self.__stopShakeTask()
|
|
taskMgr.doMethodLater(Globals.BossShakeTime, self.__shake, self.uniqueName(CogdoMazeBossSuit.ShakeTaskName))
|
|
self.bossShakeLastTime = 0
|
|
|
|
def __stopShakeTask(self):
|
|
taskMgr.remove(self.uniqueName(CogdoMazeBossSuit.ShakeTaskName))
|
|
|
|
def __shake(self, task):
|
|
if task.time - self.bossShakeLastTime > Globals.BossShakeTime:
|
|
self.suit.setPlayRate(self._walkSpeed * Globals.BossCogStompAnimationPlayrateFactor, self._walkAnimName)
|
|
self._stompSfxIval.start()
|
|
messenger.send(self.ShakeEventName, [self, Globals.BossShakeStrength])
|
|
self.bossShakeLastTime = task.time
|
|
return task.cont
|
|
|
|
def __startBlinkTask(self):
|
|
self.__stopBlinkTask()
|
|
taskMgr.doMethodLater(Globals.BlinkFrequency, self.__blink, CogdoMazeBossSuit.BlinkTaskName)
|
|
|
|
def __stopBlinkTask(self):
|
|
taskMgr.remove(CogdoMazeBossSuit.BlinkTaskName)
|
|
|
|
def __blink(self, task):
|
|
blink = Sequence(LerpColorScaleInterval(self.suit, Globals.BlinkSpeed, VBase4(1.0, 1.0, 1.0, 1.0)), LerpColorScaleInterval(self.suit, Globals.BlinkSpeed, Globals.BlinkColor))
|
|
blink.start()
|
|
return Task.again
|