oldschool-toontown/toontown/suit/DistributedSuitBase.py
John Cote 827445d8fa
general: current progress
progress includes:
 - cogs appear on streets now
 - additionally, street interests are setup for astron clients.
 - cog battles are mostly working
 - updated some sequences to work with newer panda3d
 - fixed particle effects search paths so that they load now
 - handled disconnect reasons for clients that disconnect during cog battles etc.
 - fleshed out the holiday manager a bit more
2019-11-27 20:14:30 -05:00

450 lines
19 KiB
Python

from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.distributed.ClockDelta import *
from direct.directtools.DirectGeometry import CLAMP
from direct.controls.ControlManager import CollisionHandlerRayStart
from direct.task import Task
from otp.otpbase import OTPGlobals
from otp.avatar import DistributedAvatar
import Suit
from toontown.toonbase import ToontownGlobals
from toontown.toonbase import ToontownBattleGlobals
from toontown.toonbase import TTLocalizer
from toontown.battle import DistributedBattle
from direct.fsm import ClassicFSM
from direct.fsm import State
import SuitTimings
import SuitBase
import DistributedSuitPlanner
import SuitDNA
from direct.directnotify import DirectNotifyGlobal
import SuitDialog
from toontown.battle import BattleProps
import math
import copy
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
return
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.setDisplayName(nameInfo)
else:
nameInfo = TTLocalizer.SuitBaseNameWithLevel % {'name': self._name,
'dept': self.getStyleDept(),
'level': self.getActualLevel()}
self.setDisplayName(nameInfo)
return
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 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
return
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.loader.loadSfx('phase_5/audio/sfx/ENC_propeller_in.mp3')
if self.propOutSound == None:
self.propOutSound = base.loader.loadSfx('phase_5/audio/sfx/ENC_propeller_out.mp3')
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)
return
def detachPropeller(self):
if self.prop:
self.prop.removeNode()
self.prop = None
if self.propInSound:
self.propInSound = None
if self.propOutSound:
self.propOutSound = None
return
def beginSupaFlyMove(self, pos, moveIn, trackName):
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')
animTimeInAir = groundF / fr
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), 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'))
return
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
return
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)
restOfPosPoints = posPoints[1:]
for pointIndex in range(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.show()
if self.currHP < self.maxHP:
self.updateHealthBar(0, 1)
def exitBattle(self):
self.healthBar.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 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 base.cr.newsManager.isHolidayRunning(ToontownGlobals.SILLY_SURGE_HOLIDAY):
self.sillySurgeText = True
absNum = abs(number)
if absNum > 0 and absNum <= 10:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[1])
elif absNum > 10 and absNum <= 20:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[2])
elif absNum > 20 and absNum <= 30:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[3])
elif absNum > 30 and absNum <= 40:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[4])
elif absNum > 40 and absNum <= 50:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[5])
elif absNum > 50 and absNum <= 60:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[6])
elif absNum > 60 and absNum <= 70:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[7])
elif absNum > 70 and absNum <= 80:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[8])
elif absNum > 80 and absNum <= 90:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[9])
elif absNum > 90 and absNum <= 100:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[10])
elif absNum > 100 and absNum <= 110:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[11])
else:
self.HpTextGenerator.setText(str(number) + '\n' + TTLocalizer.SillySurgeTerms[12])
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:
r = 1.0
g = 1.0
b = 0
a = 1
elif bonus == 2:
r = 1.0
g = 0.5
b = 0
a = 1
elif number < 0:
r = 0.9
g = 0
b = 0
a = 1
if self.interactivePropTrackBonus > -1 and self.interactivePropTrackBonus == attackTrack:
r = 0
g = 0
b = 1
a = 1
else:
r = 0
g = 0.9
b = 0
a = 1
self.HpTextGenerator.setTextColor(r, g, b, a)
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)
self.hpTextSeq = Sequence(self.hpText.posInterval(1.0, Point3(0, 0, self.height + 1.5), blendType='easeOut'), Wait(0.85), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.hideHpText))
self.hpTextSeq.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)