toontown-just-works/toontown/suit/DistributedSuitBase.py
2024-07-07 18:08:39 -05:00

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)