Poodletooth-iLand/toontown/suit/BossCog.py

560 lines
23 KiB
Python
Raw Normal View History

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
from pandac.PandaModules import *
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
elif health > 0.9:
2015-03-03 16:10:12 -06:00
condition = 1
elif health > 0.8:
2015-03-03 16:10:12 -06:00
condition = 2
elif health > 0.7:
condition = 3#Yellow
elif health > 0.6:
2015-06-15 19:56:12 -05:00
condition = 4
elif health > 0.5:
2015-06-15 19:56:12 -05:00
condition = 5
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-15 19:56:12 -05:00
condition = 8#Red
2015-03-03 16:10:12 -06:00
elif health > 0.0:
condition = 9#Blinking Red
2015-03-03 16:10:12 -06:00
else:
condition = 10
2015-03-03 16:10:12 -06:00
if self.healthCondition != condition:
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'))
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-15 19:56:12 -05:00
2015-03-03 16:10:12 -06:00
def __blinkRed(self, task):
if not self.healthBar:
2015-06-15 19:56:12 -05:00
return
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):
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
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