2015-03-03 16:10:12 -06:00
|
|
|
from direct.actor import Actor
|
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
|
|
from direct.fsm import FSM
|
|
|
|
from direct.fsm import State
|
|
|
|
from direct.interval.IntervalGlobal import *
|
|
|
|
from direct.showbase.PythonUtil import Functor
|
|
|
|
from direct.task.Task import Task
|
2015-06-23 18:11:48 -05:00
|
|
|
from panda3d.core import *
|
2015-03-03 16:10:12 -06:00
|
|
|
import string
|
|
|
|
import types
|
|
|
|
|
|
|
|
import Suit
|
|
|
|
import SuitDNA
|
|
|
|
from otp.avatar import Avatar
|
|
|
|
from toontown.battle import BattleParticles
|
|
|
|
from toontown.battle import BattleProps
|
|
|
|
from toontown.nametag import NametagGlobals
|
|
|
|
from toontown.toonbase import TTLocalizer
|
|
|
|
from toontown.toonbase import ToontownGlobals
|
|
|
|
|
|
|
|
|
|
|
|
GenericModel = 'phase_9/models/char/bossCog'
|
|
|
|
ModelDict = {'s': 'phase_9/models/char/sellbotBoss',
|
|
|
|
'm': 'phase_10/models/char/cashbotBoss',
|
|
|
|
'l': 'phase_11/models/char/lawbotBoss',
|
|
|
|
'c': 'phase_12/models/char/bossbotBoss'}
|
|
|
|
AnimList = ('Ff_speech', 'ltTurn2Wave', 'wave', 'Ff_lookRt', 'turn2Fb', 'Ff_neutral', 'Bb_neutral', 'Ff2Bb_spin', 'Bb2Ff_spin', 'Fb_neutral', 'Bf_neutral', 'Fb_firstHit', 'Fb_downNeutral', 'Fb_downHit', 'Fb_fall', 'Fb_down2Up', 'Fb_downLtSwing', 'Fb_downRtSwing', 'Fb_DownThrow', 'Fb_UpThrow', 'Fb_jump', 'golf_swing')
|
|
|
|
|
|
|
|
class BossCog(Avatar.Avatar):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('BossCog')
|
|
|
|
healthColors = Suit.Suit.healthColors
|
|
|
|
healthGlowColors = Suit.Suit.healthGlowColors
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
Avatar.Avatar.__init__(self)
|
|
|
|
self.setFont(ToontownGlobals.getSuitFont())
|
|
|
|
self.setPlayerType(NametagGlobals.CCSuit)
|
|
|
|
self.setPickable(0)
|
|
|
|
self.doorA = None
|
|
|
|
self.doorB = None
|
|
|
|
self.bubbleL = None
|
|
|
|
self.bubbleR = None
|
|
|
|
self.raised = 1
|
|
|
|
self.forward = 1
|
|
|
|
self.happy = 1
|
|
|
|
self.dizzy = 0
|
|
|
|
self.nowRaised = 1
|
|
|
|
self.nowForward = 1
|
|
|
|
self.nowHappy = 1
|
|
|
|
self.currentAnimIval = None
|
|
|
|
self.queuedAnimIvals = []
|
|
|
|
self.treadsLeftPos = 0
|
|
|
|
self.treadsRightPos = 0
|
|
|
|
self.healthBar = None
|
|
|
|
self.healthCondition = 0
|
|
|
|
self.animDoneEvent = 'BossCogAnimDone'
|
|
|
|
self.animIvalName = 'BossCogAnimIval'
|
|
|
|
return
|
|
|
|
|
|
|
|
def delete(self):
|
|
|
|
Avatar.Avatar.delete(self)
|
|
|
|
self.removeHealthBar()
|
|
|
|
self.setDizzy(0)
|
|
|
|
self.stopAnimate()
|
|
|
|
if self.doorA:
|
|
|
|
self.doorA.request('Off')
|
|
|
|
self.doorB.request('Off')
|
|
|
|
self.doorA = None
|
|
|
|
self.doorB = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def setDNAString(self, dnaString):
|
|
|
|
self.dna = SuitDNA.SuitDNA()
|
|
|
|
self.dna.makeFromNetString(dnaString)
|
|
|
|
self.setDNA(self.dna)
|
|
|
|
|
|
|
|
def setDNA(self, dna):
|
|
|
|
if self.style:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
self.style = dna
|
|
|
|
self.generateBossCog()
|
|
|
|
self.initializeDropShadow()
|
|
|
|
if base.wantNametags:
|
|
|
|
self.initializeNametag3d()
|
|
|
|
|
|
|
|
def generateBossCog(self):
|
|
|
|
self.throwSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_frisbee_gears.ogg')
|
|
|
|
self.swingSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_swipe.ogg')
|
|
|
|
self.spinSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_spin.ogg')
|
|
|
|
self.rainGearsSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_raining_gears.ogg')
|
|
|
|
self.swishSfx = loader.loadSfx('phase_5/audio/sfx/General_throw_miss.ogg')
|
|
|
|
self.boomSfx = loader.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.ogg')
|
|
|
|
self.deathSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_big_death.ogg')
|
|
|
|
self.upSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_raise_up.ogg')
|
|
|
|
self.downSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_collapse.ogg')
|
|
|
|
self.reelSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_reeling_backwards.ogg')
|
|
|
|
self.birdsSfx = loader.loadSfx('phase_4/audio/sfx/SZ_TC_bird1.ogg')
|
|
|
|
self.dizzyAlert = loader.loadSfx('phase_5/audio/sfx/AA_sound_aoogah.ogg')
|
|
|
|
self.grunt = loader.loadSfx('phase_9/audio/sfx/Boss_COG_VO_grunt.ogg')
|
|
|
|
self.murmur = loader.loadSfx('phase_9/audio/sfx/Boss_COG_VO_murmur.ogg')
|
|
|
|
self.statement = loader.loadSfx('phase_9/audio/sfx/Boss_COG_VO_statement.ogg')
|
|
|
|
self.question = loader.loadSfx('phase_9/audio/sfx/Boss_COG_VO_question.ogg')
|
|
|
|
self.dialogArray = [self.grunt,
|
|
|
|
self.murmur,
|
|
|
|
self.statement,
|
|
|
|
self.question,
|
|
|
|
self.statement,
|
|
|
|
self.statement]
|
|
|
|
dna = self.style
|
|
|
|
filePrefix = ModelDict[dna.dept]
|
|
|
|
self.loadModel(GenericModel + '-legs-zero', 'legs')
|
|
|
|
self.loadModel(filePrefix + '-torso-zero', 'torso')
|
|
|
|
self.loadModel(filePrefix + '-head-zero', 'head')
|
|
|
|
self.twoFaced = dna.dept == 's'
|
|
|
|
self.attach('head', 'torso', 'joint34')
|
|
|
|
self.attach('torso', 'legs', 'joint_pelvis')
|
|
|
|
self.rotateNode = self.attachNewNode('rotate')
|
|
|
|
geomNode = self.getGeomNode()
|
|
|
|
geomNode.reparentTo(self.rotateNode)
|
|
|
|
self.frontAttack = self.rotateNode.attachNewNode('frontAttack')
|
|
|
|
self.frontAttack.setPos(0, -10, 10)
|
|
|
|
self.frontAttack.setScale(2)
|
|
|
|
self.setHeight(26)
|
|
|
|
self.nametag3d.setScale(2)
|
|
|
|
for partName in ('legs', 'torso', 'head'):
|
|
|
|
animDict = {}
|
|
|
|
for anim in AnimList:
|
|
|
|
animDict[anim] = '%s-%s-%s' % (GenericModel, partName, anim)
|
|
|
|
|
|
|
|
self.loadAnims(animDict, partName)
|
|
|
|
|
|
|
|
self.stars = BattleProps.globalPropPool.getProp('stun')
|
|
|
|
self.stars.setPosHprScale(7, 0, 0, 0, 0, -90, 3, 3, 3)
|
|
|
|
self.stars.loop('stun')
|
|
|
|
self.pelvis = self.getPart('torso')
|
|
|
|
self.pelvisForwardHpr = VBase3(0, 0, 0)
|
|
|
|
self.pelvisReversedHpr = VBase3(-180, 0, 0)
|
|
|
|
self.neck = self.getPart('head')
|
|
|
|
self.neckForwardHpr = VBase3(0, 0, 0)
|
|
|
|
self.neckReversedHpr = VBase3(0, -540, 0)
|
|
|
|
self.axle = self.find('**/joint_axle')
|
|
|
|
self.doorA = self.__setupDoor('**/joint_doorFront', 'doorA', self.doorACallback, VBase3(0, 0, 0), VBase3(0, 0, -80), CollisionPolygon(Point3(5, -4, 0.32), Point3(0, -4, 0), Point3(0, 4, 0), Point3(5, 4, 0.32)))
|
|
|
|
self.doorB = self.__setupDoor('**/joint_doorRear', 'doorB', self.doorBCallback, VBase3(0, 0, 0), VBase3(0, 0, 80), CollisionPolygon(Point3(-5, 4, 0.84), Point3(0, 4, 0), Point3(0, -4, 0), Point3(-5, -4, 0.84)))
|
|
|
|
treadsModel = loader.loadModel('%s-treads' % GenericModel)
|
|
|
|
treadsModel.reparentTo(self.axle)
|
|
|
|
self.treadsLeft = treadsModel.find('**/right_tread')
|
|
|
|
self.treadsRight = treadsModel.find('**/left_tread')
|
|
|
|
self.doorA.request('Closed')
|
|
|
|
self.doorB.request('Closed')
|
|
|
|
|
|
|
|
def initializeBodyCollisions(self, collIdStr):
|
|
|
|
Avatar.Avatar.initializeBodyCollisions(self, collIdStr)
|
|
|
|
if not self.ghostMode:
|
|
|
|
self.collNode.setCollideMask(self.collNode.getIntoCollideMask() | ToontownGlobals.PieBitmask)
|
|
|
|
|
|
|
|
def generateHealthBar(self):
|
|
|
|
self.removeHealthBar()
|
|
|
|
chestNull = self.find('**/joint_lifeMeter')
|
|
|
|
if chestNull.isEmpty():
|
|
|
|
return
|
|
|
|
model = loader.loadModel('phase_3.5/models/gui/matching_game_gui')
|
|
|
|
button = model.find('**/minnieCircle')
|
|
|
|
button.setScale(6.0)
|
|
|
|
button.setP(-20)
|
|
|
|
button.setColor(self.healthColors[0])
|
|
|
|
button.reparentTo(chestNull)
|
|
|
|
self.healthBar = button
|
|
|
|
glow = BattleProps.globalPropPool.getProp('glow')
|
|
|
|
glow.reparentTo(self.healthBar)
|
|
|
|
glow.setScale(0.28)
|
|
|
|
glow.setPos(-0.005, 0.01, 0.015)
|
|
|
|
glow.setColor(self.healthGlowColors[0])
|
|
|
|
button.flattenLight()
|
|
|
|
self.healthBarGlow = glow
|
|
|
|
self.healthCondition = 0
|
|
|
|
|
|
|
|
def updateHealthBar(self):
|
|
|
|
if self.healthBar == None:
|
|
|
|
return
|
|
|
|
health = 1.0 - float(self.bossDamage) / float(self.bossMaxDamage)
|
|
|
|
if health > 0.95:
|
|
|
|
condition = 0
|
2015-03-29 14:05:19 -05:00
|
|
|
elif health > 0.9:
|
2015-03-03 16:10:12 -06:00
|
|
|
condition = 1
|
2015-03-29 14:05:19 -05:00
|
|
|
elif health > 0.8:
|
2015-03-03 16:10:12 -06:00
|
|
|
condition = 2
|
2015-03-29 14:05:19 -05:00
|
|
|
elif health > 0.7:
|
|
|
|
condition = 3#Yellow
|
|
|
|
elif health > 0.6:
|
2015-06-16 12:26:44 -05:00
|
|
|
condition = 4
|
2015-03-29 14:05:19 -05:00
|
|
|
elif health > 0.5:
|
2015-06-16 12:26:44 -05:00
|
|
|
condition = 5
|
2015-03-29 14:05:19 -05:00
|
|
|
elif health > 0.3:
|
|
|
|
condition = 6#Orange
|
|
|
|
elif health > 0.15:
|
|
|
|
condition = 7
|
2015-03-03 16:10:12 -06:00
|
|
|
elif health > 0.05:
|
2015-06-16 12:26:44 -05:00
|
|
|
condition = 8#Red
|
2015-03-03 16:10:12 -06:00
|
|
|
elif health > 0.0:
|
2015-03-29 14:05:19 -05:00
|
|
|
condition = 9#Blinking Red
|
2015-03-03 16:10:12 -06:00
|
|
|
else:
|
2015-03-29 14:05:19 -05:00
|
|
|
condition = 10
|
2015-03-03 16:10:12 -06:00
|
|
|
if self.healthCondition != condition:
|
2015-03-29 14:05:19 -05:00
|
|
|
if condition == 9:
|
2015-03-03 16:10:12 -06:00
|
|
|
blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.75), Task(self.__blinkGray), Task.pause(0.1))
|
|
|
|
taskMgr.add(blinkTask, self.uniqueName('blink-task'))
|
2015-03-29 14:05:19 -05:00
|
|
|
elif condition == 10:
|
|
|
|
if self.healthCondition == 9:
|
2015-03-03 16:10:12 -06:00
|
|
|
taskMgr.remove(self.uniqueName('blink-task'))
|
|
|
|
blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.25), Task(self.__blinkGray), Task.pause(0.1))
|
|
|
|
taskMgr.add(blinkTask, self.uniqueName('blink-task'))
|
|
|
|
else:
|
|
|
|
self.healthBar.setColor(self.healthColors[condition], 1)
|
|
|
|
self.healthBarGlow.setColor(self.healthGlowColors[condition], 1)
|
|
|
|
self.healthCondition = condition
|
2015-06-16 12:26:44 -05:00
|
|
|
|
2015-03-03 16:10:12 -06:00
|
|
|
def __blinkRed(self, task):
|
2015-03-29 14:05:19 -05:00
|
|
|
if not self.healthBar:
|
2015-06-16 12:26:44 -05:00
|
|
|
return
|
2015-03-29 14:05:19 -05:00
|
|
|
self.healthBar.setColor(self.healthColors[8], 1)
|
|
|
|
self.healthBarGlow.setColor(self.healthGlowColors[8], 1)
|
|
|
|
if self.healthCondition == 10:
|
2015-03-03 16:10:12 -06:00
|
|
|
self.healthBar.setScale(1.17)
|
|
|
|
return Task.done
|
|
|
|
|
|
|
|
def __blinkGray(self, task):
|
2015-03-29 14:05:19 -05:00
|
|
|
if not self.healthBar:
|
|
|
|
return
|
|
|
|
self.healthBar.setColor(self.healthColors[9], 1)
|
|
|
|
self.healthBarGlow.setColor(self.healthGlowColors[9], 1)
|
|
|
|
if self.healthCondition == 10:
|
2015-03-03 16:10:12 -06:00
|
|
|
self.healthBar.setScale(1.0)
|
|
|
|
return Task.done
|
|
|
|
|
|
|
|
def removeHealthBar(self):
|
|
|
|
if self.healthBar:
|
|
|
|
self.healthBar.removeNode()
|
|
|
|
self.healthBar = None
|
2015-03-29 14:05:19 -05:00
|
|
|
if self.healthCondition == 9 or self.healthCondition == 10:
|
2015-03-03 16:10:12 -06:00
|
|
|
taskMgr.remove(self.uniqueName('blink-task'))
|
|
|
|
self.healthCondition = 0
|
|
|
|
return
|
|
|
|
|
|
|
|
def reverseHead(self):
|
|
|
|
self.neck.setHpr(self.neckReversedHpr)
|
|
|
|
|
|
|
|
def forwardHead(self):
|
|
|
|
self.neck.setHpr(self.neckForwardHpr)
|
|
|
|
|
|
|
|
def reverseBody(self):
|
|
|
|
self.pelvis.setHpr(self.pelvisReversedHpr)
|
|
|
|
|
|
|
|
def forwardBody(self):
|
|
|
|
self.pelvis.setHpr(self.pelvisForwardHpr)
|
|
|
|
|
|
|
|
def getShadowJoint(self):
|
|
|
|
return self.getGeomNode()
|
|
|
|
|
|
|
|
def getNametagJoints(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
def getDialogueArray(self):
|
|
|
|
return self.dialogArray
|
|
|
|
|
|
|
|
def doorACallback(self, isOpen):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def doorBCallback(self, isOpen):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __rollTreadsInterval(self, object, start = 0, duration = 0, rate = 1):
|
|
|
|
|
|
|
|
def rollTexMatrix(t, object = object):
|
|
|
|
object.setTexOffset(TextureStage.getDefault(), t, 0)
|
|
|
|
|
|
|
|
return LerpFunctionInterval(rollTexMatrix, fromData=start, toData=start + rate * duration, duration=duration)
|
|
|
|
|
|
|
|
def rollLeftTreads(self, duration, rate):
|
|
|
|
start = self.treadsLeftPos
|
|
|
|
self.treadsLeftPos += duration * rate
|
|
|
|
return self.__rollTreadsInterval(self.treadsLeft, start=start, duration=duration, rate=rate)
|
|
|
|
|
|
|
|
def rollRightTreads(self, duration, rate):
|
|
|
|
start = self.treadsRightPos
|
|
|
|
self.treadsRightPos += duration * rate
|
|
|
|
return self.__rollTreadsInterval(self.treadsRight, start=start, duration=duration, rate=rate)
|
|
|
|
|
|
|
|
class DoorFSM(FSM.FSM):
|
|
|
|
|
|
|
|
def __init__(self, name, animate, callback, openedHpr, closedHpr, uniqueName):
|
|
|
|
FSM.FSM.__init__(self, name)
|
|
|
|
self.animate = animate
|
|
|
|
self.callback = callback
|
|
|
|
self.openedHpr = openedHpr
|
|
|
|
self.closedHpr = closedHpr
|
|
|
|
self.uniqueName = uniqueName
|
|
|
|
self.ival = 0
|
|
|
|
self.openSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_door_open.ogg')
|
|
|
|
self.closeSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_door_close.ogg')
|
|
|
|
self.request('Closed')
|
|
|
|
|
|
|
|
def filterOpening(self, request, args):
|
|
|
|
if request == 'close':
|
|
|
|
return 'Closing'
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
|
|
|
|
def enterOpening(self):
|
|
|
|
intervalName = self.uniqueName('open-%s' % self.animate.getName())
|
|
|
|
self.callback(0)
|
|
|
|
ival = Parallel(SoundInterval(self.openSfx, node=self.animate, volume=0.2), self.animate.hprInterval(1, self.openedHpr, blendType='easeInOut'), Sequence(Wait(0.2), Func(self.callback, 1)), name=intervalName)
|
|
|
|
ival.start()
|
|
|
|
self.ival = ival
|
|
|
|
|
|
|
|
def exitOpening(self):
|
|
|
|
self.ival.pause()
|
|
|
|
self.ival = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def filterOpened(self, request, args):
|
|
|
|
if request == 'close':
|
|
|
|
return 'Closing'
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
|
|
|
|
def enterOpened(self):
|
|
|
|
self.animate.setHpr(self.openedHpr)
|
|
|
|
self.callback(1)
|
|
|
|
|
|
|
|
def filterClosing(self, request, args):
|
|
|
|
if request == 'open':
|
|
|
|
return 'Opening'
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
|
|
|
|
def enterClosing(self):
|
|
|
|
intervalName = self.uniqueName('close-%s' % self.animate.getName())
|
|
|
|
self.callback(1)
|
|
|
|
ival = Parallel(SoundInterval(self.closeSfx, node=self.animate, volume=0.2), self.animate.hprInterval(1, self.closedHpr, blendType='easeInOut'), Sequence(Wait(0.8), Func(self.callback, 0)), name=intervalName)
|
|
|
|
ival.start()
|
|
|
|
self.ival = ival
|
|
|
|
|
|
|
|
def exitClosing(self):
|
|
|
|
self.ival.pause()
|
|
|
|
self.ival = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def filterClosed(self, request, args):
|
|
|
|
if request == 'open':
|
|
|
|
return 'Opening'
|
|
|
|
return self.defaultFilter(request, args)
|
|
|
|
|
|
|
|
def enterClosed(self):
|
|
|
|
self.animate.setHpr(self.closedHpr)
|
|
|
|
self.callback(0)
|
|
|
|
|
|
|
|
def __setupDoor(self, jointName, name, callback, openedHpr, closedHpr, cPoly):
|
|
|
|
joint = self.find(jointName)
|
|
|
|
children = joint.getChildren()
|
|
|
|
animate = joint.attachNewNode(name)
|
|
|
|
children.reparentTo(animate)
|
|
|
|
cnode = CollisionNode('BossZap')
|
|
|
|
cnode.setCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.WallBitmask | ToontownGlobals.CameraBitmask)
|
|
|
|
cnode.addSolid(cPoly)
|
|
|
|
animate.attachNewNode(cnode)
|
|
|
|
fsm = self.DoorFSM(name, animate, callback, openedHpr, closedHpr, self.uniqueName)
|
|
|
|
return fsm
|
|
|
|
|
|
|
|
def doAnimate(self, anim = None, now = 0, queueNeutral = 1, raised = None, forward = None, happy = None):
|
|
|
|
if now:
|
|
|
|
self.stopAnimate()
|
|
|
|
if not self.twoFaced:
|
|
|
|
happy = 1
|
|
|
|
if raised == None:
|
|
|
|
raised = self.raised
|
|
|
|
if forward == None:
|
|
|
|
forward = self.forward
|
|
|
|
if happy == None:
|
|
|
|
happy = self.happy
|
|
|
|
if now:
|
|
|
|
self.raised = raised
|
|
|
|
self.forward = forward
|
|
|
|
self.happy = happy
|
|
|
|
if self.currentAnimIval == None:
|
|
|
|
self.accept(self.animDoneEvent, self.__getNextAnim)
|
|
|
|
else:
|
|
|
|
queueNeutral = 0
|
|
|
|
ival, changed = self.__getAnimIval(anim, raised, forward, happy)
|
|
|
|
if changed or queueNeutral:
|
|
|
|
self.queuedAnimIvals.append((ival,
|
|
|
|
self.raised,
|
|
|
|
self.forward,
|
|
|
|
self.happy))
|
|
|
|
if self.currentAnimIval == None:
|
|
|
|
self.__getNextAnim()
|
|
|
|
return
|
|
|
|
|
|
|
|
def stopAnimate(self):
|
|
|
|
self.ignore(self.animDoneEvent)
|
|
|
|
self.queuedAnimIvals = []
|
|
|
|
if self.currentAnimIval:
|
|
|
|
self.currentAnimIval.setDoneEvent('')
|
|
|
|
self.currentAnimIval.finish()
|
|
|
|
self.currentAnimIval = None
|
|
|
|
self.raised = self.nowRaised
|
|
|
|
self.forward = self.nowForward
|
|
|
|
self.happy = self.nowHappy
|
|
|
|
return
|
|
|
|
|
|
|
|
def __getNextAnim(self):
|
|
|
|
if self.queuedAnimIvals:
|
|
|
|
ival, raised, forward, happy = self.queuedAnimIvals[0]
|
|
|
|
del self.queuedAnimIvals[0]
|
|
|
|
else:
|
|
|
|
ival, changed = self.__getAnimIval(None, self.raised, self.forward, self.happy)
|
|
|
|
raised = self.raised
|
|
|
|
forward = self.forward
|
|
|
|
happy = self.happy
|
|
|
|
if self.currentAnimIval:
|
|
|
|
self.currentAnimIval.setDoneEvent('')
|
|
|
|
self.currentAnimIval.finish()
|
|
|
|
self.currentAnimIval = ival
|
|
|
|
self.currentAnimIval.start()
|
|
|
|
self.nowRaised = raised
|
|
|
|
self.nowForward = forward
|
|
|
|
self.nowHappy = happy
|
|
|
|
return
|
|
|
|
|
|
|
|
def __getAnimIval(self, anim, raised, forward, happy):
|
|
|
|
ival, changed = self.__doGetAnimIval(anim, raised, forward, happy)
|
|
|
|
seq = Sequence(ival, name=self.animIvalName)
|
|
|
|
seq.setDoneEvent(self.animDoneEvent)
|
|
|
|
return (seq, changed)
|
|
|
|
|
|
|
|
def __doGetAnimIval(self, anim, raised, forward, happy):
|
|
|
|
if raised == self.raised and forward == self.forward and happy == self.happy:
|
|
|
|
return (self.getAnim(anim), anim != None)
|
|
|
|
startsHappy = self.happy
|
|
|
|
endsHappy = self.happy
|
|
|
|
ival = Sequence()
|
|
|
|
if raised and not self.raised:
|
|
|
|
upIval = self.getAngryActorInterval('Fb_down2Up')
|
|
|
|
if self.forward:
|
|
|
|
ival = upIval
|
|
|
|
else:
|
|
|
|
ival = Sequence(Func(self.reverseBody), upIval, Func(self.forwardBody))
|
|
|
|
ival = Parallel(SoundInterval(self.upSfx, node=self), ival)
|
|
|
|
if forward != self.forward:
|
|
|
|
if forward:
|
|
|
|
animName = 'Bb2Ff_spin'
|
|
|
|
else:
|
|
|
|
animName = 'Ff2Bb_spin'
|
|
|
|
ival = Sequence(ival, ActorInterval(self, animName))
|
|
|
|
startsHappy = 1
|
|
|
|
endsHappy = 1
|
|
|
|
startNeckHpr = self.neckForwardHpr
|
|
|
|
endNeckHpr = self.neckForwardHpr
|
|
|
|
if self.happy != startsHappy:
|
|
|
|
startNeckHpr = self.neckReversedHpr
|
|
|
|
if happy != endsHappy:
|
|
|
|
endNeckHpr = self.neckReversedHpr
|
|
|
|
if startNeckHpr != endNeckHpr:
|
|
|
|
ival = Sequence(Func(self.neck.setHpr, startNeckHpr), ParallelEndTogether(ival, Sequence(self.neck.hprInterval(0.5, endNeckHpr, startHpr=startNeckHpr, blendType='easeInOut'), Func(self.neck.setHpr, self.neckForwardHpr))))
|
|
|
|
elif endNeckHpr != self.neckForwardHpr:
|
|
|
|
ival = Sequence(Func(self.neck.setHpr, startNeckHpr), ival, Func(self.neck.setHpr, self.neckForwardHpr))
|
|
|
|
if not raised and self.raised:
|
|
|
|
downIval = self.getAngryActorInterval('Fb_down2Up', playRate=-1)
|
|
|
|
if forward:
|
|
|
|
ival = Sequence(ival, downIval)
|
|
|
|
else:
|
|
|
|
ival = Sequence(ival, Func(self.reverseBody), downIval, Func(self.forwardBody))
|
|
|
|
ival = Parallel(SoundInterval(self.downSfx, node=self), ival)
|
|
|
|
self.raised = raised
|
|
|
|
self.forward = forward
|
|
|
|
self.happy = happy
|
|
|
|
if anim != None:
|
|
|
|
ival = Sequence(ival, self.getAnim(anim))
|
|
|
|
return (ival, 1)
|
|
|
|
|
|
|
|
def setDizzy(self, dizzy):
|
|
|
|
if dizzy and not self.dizzy:
|
|
|
|
base.playSfx(self.dizzyAlert)
|
|
|
|
self.dizzy = dizzy
|
|
|
|
if dizzy:
|
|
|
|
self.stars.reparentTo(self.neck)
|
|
|
|
base.playSfx(self.birdsSfx, looping=1)
|
|
|
|
else:
|
|
|
|
self.stars.detachNode()
|
|
|
|
self.birdsSfx.stop()
|
|
|
|
|
|
|
|
def getAngryActorInterval(self, animName, **kw):
|
|
|
|
if self.happy:
|
|
|
|
ival = Sequence(Func(self.reverseHead), ActorInterval(self, animName, **kw), Func(self.forwardHead))
|
|
|
|
else:
|
|
|
|
ival = ActorInterval(self, animName, **kw)
|
|
|
|
return ival
|
|
|
|
|
|
|
|
def getAnim(self, anim):
|
|
|
|
ival = None
|
|
|
|
if anim == None:
|
|
|
|
partName = None
|
|
|
|
if self.happy:
|
|
|
|
animName = 'Ff_neutral'
|
|
|
|
else:
|
|
|
|
animName = 'Fb_neutral'
|
|
|
|
if self.raised:
|
|
|
|
ival = ActorInterval(self, animName)
|
|
|
|
else:
|
|
|
|
ival = Parallel(ActorInterval(self, animName, partName=['torso', 'head']), ActorInterval(self, 'Fb_downNeutral', partName='legs'))
|
|
|
|
if not self.forward:
|
|
|
|
ival = Sequence(Func(self.reverseBody), ival, Func(self.forwardBody))
|
|
|
|
elif anim == 'down2Up':
|
|
|
|
ival = Parallel(SoundInterval(self.upSfx, node=self), self.getAngryActorInterval('Fb_down2Up'))
|
|
|
|
self.raised = 1
|
|
|
|
elif anim == 'up2Down':
|
|
|
|
ival = Parallel(SoundInterval(self.downSfx, node=self), self.getAngryActorInterval('Fb_down2Up', playRate=-1))
|
|
|
|
self.raised = 0
|
|
|
|
elif anim == 'throw':
|
|
|
|
self.doAnimate(None, raised=1, happy=0, queueNeutral=0)
|
|
|
|
ival = Parallel(Sequence(SoundInterval(self.throwSfx, node=self), duration=0), self.getAngryActorInterval('Fb_UpThrow'))
|
|
|
|
elif anim == 'hit':
|
|
|
|
if self.raised:
|
|
|
|
self.raised = 0
|
|
|
|
ival = self.getAngryActorInterval('Fb_firstHit')
|
|
|
|
else:
|
|
|
|
ival = self.getAngryActorInterval('Fb_downHit')
|
|
|
|
ival = Parallel(SoundInterval(self.reelSfx, node=self), ival)
|
|
|
|
elif anim == 'ltSwing' or anim == 'rtSwing':
|
|
|
|
self.doAnimate(None, raised=0, happy=0, queueNeutral=0)
|
|
|
|
if anim == 'ltSwing':
|
|
|
|
ival = Sequence(Track((0, self.getAngryActorInterval('Fb_downLtSwing')), (0.9, SoundInterval(self.swingSfx, node=self)), (1, Func(self.bubbleL.unstash))), Func(self.bubbleL.stash))
|
|
|
|
else:
|
|
|
|
ival = Sequence(Track((0, self.getAngryActorInterval('Fb_downRtSwing')), (0.9, SoundInterval(self.swingSfx, node=self)), (1, Func(self.bubbleR.unstash))), Func(self.bubbleR.stash))
|
|
|
|
elif anim == 'frontAttack':
|
|
|
|
self.doAnimate(None, raised=1, happy=0, queueNeutral=0)
|
|
|
|
pe = BattleParticles.loadParticleFile('bossCogFrontAttack.ptf')
|
|
|
|
ival = Sequence(Func(self.reverseHead), ActorInterval(self, 'Bb2Ff_spin'), Func(self.forwardHead))
|
|
|
|
if self.forward:
|
|
|
|
ival = Sequence(Func(self.reverseBody), ParallelEndTogether(ival, self.pelvis.hprInterval(0.5, self.pelvisForwardHpr, blendType='easeInOut')))
|
|
|
|
ival = Sequence(Track((0, ival), (0, SoundInterval(self.spinSfx, node=self)), (0.9, Parallel(SoundInterval(self.rainGearsSfx, node=self), ParticleInterval(pe, self.frontAttack, worldRelative=0, duration=1.5, cleanup=True), duration=0)), (1.9, Func(self.bubbleF.unstash))), Func(self.bubbleF.stash))
|
|
|
|
self.forward = 1
|
|
|
|
self.happy = 0
|
|
|
|
self.raised = 1
|
|
|
|
elif anim == 'areaAttack':
|
|
|
|
if self.twoFaced:
|
|
|
|
self.doAnimate(None, raised=1, happy=0, queueNeutral=0)
|
|
|
|
else:
|
|
|
|
self.doAnimate(None, raised=1, happy=1, queueNeutral=1)
|
|
|
|
ival = Parallel(ActorInterval(self, 'Fb_jump'), Sequence(SoundInterval(self.swishSfx, duration=1.1, node=self), SoundInterval(self.boomSfx, duration=1.9)), Sequence(Wait(1.21), Func(self.announceAreaAttack)))
|
|
|
|
if self.twoFaced:
|
|
|
|
self.happy = 0
|
|
|
|
else:
|
|
|
|
self.happy = 1
|
|
|
|
self.raised = 1
|
|
|
|
elif anim == 'Fb_fall':
|
|
|
|
ival = Parallel(ActorInterval(self, 'Fb_fall'), Sequence(SoundInterval(self.reelSfx, node=self), SoundInterval(self.deathSfx)))
|
|
|
|
elif isinstance(anim, types.StringType):
|
|
|
|
ival = ActorInterval(self, anim)
|
|
|
|
else:
|
|
|
|
ival = anim
|
|
|
|
return ival
|