427 lines
17 KiB
Python
427 lines
17 KiB
Python
from panda3d.core import *
|
|
from direct.controls.ControlManager import CollisionHandlerRayStart
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.interval.IntervalGlobal import *
|
|
from direct.task import Task
|
|
from otp.avatar import DistributedAvatar
|
|
from otp.otpbase import OTPGlobals
|
|
from otp.nametag.NametagConstants import *
|
|
from otp.nametag import NametagGlobals
|
|
from toontown.battle import BattleProps
|
|
from toontown.toonbase import TTLocalizer, ToontownGlobals
|
|
import Suit, SuitBase, SuitDialog, SuitTimings
|
|
import random
|
|
|
|
class DistributedSuitBase(DistributedAvatar.DistributedAvatar, Suit.Suit, SuitBase.SuitBase):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSuitBase')
|
|
|
|
def __init__(self, cr):
|
|
try:
|
|
self.DistributedSuitBase_initialized
|
|
return
|
|
except:
|
|
self.DistributedSuitBase_initialized = 1
|
|
|
|
DistributedAvatar.DistributedAvatar.__init__(self, cr)
|
|
Suit.Suit.__init__(self)
|
|
SuitBase.SuitBase.__init__(self)
|
|
self.activeShadow = 0
|
|
self.virtual = 0
|
|
self.battleDetectName = None
|
|
self.cRay = None
|
|
self.cRayNode = None
|
|
self.cRayNodePath = None
|
|
self.cRayBitMask = None
|
|
self.lifter = None
|
|
self.cTrav = None
|
|
self.sp = None
|
|
self.fsm = None
|
|
self.prop = None
|
|
self.propInSound = None
|
|
self.propOutSound = None
|
|
self.reparentTo(hidden)
|
|
self.loop('neutral')
|
|
self.skeleRevives = 0
|
|
self.maxSkeleRevives = 0
|
|
self.sillySurgeText = False
|
|
self.interactivePropTrackBonus = -1
|
|
|
|
def setInteractivePropTrackBonus(self, trackBonus):
|
|
self.interactivePropTrackBonus = trackBonus
|
|
|
|
def setVirtual(self, virtual):
|
|
pass
|
|
|
|
def getVirtual(self):
|
|
return 0
|
|
|
|
def setSkeleRevives(self, num):
|
|
if num == None:
|
|
num = 0
|
|
self.skeleRevives = num
|
|
if num > self.maxSkeleRevives:
|
|
self.maxSkeleRevives = num
|
|
if self.getSkeleRevives() > 0:
|
|
nameInfo = TTLocalizer.SuitBaseNameWithLevel % {'name': self.name,
|
|
'dept': self.getStyleDept(),
|
|
'level': '%s%s' % (self.getActualLevel(), TTLocalizer.SkeleRevivePostFix % (self.skeleRevives + 1))}
|
|
self.setDisplayName(nameInfo)
|
|
else:
|
|
nameInfo = TTLocalizer.SuitBaseNameWithLevel % {'name': self.name,
|
|
'dept': self.getStyleDept(),
|
|
'level': self.getActualLevel()}
|
|
self.setDisplayName(nameInfo)
|
|
|
|
def getSkeleRevives(self):
|
|
return self.skeleRevives
|
|
|
|
def getMaxSkeleRevives(self):
|
|
return self.maxSkeleRevives
|
|
|
|
def generate(self):
|
|
DistributedAvatar.DistributedAvatar.generate(self)
|
|
|
|
def disable(self):
|
|
self.notify.debug('DistributedSuit %d: disabling' % self.getDoId())
|
|
self.ignoreAll()
|
|
self.__removeCollisionData()
|
|
self.cleanupLoseActor()
|
|
self.stop()
|
|
taskMgr.remove(self.uniqueName('blink-task'))
|
|
DistributedAvatar.DistributedAvatar.disable(self)
|
|
|
|
def delete(self):
|
|
try:
|
|
self.DistributedSuitBase_deleted
|
|
except:
|
|
self.DistributedSuitBase_deleted = 1
|
|
self.notify.debug('DistributedSuit %d: deleting' % self.getDoId())
|
|
del self.dna
|
|
del self.sp
|
|
DistributedAvatar.DistributedAvatar.delete(self)
|
|
Suit.Suit.delete(self)
|
|
SuitBase.SuitBase.delete(self)
|
|
|
|
def setDNAString(self, dnaString):
|
|
Suit.Suit.setDNAString(self, dnaString)
|
|
|
|
def setDNA(self, dna):
|
|
Suit.Suit.setDNA(self, dna)
|
|
|
|
def getHP(self):
|
|
return self.currHP
|
|
|
|
def getMaxHP(self):
|
|
return self.maxHP
|
|
|
|
def setHP(self, hp):
|
|
if hp > self.maxHP:
|
|
self.currHP = self.maxHP
|
|
else:
|
|
self.currHP = hp
|
|
return None
|
|
|
|
def getDialogueArray(self, *args):
|
|
return Suit.Suit.getDialogueArray(self, *args)
|
|
|
|
def __removeCollisionData(self):
|
|
self.enableRaycast(0)
|
|
self.cRay = None
|
|
self.cRayNode = None
|
|
self.cRayNodePath = None
|
|
self.lifter = None
|
|
self.cTrav = None
|
|
|
|
def setHeight(self, height):
|
|
Suit.Suit.setHeight(self, height)
|
|
|
|
def getRadius(self):
|
|
return Suit.Suit.getRadius(self)
|
|
|
|
def setLevelDist(self, level):
|
|
if self.notify.getDebug():
|
|
self.notify.debug('Got level %d from server for suit %d' % (level, self.getDoId()))
|
|
self.setLevel(level)
|
|
|
|
def attachPropeller(self):
|
|
if self.prop == None:
|
|
self.prop = BattleProps.globalPropPool.getProp('propeller')
|
|
if self.propInSound == None:
|
|
self.propInSound = base.loadSfx('phase_5/audio/sfx/ENC_propeller_in.ogg')
|
|
if self.propOutSound == None:
|
|
self.propOutSound = base.loadSfx('phase_5/audio/sfx/ENC_propeller_out.ogg')
|
|
if base.config.GetBool('want-new-cogs', 0):
|
|
head = self.find('**/to_head')
|
|
if head.isEmpty():
|
|
head = self.find('**/joint_head')
|
|
else:
|
|
head = self.find('**/joint_head')
|
|
self.prop.reparentTo(head)
|
|
|
|
def detachPropeller(self):
|
|
if self.prop:
|
|
self.prop.cleanup()
|
|
self.prop.removeNode()
|
|
self.prop = None
|
|
if self.propInSound:
|
|
self.propInSound = None
|
|
if self.propOutSound:
|
|
self.propOutSound = None
|
|
|
|
def beginSupaFlyMove(self, pos, moveIn, trackName, walkAfterLanding=True):
|
|
skyPos = Point3(pos)
|
|
if moveIn:
|
|
skyPos.setZ(pos.getZ() + SuitTimings.fromSky * ToontownGlobals.SuitWalkSpeed)
|
|
else:
|
|
skyPos.setZ(pos.getZ() + SuitTimings.toSky * ToontownGlobals.SuitWalkSpeed)
|
|
groundF = 28
|
|
dur = self.getDuration('landing')
|
|
fr = self.getFrameRate('landing')
|
|
if fr:
|
|
animTimeInAir = groundF / fr
|
|
else:
|
|
animTimeInAir = groundF
|
|
impactLength = dur - animTimeInAir
|
|
timeTillLanding = SuitTimings.fromSky - impactLength
|
|
waitTime = timeTillLanding - animTimeInAir
|
|
if self.prop == None:
|
|
self.prop = BattleProps.globalPropPool.getProp('propeller')
|
|
propDur = self.prop.getDuration('propeller')
|
|
lastSpinFrame = 8
|
|
fr = self.prop.getFrameRate('propeller')
|
|
spinTime = lastSpinFrame / fr
|
|
openTime = (lastSpinFrame + 1) / fr
|
|
if moveIn:
|
|
lerpPosTrack = Sequence(self.posInterval(timeTillLanding, pos, startPos=skyPos), Wait(impactLength))
|
|
shadowScale = self.dropShadow.getScale()
|
|
shadowTrack = Sequence(Func(self.dropShadow.reparentTo, render), Func(self.dropShadow.setPos, pos), self.dropShadow.scaleInterval(timeTillLanding, self.scale, startScale=Vec3(0.01, 0.01, 1.0)), Func(self.dropShadow.reparentTo, self.getShadowJoint()), Func(self.dropShadow.setPos, 0, 0, 0), Func(self.dropShadow.setScale, shadowScale))
|
|
fadeInTrack = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(1, colorScale=VBase4(1, 1, 1, 1), startColorScale=VBase4(1, 1, 1, 0)), Func(self.clearColorScale), Func(self.clearTransparency))
|
|
animTrack = Sequence(Func(self.pose, 'landing', 0), Wait(waitTime), ActorInterval(self, 'landing', duration=dur))
|
|
if walkAfterLanding:
|
|
animTrack.append(Func(self.loop, 'walk'))
|
|
self.attachPropeller()
|
|
propTrack = Parallel(SoundInterval(self.propInSound, duration=waitTime + dur, node=self), Sequence(ActorInterval(self.prop, 'propeller', constrainedLoop=1, duration=waitTime + spinTime, startTime=0.0, endTime=spinTime), ActorInterval(self.prop, 'propeller', duration=propDur - openTime, startTime=openTime), Func(self.detachPropeller)))
|
|
return Parallel(lerpPosTrack, shadowTrack, fadeInTrack, animTrack, propTrack, name=self.taskName('trackName'))
|
|
else:
|
|
lerpPosTrack = Sequence(Wait(impactLength), LerpPosInterval(self, timeTillLanding, skyPos, startPos=pos))
|
|
shadowTrack = Sequence(Func(self.dropShadow.reparentTo, render), Func(self.dropShadow.setPos, pos), self.dropShadow.scaleInterval(timeTillLanding, Vec3(0.01, 0.01, 1.0), startScale=self.scale), Func(self.dropShadow.reparentTo, self.getShadowJoint()), Func(self.dropShadow.setPos, 0, 0, 0))
|
|
fadeOutTrack = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(1, colorScale=VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1)), Func(self.clearColorScale), Func(self.clearTransparency), Func(self.reparentTo, hidden))
|
|
actInt = ActorInterval(self, 'landing', loop=0, startTime=dur, endTime=0.0)
|
|
self.attachPropeller()
|
|
self.prop.hide()
|
|
propTrack = Parallel(SoundInterval(self.propOutSound, duration=waitTime + dur, node=self), Sequence(Func(self.prop.show), ActorInterval(self.prop, 'propeller', endTime=openTime, startTime=propDur), ActorInterval(self.prop, 'propeller', constrainedLoop=1, duration=propDur - openTime, startTime=spinTime, endTime=0.0), Func(self.detachPropeller)))
|
|
return Parallel(ParallelEndTogether(lerpPosTrack, shadowTrack, fadeOutTrack), actInt, propTrack, name=self.taskName('trackName'))
|
|
|
|
def enableBattleDetect(self, name, handler):
|
|
if self.collTube:
|
|
self.battleDetectName = self.taskName(name)
|
|
self.collNode = CollisionNode(self.battleDetectName)
|
|
self.collNode.addSolid(self.collTube)
|
|
self.collNodePath = self.attachNewNode(self.collNode)
|
|
self.collNode.setCollideMask(ToontownGlobals.WallBitmask)
|
|
self.accept('enter' + self.battleDetectName, handler)
|
|
return Task.done
|
|
|
|
def disableBattleDetect(self):
|
|
if self.battleDetectName:
|
|
self.ignore('enter' + self.battleDetectName)
|
|
self.battleDetectName = None
|
|
if self.collNodePath:
|
|
self.collNodePath.removeNode()
|
|
self.collNodePath = None
|
|
|
|
def enableRaycast(self, enable = 1):
|
|
if not self.cTrav or not hasattr(self, 'cRayNode') or not self.cRayNode:
|
|
return
|
|
self.cTrav.removeCollider(self.cRayNodePath)
|
|
if enable:
|
|
if self.notify.getDebug():
|
|
self.notify.debug('enabling raycast')
|
|
self.cTrav.addCollider(self.cRayNodePath, self.lifter)
|
|
elif self.notify.getDebug():
|
|
self.notify.debug('disabling raycast')
|
|
|
|
def b_setBrushOff(self, index):
|
|
self.setBrushOff(index)
|
|
self.d_setBrushOff(index)
|
|
|
|
def d_setBrushOff(self, index):
|
|
self.sendUpdate('setBrushOff', [index])
|
|
|
|
def setBrushOff(self, index):
|
|
self.setChatAbsolute(SuitDialog.getBrushOffText(self.getStyleName(), index), CFSpeech | CFTimeout)
|
|
|
|
def initializeBodyCollisions(self, collIdStr):
|
|
DistributedAvatar.DistributedAvatar.initializeBodyCollisions(self, collIdStr)
|
|
if not self.ghostMode:
|
|
self.collNode.setCollideMask(self.collNode.getIntoCollideMask() | ToontownGlobals.PieBitmask)
|
|
self.cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
|
|
self.cRayNode = CollisionNode(self.taskName('cRay'))
|
|
self.cRayNode.addSolid(self.cRay)
|
|
self.cRayNodePath = self.attachNewNode(self.cRayNode)
|
|
self.cRayNodePath.hide()
|
|
self.cRayBitMask = ToontownGlobals.FloorBitmask
|
|
self.cRayNode.setFromCollideMask(self.cRayBitMask)
|
|
self.cRayNode.setIntoCollideMask(BitMask32.allOff())
|
|
self.lifter = CollisionHandlerFloor()
|
|
self.lifter.setOffset(ToontownGlobals.FloorOffset)
|
|
self.lifter.setReach(6.0)
|
|
self.lifter.setMaxVelocity(8.0)
|
|
self.lifter.addCollider(self.cRayNodePath, self)
|
|
self.cTrav = base.cTrav
|
|
|
|
def disableBodyCollisions(self):
|
|
self.disableBattleDetect()
|
|
self.enableRaycast(0)
|
|
if self.cRayNodePath:
|
|
self.cRayNodePath.removeNode()
|
|
del self.cRayNode
|
|
del self.cRay
|
|
del self.lifter
|
|
|
|
def denyBattle(self):
|
|
self.notify.debug('denyBattle()')
|
|
place = self.cr.playGame.getPlace()
|
|
if place.fsm.getCurrentState().getName() == 'WaitForBattle':
|
|
place.setState('walk')
|
|
self.resumePath(self.pathState)
|
|
|
|
def makePathTrack(self, nodePath, posPoints, velocity, name):
|
|
track = Sequence(name=name)
|
|
nodePath.setPos(posPoints[0])
|
|
for pointIndex in xrange(len(posPoints) - 1):
|
|
startPoint = posPoints[pointIndex]
|
|
endPoint = posPoints[pointIndex + 1]
|
|
track.append(Func(nodePath.headsUp, endPoint[0], endPoint[1], endPoint[2]))
|
|
distance = Vec3(endPoint - startPoint).length()
|
|
duration = distance / velocity
|
|
track.append(LerpPosInterval(nodePath, duration=duration, pos=Point3(endPoint), startPos=Point3(startPoint)))
|
|
return track
|
|
|
|
def setState(self, state):
|
|
if self.fsm == None:
|
|
return 0
|
|
if self.fsm.getCurrentState().getName() == state:
|
|
return 0
|
|
return self.fsm.request(state)
|
|
|
|
def subclassManagesParent(self):
|
|
return 0
|
|
|
|
def enterOff(self, *args):
|
|
self.hideNametag3d()
|
|
self.hideNametag2d()
|
|
if not self.subclassManagesParent():
|
|
self.setParent(ToontownGlobals.SPHidden)
|
|
|
|
def exitOff(self):
|
|
if not self.subclassManagesParent():
|
|
self.setParent(ToontownGlobals.SPRender)
|
|
self.showNametag3d()
|
|
self.showNametag2d()
|
|
self.loop('neutral', 0)
|
|
|
|
def enterBattle(self):
|
|
self.loop('neutral', 0)
|
|
self.disableBattleDetect()
|
|
self.corpMedallion.hide()
|
|
self.healthBar.geom.show()
|
|
if self.currHP < self.maxHP:
|
|
self.updateHealthBar(0, 1)
|
|
|
|
def exitBattle(self):
|
|
self.healthBar.geom.hide()
|
|
self.corpMedallion.show()
|
|
self.currHP = self.maxHP
|
|
self.interactivePropTrackBonus = -1
|
|
|
|
def enterWaitForBattle(self):
|
|
self.loop('neutral', 0)
|
|
|
|
def exitWaitForBattle(self):
|
|
pass
|
|
|
|
def setSkelecog(self, flag):
|
|
SuitBase.SuitBase.setSkelecog(self, flag)
|
|
if flag:
|
|
Suit.Suit.makeSkeleton(self)
|
|
|
|
def setWaiter(self, flag):
|
|
SuitBase.SuitBase.setWaiter(self, flag)
|
|
if flag:
|
|
Suit.Suit.makeWaiter(self)
|
|
|
|
def showHpText(self, number, bonus = 0, scale = 1, attackTrack = -1):
|
|
if self.HpTextEnabled and not self.ghostMode:
|
|
if number != 0:
|
|
if self.hpText:
|
|
self.hideHpText()
|
|
|
|
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
|
|
|
|
if number < 0:
|
|
self.HpTextGenerator.setText(str(number))
|
|
|
|
if config.GetBool('silly-surge-text', True) and random.randrange(0, 100) < config.GetInt('silly-surge-chance', 10):
|
|
self.sillySurgeText = True
|
|
absNumber = int(abs(number) / 10)
|
|
|
|
if len(TTLocalizer.SillySurgeTerms) > absNumber:
|
|
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[absNumber])
|
|
else:
|
|
self.HpTextGenerator.setText(str(number) + '\n' + random.choice(TTLocalizer.SillySurgeTerms))
|
|
|
|
if self.interactivePropTrackBonus > -1 and self.interactivePropTrackBonus == attackTrack:
|
|
self.sillySurgeText = True
|
|
|
|
if attackTrack in TTLocalizer.InteractivePropTrackBonusTerms:
|
|
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.InteractivePropTrackBonusTerms[attackTrack])
|
|
else:
|
|
self.HpTextGenerator.setText('+' + str(number))
|
|
|
|
self.HpTextGenerator.clearShadow()
|
|
self.HpTextGenerator.setAlign(TextNode.ACenter)
|
|
|
|
if bonus == 1:
|
|
color = [1, 1, 0, 1]
|
|
elif bonus == 2:
|
|
color = [1, 0.5, 0, 1]
|
|
elif number < 0:
|
|
color = [0.9, 0, 0, 1]
|
|
|
|
if self.interactivePropTrackBonus > -1 and self.interactivePropTrackBonus == attackTrack:
|
|
color = [0, 0, 1, 1]
|
|
else:
|
|
color = [0, 0.9, 0, 1]
|
|
|
|
self.HpTextGenerator.setTextColor(*color)
|
|
self.hpTextNode = self.HpTextGenerator.generate()
|
|
self.hpText = self.attachNewNode(self.hpTextNode)
|
|
self.hpText.setScale(scale)
|
|
self.hpText.setBillboardPointEye()
|
|
self.hpText.setBin('fixed', 100)
|
|
|
|
if self.sillySurgeText:
|
|
self.nametag3d.setDepthTest(0)
|
|
self.nametag3d.setBin('fixed', 99)
|
|
|
|
self.hpText.setPos(0, 0, self.height / 2)
|
|
color[3] = 0
|
|
Sequence(self.hpText.posInterval(1.0, Point3(0, 0, self.height + 1.5), blendType='easeOut'), Wait(0.85), self.hpText.colorInterval(0.1, Vec4(*color), 0.1), Func(self.hideHpText)).start()
|
|
|
|
def hideHpText(self):
|
|
DistributedAvatar.DistributedAvatar.hideHpText(self)
|
|
|
|
if self.sillySurgeText:
|
|
self.nametag3d.clearDepthTest()
|
|
self.nametag3d.clearBin()
|
|
self.sillySurgeText = False
|
|
|
|
def getAvIdName(self):
|
|
try:
|
|
level = self.getActualLevel()
|
|
except:
|
|
level = '???'
|
|
|
|
return '%s\n%s\nLevel %s' % (self.getName(), self.doId, level)
|