class DistributedFoodBelt(DistributedObject.DistributedObject, FSM.FSM, FoodBeltBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFoodBelt') BeltSpeed = 5 OnDuration = 300 ToonupBeltSpeed = 1.0 BeltActorPlayRate = 5.3499999999999996 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 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.10000000000000001 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.wav') 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() 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.10000000000000001) debugFood.reparentTo(newFoodNode) newFoodNode.setH(180) self.foodNodes.append(newFoodNode) 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.10000000000000001) 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 None 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)
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.loader.loadSfx( 'phase_12/audio/sfx/CHQ_FACT_conveyor_belt.wav') 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)
class DistributedFoodBelt(DistributedObject.DistributedObject, FSM.FSM, FoodBeltBase): """ This class represents a conveyer belt bringing cog food out, The DistributedLawbotBoss creates 2 of these for the CEO battle scene. """ notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFoodBelt') BeltSpeed = 5 # in feet per second OnDuration = 300 # in seconds, how long the belt moves 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): """Create a new food belt.""" 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 # unique for each food loaded in the belt self.beltActor = None self.toonupIvals = [] self.toonupWaitTimes = [] self.toonupModelDict = {} self.toonupNum = 0 # unique for each toonup loaded in the belt def delete(self): """Delete ourself from the world.""" DistributedObject.DistributedObject.delete(self) self.cleanup() def announceGenerate(self): """Handle all required fields being filled in.""" 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) ##### Messages To/From The Server ##### def setBossCogId(self, bossCogId): """Handle receiving the CEO doId from the server.""" self.bossCogId = bossCogId # This would be risky if we had toons entering the zone during # a battle--but since all the toons are always there from the # beginning, we can be confident that the BossCog has already # been generated by the time we receive the generate for its # associated battles. self.boss = base.cr.doId2do.get(bossCogId) def setIndex(self, index): """Handle receiving the index which identifies our side the server.""" self.index = index # WARNING debug only, remove this #if (index == 0): # base.fb = self def setState(self, state): """Set the state as dictated by the AI.""" 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)) ### FSM States ### def enterOn(self): """Handle entering the on state.""" self.beltSoundInterval.loop() for i in range(len(self.foodNodes)): self.doMethodLater(self.foodWaitTimes[i], self.startFoodMoving, 'start-%d-%d' % (self.index, i), extraArgs = [i]) def exitOn(self): """Handle exiting the on state.""" self.beltSoundInterval.finish() for i in range(len(self.foodNodes)): taskName = 'start-%d-%d' % (self.index, i) self.removeTask(taskName) pass def enterToonup(self): """Handle entering the toonup state.""" self.beltSound.setPlayRate(self.ToonupBeltSpeed / self.BeltSpeed) self.beltSoundInterval.loop() for i in range(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): """Handle exiting the toonup state.""" self.beltSoundInterval.finish() for i in range(len(self.foodNodes)): taskName = 'startToonup-%d-%d' % (self.index, i) self.removeTask(taskName) pass def enterInactive(self): """Handle entering the inactive state.""" for ival in self.foodIvals: ival.finish() for ival in self.toonupIvals: ival.finish() for i in range(len(self.foodNodes)): self.removeFood(i) self.removeToonup(i) if self.beltActor: self.beltActor.stop() def exitInactive(self): """Handle exiting the inactive state.""" pass def startFoodMoving(self, foodIndex): """Start the food moving.""" assert self.notify.debugStateCall(self) 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): """Start the food moving.""" assert self.notify.debugStateCall(self) 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') ### loading assets ### def loadAssets(self): """Load and setup the assets for the food belt.""" # later on this will become a loadModel call 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) # adjust this number as necessary to match up with the food intervals self.beltActor.setPlayRate(self.BeltActorPlayRate, 'idle') #self.beltActor.loop('idle') # 1st uv animation 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.loader.loadSfx("phase_12/audio/sfx/CHQ_FACT_conveyor_belt.wav") 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 range(len(self.foodNodes)): taskName = 'start-%d-%d' % (self.index, i) self.removeTask(taskName) for i in range(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() def setupFoodNodes(self): """Create the node paths the food will be parented to.""" assert self.notify.debugStateCall(self) # we may later just load this from the belt model for i in range(self.NumFoodNodes): # we want index 0 to be the first one out 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 # loader.loadModel('models/misc/xyzAxis') if debugFood: debugFood.setScale(0.1) debugFood.reparentTo(newFoodNode) # to make the front side of the cans come out of the belt newFoodNode.setH(180) self.foodNodes.append(newFoodNode) def setupFoodIvals(self): """Create all the food intervals for the belt.""" assert self.notify.debugStateCall(self) for i in range(len(self.foodNodes)): foodIval = self.createOneFoodIval(self.foodNodes[i]) self.foodIvals.append(foodIval) def createOneFoodIval(self, foodNode): """Create and return a food Interval for this node. This does not include the initial wait for the food to appear """ 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): """Load the food into a food node.""" 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]) # create a collision tube so toons can get the food 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)) # lower it a little bit to be easier to collide with targetNodePath.setZ(targetNodePath.getZ()-1.5) self.accept('enter'+colName, self.touchedFood) self.foodModelDict[foodIndex] = foodModel def removeFood(self, foodIndex): """Remove the food from a food node.""" if foodIndex in self.foodModelDict: foodModel = self.foodModelDict[foodIndex] foodModel.stash() def touchedFood(self, colEntry): """Handle a toon touching the food collision.""" 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 #self.notify.debug('touched food, beltIndex=%d, foodIndex=%d foodNum==%d' % # (beltIndex, foodIndex, foodNum)) if self.boss: self.boss.localToonTouchedBeltFood(beltIndex, foodIndex, foodNum) def setupToonupIvals(self): """Create all the toonup intervals for the belt.""" assert self.notify.debugStateCall(self) for i in range(len(self.foodNodes)): toonupIval = self.createOneToonupIval(self.foodNodes[i]) self.toonupIvals.append(toonupIval) def createOneToonupIval(self, foodNode): """Create and return a toonup Interval for this node. This does not include the initial wait for the toonup to appear """ 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): """Load the toonup into a food node.""" 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]) # create a collision tube so toons can get the toonup 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)) # lower it a little bit to be easier to collide with targetNodePath.setZ(targetNodePath.getZ()- (1.5 / toonupModelScale) ) self.accept('enter'+colName, self.touchedToonup) self.toonupModelDict[toonupIndex] = toonupModel def removeToonup(self, toonupIndex): """Remove the toonup from a toonup node.""" if toonupIndex in self.toonupModelDict: toonupModel = self.toonupModelDict[toonupIndex] toonupModel.stash() def touchedToonup(self, colEntry): """Handle a toon touching the toonup collision.""" # don't get a toonup if you're at full laff 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 #self.notify.debug('touched toonup, beltIndex=%d, toonupIndex=%d toonupNum==%d' % # (beltIndex, toonupIndex, toonupNum)) if self.boss: self.boss.localToonTouchedBeltToonup(beltIndex, toonupIndex, toonupNum)