コード例 #1
0
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)
コード例 #2
0
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)
コード例 #3
0
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)