toontown-just-works/toontown/coghq/DistributedFoodBelt.py
2024-07-07 18:08:39 -05:00

352 lines
14 KiB
Python

from pandac.PandaModules import NodePath, Point3, CollisionTube, CollisionNode
from direct.fsm import FSM
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from direct.interval.IntervalGlobal import Sequence, Wait, LerpPosInterval, ProjectileInterval, Func, SoundInterval
from direct.actor import Actor
from toontown.toonbase import ToontownGlobals
from toontown.coghq.FoodBeltBase import FoodBeltBase
class DistributedFoodBelt(DistributedObject.DistributedObject, FSM.FSM, FoodBeltBase):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFoodBelt')
BeltSpeed = 5
OnDuration = 300
ToonupBeltSpeed = 1.0
BeltActorPlayRate = 5.35
ToonupBeltActorPlayRate = BeltActorPlayRate * ToonupBeltSpeed / BeltSpeed
ToonupModels = ['phase_6/models/golf/picnic_apple.bam',
'phase_6/models/golf/picnic_cupcake.bam',
'phase_6/models/golf/picnic_sandwich.bam',
'phase_6/models/golf/picnic_chocolate_cake.bam']
ToonupScales = [5,
5,
5,
4]
ToonupZOffsets = [-0.25,
-0.25,
-0,
-0.25]
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
FSM.FSM.__init__(self, 'DistributedFoodBelt')
self.boss = None
self.bossCogId = 0
self.index = -1
self.foodNodes = []
self.foodIvals = []
self.foodWaitTimes = []
self.foodModelDict = {}
self.foodNum = 0
self.beltActor = None
self.toonupIvals = []
self.toonupWaitTimes = []
self.toonupModelDict = {}
self.toonupNum = 0
return
def delete(self):
DistributedObject.DistributedObject.delete(self)
self.cleanup()
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
if self.boss:
self.boss.setBelt(self, self.index)
self.loadAssets()
else:
self.notify.warning('announceGenerate self.boss is None, self.bossCogId = %d' % self.bossCogId)
def setBossCogId(self, bossCogId):
self.bossCogId = bossCogId
self.boss = base.cr.doId2do.get(bossCogId)
def setIndex(self, index):
self.index = index
def setState(self, state):
if state == 'F':
self.demand('Off')
elif state == 'N':
self.demand('On')
elif state == 'I':
self.demand('Inactive')
elif state == 'T':
self.demand('Toonup')
else:
self.notify.error('Invalid state from AI: %s' % state)
def enterOn(self):
self.beltSoundInterval.loop()
for i in xrange(len(self.foodNodes)):
self.doMethodLater(self.foodWaitTimes[i], self.startFoodMoving, 'start-%d-%d' % (self.index, i), extraArgs=[i])
def exitOn(self):
self.beltSoundInterval.finish()
for i in xrange(len(self.foodNodes)):
taskName = 'start-%d-%d' % (self.index, i)
self.removeTask(taskName)
def enterToonup(self):
self.beltSound.setPlayRate(self.ToonupBeltSpeed / self.BeltSpeed)
self.beltSoundInterval.loop()
for i in xrange(len(self.foodNodes)):
self.removeFood(i)
self.beltActor.setPlayRate(self.ToonupBeltActorPlayRate, 'idle')
self.doMethodLater(self.toonupWaitTimes[i], self.startToonupMoving, 'startToonup-%d-%d' % (self.index, i), extraArgs=[i])
def exitToonup(self):
self.beltSoundInterval.finish()
for i in xrange(len(self.foodNodes)):
taskName = 'startToonup-%d-%d' % (self.index, i)
self.removeTask(taskName)
def enterInactive(self):
for ival in self.foodIvals:
ival.finish()
for ival in self.toonupIvals:
ival.finish()
for i in xrange(len(self.foodNodes)):
self.removeFood(i)
self.removeToonup(i)
if self.beltActor:
self.beltActor.stop()
def exitInactive(self):
pass
def startFoodMoving(self, foodIndex):
if foodIndex < len(self.foodIvals):
self.foodIvals[foodIndex].loop()
else:
self.notify.warning('startFoodMoving invalid index %d' % foodIndex)
if self.beltActor:
self.beltActor.loop('idle')
def startToonupMoving(self, toonupIndex):
if toonupIndex < len(self.toonupIvals):
self.toonupIvals[toonupIndex].loop()
else:
self.notify.warning('startToonupMoving invalid index %d' % toonupIndex)
if self.beltActor:
self.beltActor.loop('idle')
def loadAssets(self):
self.beltModel = NodePath('beltModel')
self.beltModel.reparentTo(self.boss.geom)
self.startLocator = self.boss.geom.find('**/conveyer_belt_start_%d' % (self.index + 1))
self.endLocator = self.boss.geom.find('**/conveyer_belt_end_%d' % (self.index + 1))
center = (self.startLocator.getPos() + self.endLocator.getPos()) / 2.0
self.beltHeight = center.getZ()
self.beltHeight += 0.1
center.setZ(0)
self.beltLength = (self.endLocator.getPos() - self.startLocator.getPos()).length()
self.distBetweenFoodNodes = self.beltLength / self.NumFoodNodes
self.notify.debug('setting beltModelPos to %s' % center)
self.beltModel.setPos(center)
self.setupFoodNodes()
self.setupFoodIvals()
self.setupToonupIvals()
if self.index == 0:
self.beltActorModel = loader.loadModel('phase_12/models/bossbotHQ/food_belt1_model')
else:
self.beltActorModel = loader.loadModel('phase_12/models/bossbotHQ/food_belt2_model')
if self.beltActorModel:
self.beltActor = Actor.Actor(self.beltActorModel)
if self.index == 0:
self.beltActor.loadAnims({'idle': 'phase_12/models/bossbotHQ/food_belt1'})
else:
self.beltActor.loadAnims({'idle': 'phase_12/models/bossbotHQ/food_belt2'})
self.beltActor.reparentTo(render)
self.beltActor.setPlayRate(self.BeltActorPlayRate, 'idle')
mesh = self.beltActor.find('**/mesh_tide1')
joint = self.beltActor.find('**/uvj_WakeWhiteTide1')
mesh.setTexProjector(mesh.findTextureStage('default'), joint, self.beltActor)
self.beltActor.setPos(self.startLocator.getPos())
self.beltSound = base.loadSfx('phase_12/audio/sfx/CHQ_FACT_conveyor_belt.ogg')
self.beltSound.setLoop(1)
self.beltSoundInterval = SoundInterval(self.beltSound, node=self.beltModel, listenerNode=base.localAvatar, seamlessLoop=True, volume=0.25, cutOff=100)
def cleanup(self):
for i in xrange(len(self.foodNodes)):
taskName = 'start-%d-%d' % (self.index, i)
self.removeTask(taskName)
for i in xrange(len(self.foodNodes)):
taskName = 'startToonup-%d-%d' % (self.index, i)
self.removeTask(taskName)
for ival in self.foodIvals:
ival.finish()
self.foodIvals = []
for ival in self.toonupIvals:
ival.finish()
self.toonupIvals = []
self.beltSoundInterval.finish()
self.beltActor.delete()
self.beltModel = None
self.removeAllTasks()
self.ignoreAll()
return
def setupFoodNodes(self):
for i in xrange(self.NumFoodNodes):
newPosIndex = self.NumFoodNodes - 1 - i
yPos = -(self.beltLength / 2.0) + newPosIndex * self.distBetweenFoodNodes
newFoodNode = NodePath('foodNode-%d-%d' % (self.index, i))
newFoodNode.reparentTo(self.beltModel)
newFoodNode.setPos(0, yPos, self.beltHeight)
debugFood = None
if debugFood:
debugFood.setScale(0.1)
debugFood.reparentTo(newFoodNode)
newFoodNode.setH(180)
self.foodNodes.append(newFoodNode)
return
def setupFoodIvals(self):
for i in xrange(len(self.foodNodes)):
foodIval = self.createOneFoodIval(self.foodNodes[i])
self.foodIvals.append(foodIval)
def createOneFoodIval(self, foodNode):
foodIndex = self.foodNodes.index(foodNode)
waitTimeForOne = self.distBetweenFoodNodes / self.BeltSpeed
waitTime = waitTimeForOne * foodIndex
self.foodWaitTimes.append(waitTime)
totalTimeToTraverseBelt = self.beltLength / self.BeltSpeed
startPosY = -(self.beltLength / 2.0)
endPosY = self.beltLength / 2.0
retval = Sequence(Func(self.loadFood, foodIndex), LerpPosInterval(foodNode, duration=totalTimeToTraverseBelt, startPos=Point3(0, startPosY, self.beltHeight), pos=Point3(0, endPosY, self.beltHeight)), ProjectileInterval(foodNode, startPos=Point3(0, endPosY, self.beltHeight), startVel=Point3(0, self.BeltSpeed, 0), endZ=0), Func(self.removeFood, foodIndex))
return retval
def loadFood(self, foodIndex):
self.foodNum += 1
if foodIndex in self.foodModelDict:
foodModel = self.foodModelDict[foodIndex]
foodModel.reparentTo(self.foodNodes[foodIndex])
colNp = foodModel.find('**/FoodCol*')
colNp.setTag('foodNum', str(self.foodNum))
else:
foodModelScale = ToontownGlobals.BossbotFoodModelScale
foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood')
foodModel.setScale(foodModelScale)
foodModel.reparentTo(self.foodNodes[foodIndex])
target = CollisionTube(4, 0, 0, -4, 0, 0, 2)
target.setTangible(0)
colName = 'FoodCol-%d-%d' % (self.index, foodIndex)
targetNode = CollisionNode(colName)
targetNode.addSolid(target)
targetNode.setCollideMask(ToontownGlobals.WallBitmask)
targetNodePath = foodModel.attachNewNode(targetNode)
targetNodePath.setScale(1.0 / foodModelScale)
targetNodePath.setTag('foodIndex', str(foodIndex))
targetNodePath.setTag('beltIndex', str(self.index))
targetNodePath.setTag('foodNum', str(self.foodNum))
targetNodePath.setZ(targetNodePath.getZ() - 1.5)
self.accept('enter' + colName, self.touchedFood)
self.foodModelDict[foodIndex] = foodModel
def removeFood(self, foodIndex):
if foodIndex in self.foodModelDict:
foodModel = self.foodModelDict[foodIndex]
foodModel.stash()
def touchedFood(self, colEntry):
into = colEntry.getIntoNodePath()
try:
beltIndex = int(into.getTag('beltIndex'))
except:
beltIndex = 0
try:
foodIndex = int(into.getTag('foodIndex'))
except:
foodIndex = 0
try:
foodNum = int(into.getTag('foodNum'))
except:
foodNum = 0
if self.boss:
self.boss.localToonTouchedBeltFood(beltIndex, foodIndex, foodNum)
def setupToonupIvals(self):
for i in xrange(len(self.foodNodes)):
toonupIval = self.createOneToonupIval(self.foodNodes[i])
self.toonupIvals.append(toonupIval)
def createOneToonupIval(self, foodNode):
toonupIndex = self.foodNodes.index(foodNode)
waitTimeForOne = self.distBetweenFoodNodes / self.ToonupBeltSpeed
waitTime = waitTimeForOne * toonupIndex
self.toonupWaitTimes.append(waitTime)
totalTimeToTraverseBelt = self.beltLength / self.ToonupBeltSpeed
startPosY = -(self.beltLength / 2.0)
endPosY = self.beltLength / 2.0
retval = Sequence(Func(self.loadToonup, toonupIndex), LerpPosInterval(foodNode, duration=totalTimeToTraverseBelt, startPos=Point3(0, startPosY, self.beltHeight), pos=Point3(0, endPosY, self.beltHeight)), ProjectileInterval(foodNode, startPos=Point3(0, endPosY, self.beltHeight), startVel=Point3(0, self.BeltSpeed, 0), endZ=0), Func(self.removeToonup, toonupIndex))
return retval
def loadToonup(self, toonupIndex):
self.toonupNum += 1
if toonupIndex in self.toonupModelDict:
toonupModel = self.toonupModelDict[toonupIndex]
toonupModel.reparentTo(self.foodNodes[toonupIndex])
colNp = toonupModel.find('**/ToonupCol*')
colNp.setTag('toonupNum', str(self.toonupNum))
else:
toonupModelScale = self.ToonupScales[toonupIndex]
modelName = self.ToonupModels[toonupIndex]
toonupModel = loader.loadModel(modelName)
self.foodNodes[toonupIndex].setZ(self.beltHeight - 0.1)
toonupModel.setZ(self.ToonupZOffsets[toonupIndex])
toonupModel.setScale(toonupModelScale)
toonupModel.reparentTo(self.foodNodes[toonupIndex])
target = CollisionTube(4, 0, 0, -4, 0, 0, 2)
target.setTangible(0)
colName = 'ToonupCol-%d-%d' % (self.index, toonupIndex)
targetNode = CollisionNode(colName)
targetNode.addSolid(target)
targetNode.setCollideMask(ToontownGlobals.WallBitmask)
targetNodePath = toonupModel.attachNewNode(targetNode)
targetNodePath.setScale(1.0 / toonupModelScale)
targetNodePath.setTag('toonupIndex', str(toonupIndex))
targetNodePath.setTag('beltIndex', str(self.index))
targetNodePath.setTag('toonupNum', str(self.toonupNum))
targetNodePath.setZ(targetNodePath.getZ() - 1.5 / toonupModelScale)
self.accept('enter' + colName, self.touchedToonup)
self.toonupModelDict[toonupIndex] = toonupModel
def removeToonup(self, toonupIndex):
if toonupIndex in self.toonupModelDict:
toonupModel = self.toonupModelDict[toonupIndex]
toonupModel.stash()
def touchedToonup(self, colEntry):
if base.localAvatar.hp >= base.localAvatar.maxHp:
return
into = colEntry.getIntoNodePath()
try:
beltIndex = int(into.getTag('beltIndex'))
except:
beltIndex = 0
try:
toonupIndex = int(into.getTag('toonupIndex'))
except:
toonupIndex = 0
try:
toonupNum = int(into.getTag('toonupNum'))
except:
toonupNum = 0
if self.boss:
self.boss.localToonTouchedBeltToonup(beltIndex, toonupIndex, toonupNum)