示例#1
0
class DistributedArcadeBattleZoneAI(DistributedBattleZoneAI):
    notify = directNotify.newCategory('DistributedArcadeBattleZoneAI')

    def __init__(self, air):
        DistributedBattleZoneAI.__init__(self, air)
        self.battleType = BattleGlobals.BTArcade
        self.matchData = None
        self.fsm = ClassicFSM('DistributedArcadeBattleZoneAI', [
            State('off', self.enterOff, self.exitOff),
        ], 'off', 'off')
        self.readyAvatars = []

        # Variables related to turrets
        self.turretMgr = None

    def announceGenerate(self):
        DistributedBattleZoneAI.announceGenerate(self)
        self.turretMgr = DistributedPieTurretManagerAI(self.air)
        self.turretMgr.generateWithRequired(self.zoneId)
        self.fsm.enterInitialState()

    def enterOff(self):
        pass

    def exitOff(self):
        pass
示例#2
0
class Walk(StateData):
    notify = directNotify.newCategory("Walk")

    def __init__(self, doneEvent):
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('Walk', [
            State('off', self.enterOff, self.exitOff, ['walking', 'deadWalking']),
            State('walking', self.enterWalking, self.exitWalking),
            State('deadWalking', self.enterDeadWalking, self.exitDeadWalking)],
            'off', 'off')
        self.fsm.enterInitialState()

    def unload(self):
        del self.fsm

    def enter(self, wantMouse = 0):
        base.localAvatar.startPlay(wantMouse = wantMouse)

    def exit(self):
        if base.localAvatarReachable():
            base.localAvatar.lastState = None
            self.fsm.request('off')
            base.localAvatar.stopPlay()
        

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterWalking(self):
        if base.localAvatar.getHealth() > 0:
            base.localAvatar.startTrackAnimToSpeed()
            #base.localAvatar.setWalkSpeedNormal()
        else:
            self.fsm.request('deadWalking')

    def exitWalking(self):
        base.localAvatar.stopTrackAnimToSpeed()

    def enterDeadWalking(self):
        base.localAvatar.startTrackAnimToSpeed()
        base.localAvatar.setWalkSpeedSlow()
        base.taskMgr.add(self.__watchForPositiveHP, base.localAvatar.uniqueName('watchforPositiveHP'))

    def __watchForPositiveHP(self, task):
        if base.localAvatar.getHealth() > 0:
            self.fsm.request('walking')
            return task.done
        return task.cont

    def exitDeadWalking(self):
        base.taskMgr.remove(base.localAvatar.uniqueName('watchforPositiveHP'))
        base.localAvatar.stopTrackAnimToSpeed()
示例#3
0
class ToonInterior(Place.Place):
    notify = directNotify.newCategory("ToonInterior")

    def __init__(self, hood, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        Place.Place.__init__(self, hood, doneEvent)
        self.interior = True
        self.fsm = ClassicFSM('ToonInterior', [
            State('start', self.enterStart, self.exitStart,
                  ['doorOut', 'teleportIn']),
            State('walk', self.enterWalk, self.exitWalk,
                  ['stop', 'doorIn', 'shtickerBook', 'teleportOut']),
            State('shtickerBook', self.enterShtickerBook,
                  self.exitShtickerBook, ['teleportOut', 'walk']),
            State('teleportOut', self.enterTeleportOut, self.exitTeleportOut,
                  ['teleportIn', 'stop']),
            State('teleportIn', self.enterTeleportIn, self.exitTeleportIn,
                  ['walk', 'stop']),
            State('tunnelOut', self.enterTunnelOut, self.exitTunnelOut,
                  ['walk']),
            State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
            State('stop', self.enterStop, self.exitStop,
                  ['walk', 'died', 'teleportOut', 'doorIn']),
            State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
            State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
            State('final', self.enterFinal, self.exitFinal, ['final'])
        ], 'start', 'final')

    def enter(self, requestStatus):
        Place.Place.enter(self)
        self.fsm.enterInitialState()
        base.playMusic(self.loader.interiorSong, looping=1)
        self.fsm.request(requestStatus['how'], [requestStatus])
        return

    def exit(self):
        base.stopMusic()
        Place.Place.exit(self)

    def load(self):
        Place.Place.load(self)
        self.parentFSM.getStateNamed('toonInterior').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('toonInterior').removeChild(self.fsm)
        del self.fsm
        del self.parentFSM
        self.ignoreAll()
        Place.Place.unload(self)
        return
示例#4
0
class ToonInterior(Place.Place):
    notify = directNotify.newCategory('ToonInterior')

    def __init__(self, hood, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        Place.Place.__init__(self, hood, doneEvent)
        self.fsm = ClassicFSM('ToonInterior', [State('start', self.enterStart, self.exitStart, ['doorOut', 'teleportIn']),
         State('walk', self.enterWalk, self.exitWalk, ['stop',
          'doorIn',
          'shtickerBook',
          'teleportOut']),
         State('shtickerBook', self.enterShtickerBook, self.exitShtickerBook, ['teleportOut', 'walk']),
         State('teleportOut', self.enterTeleportOut, self.exitTeleportOut, ['teleportIn', 'stop']),
         State('teleportIn', self.enterTeleportIn, self.exitTeleportIn, ['walk', 'stop']),
         State('tunnelOut', self.enterTunnelOut, self.exitTunnelOut, ['walk']),
         State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
         State('stop', self.enterStop, self.exitStop, ['walk',
          'died',
          'teleportOut',
          'doorIn']),
         State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
         State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
         State('final', self.enterFinal, self.exitFinal, ['final'])], 'start', 'final')

    def enter(self, requestStatus):
        Place.Place.enter(self)
        self.fsm.enterInitialState()
        base.playMusic(self.loader.interiorMusic, volume=0.8, looping=1)
        self.fsm.request(requestStatus['how'], [requestStatus])

    def exit(self):
        self.loader.interiorMusic.stop()
        Place.Place.exit(self)

    def load(self):
        Place.Place.load(self)
        self.parentFSM.getStateNamed('toonInterior').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('toonInterior').removeChild(self.fsm)
        del self.fsm
        del self.parentFSM
        self.ignoreAll()
        Place.Place.unload(self)
示例#5
0
class Street(Place):
    notify = directNotify.newCategory("Street")

    def __init__(self, loader, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        Place.__init__(self, loader, doneEvent)
        self.fsm = ClassicFSM('Street', [
            State(
                'start', self.enterStart, self.exitStart,
                ['walk', 'doorOut', 'teleportIn', 'tunnelOut', 'elevatorIn']),
            State('walk', self.enterWalk, self.exitWalk,
                  ['stop', 'tunnelIn', 'shtickerBook', 'teleportOut']),
            State('shtickerBook', self.enterShtickerBook,
                  self.exitShtickerBook, ['teleportOut', 'walk']),
            State('teleportOut', self.enterTeleportOut, self.exitTeleportOut,
                  ['teleportIn', 'stop']),
            State('tunnelOut', self.enterTunnelOut, self.exitTunnelOut,
                  ['walk']),
            State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
            State('stop', self.enterStop, self.exitStop,
                  ['walk', 'died', 'teleportOut', 'doorIn']),
            State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
            State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
            State('teleportIn', self.enterTeleportIn, self.exitTeleportIn,
                  ['walk', 'stop']),
            State('elevatorIn', self.enterElevatorIn, self.exitElevatorIn,
                  ['walk', 'stop']),
            State('final', self.enterFinal, self.exitFinal, ['final'])
        ], 'start', 'final')

    def enterElevatorIn(self, requestStatus):
        taskMgr.add(self.elevatorInTask,
                    'Street.elevatorInTask',
                    extraArgs=[requestStatus['bldgDoId']],
                    appendTask=True)

    def elevatorInTask(self, bldgDoId, task):
        bldg = base.cr.doId2do.get(bldgDoId)
        if bldg:
            if bldg.elevatorNodePath is not None:
                if self._enterElevatorGotElevator():
                    return task.done
        return task.cont

    def _enterElevatorGotElevator(self):
        if not messenger.whoAccepts('insideVictorElevator'):
            return False
        messenger.send('insideVictorElevator')
        return True

    def exitElevatorIn(self):
        taskMgr.remove('Street.elevatorInTask')

    def enter(self, requestStatus, visibilityFlag=1):
        Place.enter(self)
        self.fsm.enterInitialState()
        base.playMusic(self.loader.music, volume=0.8, looping=1)
        self.loader.geom.reparentTo(render)
        if visibilityFlag:
            self.visibilityOn()
        self.loader.hood.startSky()
        self.enterZone(requestStatus['zoneId'])
        self.fsm.request(requestStatus['how'], [requestStatus])
        return

    def exit(self, vis=1):
        if vis:
            self.visibilityOff()
        self.loader.geom.reparentTo(hidden)
        self.loader.hood.stopSky()
        self.loader.music.stop()
        Place.exit(self)

    def load(self):
        Place.load(self)
        self.parentFSM.getStateNamed('street').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('street').removeChild(self.fsm)
        del self.fsm
        del self.parentFSM
        self.enterZone(None)
        self.ignoreAll()
        Place.unload(self)
        return

    def hideAllVisibles(self):
        for i in self.loader.nodeList:
            i.stash()

    def showAllVisibles(self):
        for i in self.loader.nodeList:
            i.unstash()

    def visibilityOn(self):
        self.hideAllVisibles()
        self.accept('on-floor', self.enterZone)

    def visibilityOff(self):
        self.ignore('on-floor')
        self.showAllVisibles()

    def enterZone(self, newZone):
        if isinstance(newZone, CollisionEntry):
            try:
                newZoneId = int(newZone.getIntoNode().getName())
            except:
                self.notify.warning(
                    'Invalid floor collision node in street: %s' %
                    newZone.getIntoNode().getName())
                return
        else:
            newZoneId = newZone
        self.doEnterZone(newZoneId)

    def doEnterZone(self, newZoneId):
        visualizeZones = 0
        if self.zoneId != None:
            for i in self.loader.nodeDict[self.zoneId]:
                if newZoneId:
                    if i not in self.loader.nodeDict[newZoneId]:
                        self.loader.fadeOutDict[i].start()
                else:
                    i.stash()

        if newZoneId != None:
            for i in self.loader.nodeDict[newZoneId]:
                if self.zoneId:
                    if i not in self.loader.nodeDict[self.zoneId]:
                        self.loader.fadeInDict[i].start()
                else:
                    if self.loader.fadeOutDict[i].isPlaying():
                        self.loader.fadeOutDict[i].finish()
                    if self.loader.fadeInDict[i].isPlaying():
                        self.loader.fadeInDict[i].finish()
                    i.unstash()

        if newZoneId != self.zoneId:
            if visualizeZones:
                if self.zoneId != None:
                    self.loader.zoneDict[self.zoneId].clearColor()
                if newZoneId != None:
                    self.loader.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100)
            if newZoneId is not None:
                loader = base.cr.playGame.getPlace().loader
                if newZoneId in loader.zoneVisDict:
                    base.cr.sendSetZoneMsg(newZoneId,
                                           loader.zoneVisDict[newZoneId])
                else:
                    visList = [newZoneId] + loader.zoneVisDict.values()[0]
                    base.cr.sendSetZoneMsg(newZoneId, visList)
            self.zoneId = newZoneId
        geom = base.cr.playGame.getPlace().loader.geom
        return
示例#6
0
class RaceGameMovement(DirectObject):
    MINIMUM_POWER = 0.3
    MINIMUM_KEY_DELAY = 0.015
    POWER_FACTOR = 2.5
    defaultBoostBarColor = (0.4, 0.4, 0.7, 1.0)
    fullBoostBarColor = (0.0, 0.0, 0.7, 1.0)

    def __init__(self, avatar):
        DirectObject.__init__(self)
        self.avatar = avatar
        self.power = self.MINIMUM_POWER
        self.boost = 0.0
        self.fsm = ClassicFSM('RaceGameMovement', [State('off', self.enterOff, self.exitOff, ['run']),
         State('run', self.enterRun, self.exitRun, ['fall', 'off']),
         State('fall', self.enterFall, self.exitFall, ['run', 'off']),
         State('final', self.enterFinal, self.exitFinal)], 'off', 'final')
        self.fsm.enterInitialState()
        self.boostFSM = ClassicFSM('Boost', [State('off', self.enterBoostOff, self.exitBoostOff, ['boost']), State('boost', self.enterBoost, self.exitBoost)], 'off', 'off')
        self.boostFSM.enterInitialState()
        self.keysPressed = {'arrow_left': 0,
         'arrow_right': 0}
        self.startTime = 0.0
        self.endTime = 0.0
        self.fallTrack = None
        self.isStopped = True
        self.isBoosting = False
        return

    def setBoosting(self, value):
        self.isBoosting = value

    def getBoosting(self):
        return self.isBoosting

    def enterBoostOff(self):
        self.ignore('control')

    def exitBoostOff(self):
        pass

    def createGui(self):
        """ Create the GUI that will tell the client how much
        running power they have. """
        self.powerFrame = DirectFrame()
        self.powerBg = OnscreenImage(image=DGG.getDefaultDialogGeom(), scale=(0.5, 1.0, 0.5), pos=(1.02, 0, 0.7), parent=self.powerFrame, color=CIGlobals.DialogColor)
        self.powerBar = DirectWaitBar(barColor=(0, 0.7, 0, 1), range=20.0, value=0, parent=self.powerFrame, scale=(0.15, 0, 1.1), pos=(1.02, 0, 0.66))
        self.powerBar.setR(-90)
        self.powerTitle = DirectLabel(text='POWER', text_scale=0.08, pos=(1.02, 0, 0.85), relief=None, parent=self.powerFrame, text_fg=(1, 1, 0, 1), text_font=CIGlobals.getMickeyFont())
        self.boostFrame = DirectFrame()
        self.boostBg = OnscreenImage(image=DGG.getDefaultDialogGeom(), scale=(0.5, 1.0, 0.5), pos=(0.45, 0, 0.7), parent=self.boostFrame, color=CIGlobals.DialogColor)
        self.boostBar = DirectWaitBar(barColor=self.defaultBoostBarColor, range=10, value=0, parent=self.boostFrame, scale=(0.15, 0, 1.1), pos=(0.45, 0, 0.66))
        self.boostBar.setR(-90)
        self.boostTitle = DirectLabel(text='BOOST', text_scale=0.08, pos=(0.45, 0, 0.85), relief=None, parent=self.boostFrame, text_fg=(1, 1, 0, 1), text_font=CIGlobals.getMickeyFont())
        self.boostFullLbl = DirectLabel(text='BOOST READY', text_scale=0.065, pos=(0.45, 0, 0.3), relief=None, parent=self.boostFrame, text_fg=self.fullBoostBarColor, text_shadow=(0.4, 0.4, 0.4, 1.0), text_font=CIGlobals.getToonFont())
        self.boostFullLbl.hide()
        return

    def deleteGui(self):
        """ Delete the GUI that will tell the client how much
        running power they have. """
        self.powerFrame.destroy()
        self.powerBg.destroy()
        self.powerBar.destroy()
        self.powerTitle.destroy()
        self.boostFrame.destroy()
        self.boostBg.destroy()
        self.boostBar.destroy()
        self.boostTitle.destroy()
        self.boostFullLbl.destroy()

    def enableArrowKeys(self):
        """ Enable the arrow keys to increase movement power. """
        self.accept('arrow_left', self.keyPressed, ['arrow_left'])
        self.accept('arrow_right', self.keyPressed, ['arrow_right'])

    def disableArrowKeys(self):
        """ Disable the arrow keys to increase movement power. """
        self.ignore('arrow_left')
        self.ignore('arrow_right')

    def boostKeyPressed(self):
        self.boostFullLbl.hide()
        self.boostFSM.request('boost')

    def keyPressed(self, key):
        """ Figure out which key was pressed and increment the movement power
        if the values of both keys are 1. Also, make the avatar fall down if
        the time between key presses is too fast or the avatar pressed the same
        key more than once."""
        self.stopDelayTimer()
        if self.keysPressed[key] == 1 or self.isTooFast():
            self.resetKeys()
            self.fsm.request('fall')
            return
        self.keysPressed[key] = 1
        if self.keysPressed['arrow_left'] == 1 and self.keysPressed['arrow_right'] == 1:
            self.resetKeys()
            self.changePower()
            self.restartDelayTimer()

    def enterBoost(self):
        self.disableArrowKeys()
        self.resetKeys()
        base.localAvatar.b_setAnimState('swim')
        self.power = 30.0
        taskMgr.add(self.boostTask, 'boostTask')
        self.boostSfx = base.loadSfx('phase_6/audio/sfx/KART_turboLoop.wav')
        base.playSfx(self.boostSfx, looping=1)

    def exitBoost(self):
        self.enableArrowKeys()
        base.localAvatar.b_setAnimState('run')
        self.power = 17.0
        taskMgr.remove('boostTask')
        self.boostSfx.stop()
        del self.boostSfx

    def boostTask(self, task):
        if self.boostBar['value'] <= 0.0:
            self.boostFSM.request('off')
            self.boostBar['barColor'] = self.defaultBoostBarColor
            return task.done
        self.boostBar['value'] -= 0.3
        task.delayTime = 0.05
        return task.again

    def enterFall(self):
        """ The avatar is pressing his arrow keys too fast. Stop running and
        make the avatar fall down. """
        self.avatar.b_setAnimState('fallFWD')
        self.fallTrack = Sequence(Wait(2.5), Func(self.fsm.request, 'run'))
        self.fallTrack.start()

    def exitFall(self):
        self.fallTrack.pause()
        self.fallTrack = None
        return

    def isTooFast(self):
        """ Determine if the delay between key presses in seconds is too low. """
        return self.getDelayTime() < self.MINIMUM_KEY_DELAY

    def resetKeys(self):
        """ Reset the value of the keys. """
        for key in self.keysPressed:
            self.keysPressed[key] = 0

    def changePower(self):
        """ Increase the avatar's movement power. """
        self.power = self.POWER_FACTOR / self.getDelayTime()
        if self.boostBar['barColor'] != self.fullBoostBarColor:
            if self.power >= self.powerBar['range']:
                self.boostBar['value'] += 0.8
                if self.boostBar['value'] >= self.boostBar['range']:
                    self.boostBar['barColor'] = self.fullBoostBarColor
                    self.boostFullLbl.show()
                    self.acceptOnce('control', self.boostKeyPressed)
        print self.power
        self.powerBar.update(self.power)

    def startDelayTimer(self):
        self.startTime = globalClock.getFrameTime()

    def stopDelayTimer(self):
        self.endTime = globalClock.getFrameTime()

    def resetDelayTimer(self):
        self.startTime = 0.0
        self.endTime = 0.0

    def restartDelayTimer(self):
        self.stopDelayTimer()
        self.resetDelayTimer()
        self.startDelayTimer()

    def getDelayTime(self):
        return self.endTime - self.startTime

    def enterRun(self):
        """ Start moving the avatar, make the avatar run, and
        start tracking the delay between key presses. """
        taskMgr.add(self.move, 'move')
        if self.boostBar['barColor'] == self.fullBoostBarColor:
            self.boostFullLbl.show()
            self.acceptOnce('control', self.boostKeyPressed)
        self.startDelayTimer()
        self.enableArrowKeys()
        self.avatar.b_setAnimState('run')
        self.isStopped = False

    def exitRun(self):
        """ Stop moving the avatar, make the avatar stand, and stop
        tracking the delay between key presses. """
        taskMgr.remove('move')
        self.boostFSM.request('off')
        if self.boostBar['barColor'] == self.fullBoostBarColor:
            self.boostFullLbl.hide()
            self.ignore('control')
        self.stopDelayTimer()
        self.resetDelayTimer()
        self.disableArrowKeys()
        self.avatar.b_setAnimState('neutral')
        self.isStopped = True
        self.power = self.MINIMUM_POWER
        self.powerBar.update(0)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterFinal(self):
        pass

    def exitFinal(self):
        pass

    def decreasePower(self, task):
        """ Decrease power so the avatar does not keep the same amount
        of power while not tapping the arrow keys. """
        if self.power > self.MINIMUM_POWER:
            self.power -= self.POWER_FACTOR / 0.01
            if self.power < self.MINIMUM_POWER:
                self.power = self.MINIMUM_POWER
        task.delayTime = 0.5
        return Task.again

    def move(self, task):
        """ Move the avatar forward on the Y axis with the current amount of power. """
        dt = globalClock.getDt()
        self.avatar.setY(self.avatar.getY() + self.power * dt)
        return Task.cont

    def cleanup(self):
        self.fsm.requestFinalState()
示例#7
0
class PlayGame(StateData):
    notify = directNotify.newCategory('PlayGame')

    Hood2HoodClass = {ZoneUtil.ToontownCentral: TTHood.TTHood,
                ZoneUtil.MinigameArea: MGHood.MGHood,
                ZoneUtil.TheBrrrgh: BRHood.BRHood,
                ZoneUtil.DonaldsDreamland: DLHood.DLHood,
                ZoneUtil.MinniesMelodyland: MLHood.MLHood,
                ZoneUtil.DaisyGardens: DGHood.DGHood,
                ZoneUtil.DonaldsDock: DDHood.DDHood,
                ZoneUtil.BattleTTC: CTCHood.CTCHood,
                ZoneUtil.CogTropolis: CTHood.CTHood}
    Hood2HoodState = {ZoneUtil.ToontownCentral: 'TTHood',
                ZoneUtil.MinigameArea: 'MGHood',
                ZoneUtil.TheBrrrgh: 'BRHood',
                ZoneUtil.DonaldsDreamland: 'DLHood',
                ZoneUtil.MinniesMelodyland: 'MLHood',
                ZoneUtil.DaisyGardens: 'DGHood',
                ZoneUtil.DonaldsDock: 'DDHood',
                ZoneUtil.BattleTTC: 'CTCHood',
                ZoneUtil.CogTropolis: 'CTHood'}

    def __init__(self, parentFSM, doneEvent):
        StateData.__init__(self, "playGameDone")
        self.doneEvent = doneEvent
        self.fsm = ClassicFSM('World', [State('off', self.enterOff, self.exitOff, ['quietZone']),
                State('quietZone', self.enterQuietZone, self.exitQuietZone, ['TTHood',
                    'BRHood', 'DLHood', 'MLHood', 'DGHood', 'DDHood', 'MGHood', 'CTCHood', 'CTHood']),
                State('TTHood', self.enterTTHood, self.exitTTHood, ['quietZone']),
                State('BRHood', self.enterBRHood, self.exitBRHood, ['quietZone']),
                State('DLHood', self.enterDLHood, self.exitDLHood, ['quietZone']),
                State('MLHood', self.enterMLHood, self.exitMLHood, ['quietZone']),
                State('DGHood', self.enterDGHood, self.exitDGHood, ['quietZone']),
                State('DDHood', self.enterDDHood, self.exitDDHood, ['quietZone']),
                State('MGHood', self.enterMGHood, self.exitMGHood, ['quietZone']),
                State('CTCHood', self.enterCTCHood, self.exitCTCHood, ['quietZone']),
                State('CTHood', self.enterCTHood, self.exitCTHood, ['quietZone'])],
                'off', 'off')
        self.fsm.enterInitialState()

        self.parentFSM = parentFSM
        self.parentFSM.getStateNamed('playGame').addChild(self.fsm)

        self.hoodDoneEvent = 'hoodDone'
        self.hood = None
        self.quietZoneDoneEvent = uniqueName('quietZoneDone')
        self.quietZoneStateData = None
        self.place = None
        self.lastHood = None
        self.suitManager = None

    def enter(self, hoodId, zoneId, avId):
        StateData.enter(self)
        whereName = ZoneUtil.getWhereName(zoneId)
        loaderName = ZoneUtil.getLoaderName(zoneId)
        self.fsm.request('quietZone', [{'zoneId': zoneId,
            'hoodId': hoodId,
            'where': whereName,
            'how': 'teleportIn',
            'avId': avId,
            'shardId': None,
            'loader': loaderName}])

    def exit(self):
        StateData.exit(self)

    def getCurrentWorldName(self):
        return self.fsm.getCurrentState().getName()

    def enterOff(self):
        pass

    def exitOff(self):
        pass
        
    def enterCTHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitCTHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.CogTropolis

    def enterCTCHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitCTCHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.ToontownCentral

    def enterDDHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitDDHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.DonaldsDock

    def enterDGHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitDGHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.DaisyGardens

    def enterMLHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitMLHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.MinniesMelodyland

    def enterDLHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitDLHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.DonaldsDreamland

    def enterBRHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitBRHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.TheBrrrgh

    def enterTTHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitTTHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.ToontownCentral

    def enterMGHood(self, requestStatus):
        self.accept(self.hoodDoneEvent, self.handleHoodDone)
        self.hood.enter(requestStatus)

    def exitMGHood(self):
        self.ignore(self.hoodDoneEvent)
        self.hood.exit()
        self.hood.unload()
        self.hood = None
        self.lastHood = ZoneUtil.MinigameArea

    def handleHoodDone(self):
        doneStatus = self.hood.getDoneStatus()
        if doneStatus['zoneId'] is None:
            self.doneStatus = doneStatus
            messenger.send(self.doneEvent)
        else:
            self.fsm.request('quietZone', [doneStatus])

    def loadDNAStore(self):
        if hasattr(self, 'dnaStore'):
            self.dnaStore.reset_nodes()
            self.dnaStore.reset_hood_nodes()
            self.dnaStore.reset_place_nodes()
            self.dnaStore.reset_hood()
            self.dnaStore.reset_fonts()
            self.dnaStore.reset_DNA_vis_groups()
            self.dnaStore.reset_materials()
            self.dnaStore.reset_block_numbers()
            self.dnaStore.reset_block_zones()
            self.dnaStore.reset_suit_points()
            del self.dnaStore

        self.dnaStore = DNAStorage()
        loadDNAFile(self.dnaStore, 'phase_4/dna/storage.pdna')
        self.dnaStore.storeFont('humanist', CIGlobals.getToonFont())
        self.dnaStore.storeFont('mickey', CIGlobals.getMickeyFont())
        self.dnaStore.storeFont('suit', CIGlobals.getSuitFont())
        loadDNAFile(self.dnaStore, 'phase_3.5/dna/storage_interior.pdna')

    def enterQuietZone(self, requestStatus):
        self.acceptOnce(self.quietZoneDoneEvent, self.handleQuietZoneDone, [requestStatus])
        self.acceptOnce('enteredQuietZone', self.handleEnteredQuietZone, [requestStatus])
        self.quietZoneStateData = QuietZoneState(self.quietZoneDoneEvent, 0)
        self.quietZoneStateData.load()
        self.quietZoneStateData.enter(requestStatus)

    def handleEnteredQuietZone(self, requestStatus):
        hoodId = requestStatus['hoodId']
        if self.Hood2HoodClass.has_key(hoodId):
            hoodClass = self.Hood2HoodClass[hoodId]
            base.transitions.noTransitions()
            loader.beginBulkLoad('hood', hoodId, 100)
            self.loadDNAStore()
            self.hood = hoodClass(self.fsm, self.hoodDoneEvent, self.dnaStore, hoodId)
            self.hood.load()

            hoodState = self.Hood2HoodState[hoodId]
            self.fsm.request(hoodState, [requestStatus], exitCurrent = 0)
        self.quietZoneStateData.fsm.request('waitForSetZoneResponse')

    def handleQuietZoneDone(self, requestStatus):
        if self.hood:
            self.hood.enterTheLoader(requestStatus)
            self.hood.loader.enterThePlace(requestStatus)
            loader.endBulkLoad('hood')
        self.exitQuietZone()

    def exitQuietZone(self):
        if self.quietZoneStateData:
            self.ignore('enteredQuietZone')
            self.ignore(self.quietZoneDoneEvent)
            self.quietZoneStateData.exit()
            self.quietZoneStateData.unload()
            self.quietZoneStateData = None

    def setPlace(self, place):
        self.place = place

    def getPlace(self):
        return self.place
示例#8
0
class Suit(Avatar.Avatar):
	healthColors = (Vec4(0, 1, 0, 1),
		Vec4(1, 1, 0, 1),
		Vec4(1, 0.5, 0, 1),
		Vec4(1, 0, 0, 1),
		Vec4(0.3, 0.3, 0.3, 1))
	healthGlowColors = (Vec4(0.25, 1, 0.25, 0.5),
		Vec4(1, 1, 0.25, 0.5),
		Vec4(1, 0.5, 0.25, 0.5),
		Vec4(1, 0.25, 0.25, 0.5),
		Vec4(0.3, 0.3, 0.3, 0))
	medallionColors = {'c': Vec4(0.863, 0.776, 0.769, 1.0),
		's': Vec4(0.843, 0.745, 0.745, 1.0),
		'l': Vec4(0.749, 0.776, 0.824, 1.0),
		'm': Vec4(0.749, 0.769, 0.749, 1.0)}
	health2DmgMultiplier = 2.5
	
	def __init__(self):
		try:
			self.Suit_initialized
			return
		except:
			self.Suit_initialized = 1
		
		Avatar.Avatar.__init__(self)
		self.avatarType = CIGlobals.Suit
		self.name = ''
		self.chat = ''
		self.suit = None
		self.suitHeads = None
		self.suitHead = None
		self.loserSuit = None
		self.healthMeterGlow = None
		self.healthMeter = None
		self.weapon = None
		self.weapon_sfx = None
		self.anim = None
		self.suit_dial = None
		self.shadow = None
		self.balloon_sfx = None
		self.add_sfx = None
		self.explosion = None
		self.largeExp = None
		self.smallExp = None
		self.death_sfx = None
		self.attack = None
		self.wtrajectory = None
		self.throwObjectId = None
		self.hasSpawned = False
		self.condition = 0
		self.type = ""
		self.head = ""
		self.team = ""
		self.isSkele = 0
		self.animFSM = ClassicFSM('Suit', [State('off', self.enterOff, self.exitOff),
								State('neutral', self.enterNeutral, self.exitNeutral),
								State('walk', self.enterWalk, self.exitWalk),
								State('die', self.enterDie, self.exitDie),
								State('attack', self.enterAttack, self.exitAttack),
								State('flydown', self.enterFlyDown, self.exitFlyDown),
								State('pie', self.enterPie, self.exitPie),
								State('win', self.enterWin, self.exitWin),
								State('flyaway', self.enterFlyAway, self.exitFlyAway),
								State('rollodex', self.enterRollodex, self.exitRollodex)], 'off', 'off')
		animStateList = self.animFSM.getStates()
		self.animFSM.enterInitialState()
		
		self.initializeBodyCollisions()
		
	def delete(self):
		try:
			self.Suit_deleted
		except:
			self.Suit_deleted = 1
			if self.suit:
				self.cleanupSuit()
			if self.loserSuit:
				self.cleanupLoserSuit()
			if self.suitHeads:
				self.suitHeads.remove()
				self.suitHeads = None
			if self.suitHead:
				self.suitHead.remove()
				self.suitHead = None
			if self.healthMeterGlow:
				self.healthMeterGlow.remove()
				self.healthMeterGlow = None
			if self.healthMeter:
				self.healthMeter.remove()
				self.healthMeter = None
			if self.shadow:
				self.shadow.remove()
				self.shadow = None
			self.weapon = None
			self.weapon_sfx = None
			self.suit_dial = None
			del self.shadowPlacer
			
	def generateSuit(self, suitType, suitHead, suitTeam, suitHealth, skeleton):
		self.health = suitHealth
		self.maxHealth = suitHealth
		self.generateBody(suitType, suitTeam, suitHead, skeleton)
		self.generateHealthMeter()
		self.generateHead(suitType, suitHead)
		self.setupNameTag()
		Avatar.Avatar.initShadow(self)
		
	def generateBody(self, suitType, suitTeam, suitHead, skeleton):
		if self.suit:
			self.cleanupSuit()
			
		self.team = suitTeam
		self.type = suitType
		self.head = suitHead
		self.isSkele = skeleton
		
		if suitType == "A":
			if skeleton:
				self.suit = Actor("phase_5/models/char/cogA_robot-zero.bam")
			else:
				self.suit = Actor("phase_3.5/models/char/suitA-mod.bam")
			self.suit.loadAnims({"neutral": "phase_4/models/char/suitA-neutral.bam",
							"walk": "phase_4/models/char/suitA-walk.bam",
							"pie": "phase_4/models/char/suitA-pie-small.bam",
							"land": "phase_5/models/char/suitA-landing.bam",
							"throw-object": "phase_5/models/char/suitA-throw-object.bam",
							"throw-paper": "phase_5/models/char/suitA-throw-paper.bam",
							"glower": "phase_5/models/char/suitA-glower.bam",
							"win": "phase_4/models/char/suitA-victory.bam",
							"rollodex": "phase_5/models/char/suitA-roll-o-dex.bam"})
		if suitType == "B":
			if skeleton:
				self.suit = Actor("phase_5/models/char/cogB_robot-zero.bam")
			else:
				self.suit = Actor("phase_3.5/models/char/suitB-mod.bam")
			self.suit.loadAnims({"neutral": "phase_4/models/char/suitB-neutral.bam",
							"walk": "phase_4/models/char/suitB-walk.bam",
							"pie": "phase_4/models/char/suitB-pie-small.bam",
							"land": "phase_5/models/char/suitB-landing.bam",
							"throw-object": "phase_5/models/char/suitB-throw-object.bam",
							"throw-paper": "phase_5/models/char/suitB-throw-paper.bam",
							"glower": "phase_5/models/char/suitB-magic1.bam",
							"win": "phase_4/models/char/suitB-victory.bam",
							"rollodex": "phase_5/models/char/suitB-roll-o-dex.bam"})
		if suitType == "C":
			if skeleton:
				self.suit = Actor("phase_5/models/char/cogC_robot-zero.bam")
			else:
				self.suit = Actor("phase_3.5/models/char/suitC-mod.bam")
			self.suit.loadAnims({"neutral": "phase_3.5/models/char/suitC-neutral.bam",
						"walk": "phase_3.5/models/char/suitC-walk.bam",
						"pie": "phase_3.5/models/char/suitC-pie-small.bam",
						"land": "phase_5/models/char/suitC-landing.bam",
						"throw-object": "phase_3.5/models/char/suitC-throw-paper.bam",
						"throw-paper": "phase_3.5/models/char/suitC-throw-paper.bam",
						"glower": "phase_5/models/char/suitC-glower.bam",
						"win": "phase_4/models/char/suitC-victory.bam"})
		if skeleton:
			self.suit.setTwoSided(1)
		self.suit.getGeomNode().setScale(CIGlobals.SuitScales[suitHead] / CIGlobals.SuitScaleFactors[suitType])
		
		if skeleton:
			if suitTeam == "s":
				self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_sales.jpg")
			elif suitTeam == "m":
				self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_money.jpg")
			elif suitTeam == "l":
				self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_legal.jpg")
			elif suitTeam == "c":
				self.suit_tie = loader.loadTexture("phase_5/maps/cog_robot_tie_boss.jpg")
			self.suit.find('**/tie').setTexture(self.suit_tie, 1)
		else:
			self.suit_blazer = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_blazer.jpg")
			self.suit_leg = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_leg.jpg")
			self.suit_sleeve = loader.loadTexture("phase_3.5/maps/" + suitTeam + "_sleeve.jpg")
			
			self.suit.find('**/legs').setTexture(self.suit_leg, 1)
			self.suit.find('**/arms').setTexture(self.suit_sleeve, 1)
			self.suit.find('**/torso').setTexture(self.suit_blazer, 1)
		
			if suitHead == "coldcaller":
				self.suit.find('**/hands').setColor(0.55, 0.65, 1.0, 1.0)
			elif suitHead == "corporateraider":
				self.suit.find('**/hands').setColor(0.85, 0.55, 0.55, 1.0)
			elif suitHead == "bigcheese":
				self.suit.find('**/hands').setColor(0.75, 0.95, 0.75, 1.0)
			elif suitHead == "bloodsucker":
				self.suit.find('**/hands').setColor(0.95, 0.95, 1.0, 1.0)
			elif suitHead == "spindoctor":
				self.suit.find('**/hands').setColor(0.5, 0.8, 0.75, 1.0)
			elif suitHead == "legaleagle":
				self.suit.find('**/hands').setColor(0.25, 0.25, 0.5, 1.0)
			elif suitHead == "pennypincher":
				self.suit.find('**/hands').setColor(1.0, 0.5, 0.6, 1.0)
			elif suitHead == "loanshark":
				self.suit.find('**/hands').setColor(0.5, 0.85, 0.75, 1.0)
			else:
				self.suit.find('**/hands').setColor(CIGlobals.SuitHandColors[suitTeam])
		
		self.suit.reparentTo(self)
		
	def generateHead(self, suitType, suitHead):
		if self.suitHead:
			self.cleanupSuitHead()
			
		self.type = suitType
		self.head = suitHead
		
		if suitHead == "vp":
			self.suitHead = Actor("phase_9/models/char/sellbotBoss-head-zero.bam",
								{"neutral": "phase_9/models/char/bossCog-head-Ff_neutral.bam"})
			self.suitHead.setTwoSided(True)
			self.suitHead.loop("neutral")
			self.suitHead.setScale(0.35)
			self.suitHead.setHpr(270, 0, 270)
			self.suitHead.setZ(-0.10)
		else:
			if suitType == "A" or suitType == "B":
				self.suitHeads = loader.loadModel("phase_4/models/char/suit" + suitType + "-heads.bam")
			else:
				self.suitHeads = loader.loadModel("phase_3.5/models/char/suit" + suitType + "-heads.bam")
			self.suitHead = self.suitHeads.find('**/' + CIGlobals.SuitHeads[suitHead])
			if suitHead == "flunky":
				glasses = self.suitHeads.find('**/glasses')
				glasses.reparentTo(self.suitHead)
				glasses.setTwoSided(True)
			if suitHead in CIGlobals.SuitSharedHeads:
				if suitHead == "coldcaller":
					self.suitHead.setColor(0.25, 0.35, 1.0, 1.0)
				else:
					headTexture = loader.loadTexture("phase_3.5/maps/" + suitHead + ".jpg")
					self.suitHead.setTexture(headTexture, 1)
		if not self.isSkele:
			self.suitHead.reparentTo(self.suit.find('**/joint_head'))
			
	def cleanupSuit(self):
		if self.shadow:
			self.shadow.remove()
			self.shadow = None
		self.removeHealthBar()
		self.suit.cleanup()
		self.suit = None
		
	def cleanupSuitHead(self):
		if self.suitHeads:
			self.suitHeads.remove()
			self.suitHeads = None
		if self.suitHead:
			self.suitHead.remove()
			self.suitHead = None
		
	def cleanupLoserSuit(self):
		if self.explosion:
			self.explosion.remove()
			self.explosion = None
		if self.smallExp:
			self.smallExp = None
		if self.largeExp:
			self.largeExp.cleanup()
			self.largeExp = None
		if self.loserSuit:
			self.loserSuit.cleanup()
			self.loserSuit = None
		
	def setName(self, nameString, charName):
		Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType, charName=charName)
		
	def setChat(self, chatString):
		self.chat = chatString
		if self.isSkele:
			if "?" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_question.ogg")
			elif "!" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_grunt.ogg")
			else:
				self.suit_dial = audio3d.loadSfx("phase_5/audio/sfx/Skel_COG_VO_statement.ogg")
		elif self.head == "vp":
			if "?" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_question.ogg")
			elif "!" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_grunt.ogg")
			else:
				self.suit_dial = audio3d.loadSfx("phase_9/audio/sfx/Boss_COG_VO_statement.ogg")
		else:
			if "?" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_question.ogg")
			elif "!" in chatString:
				self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_grunt.ogg")
			else:
				self.suit_dial = audio3d.loadSfx("phase_3.5/audio/dial/COG_VO_statement.ogg")
		if self.isSkele:
			audio3d.attachSoundToObject(self.suit_dial, self.suit)
		else:
			audio3d.attachSoundToObject(self.suit_dial, self.suitHead)
		self.suit_dial.play()
		Avatar.Avatar.setChat(self, chatString)
		
	def generateHealthMeter(self):
		self.removeHealthBar()
		model = loader.loadModel("phase_3.5/models/gui/matching_game_gui.bam")
		button = model.find('**/minnieCircle')
		button.setScale(3.0)
		button.setH(180)
		button.setColor(self.healthColors[0])
		chestNull = self.suit.find('**/def_joint_attachMeter')
		if chestNull.isEmpty():
			chestNull = self.suit.find('**/joint_attachMeter')
		button.reparentTo(chestNull)
		self.healthBar = button
		glow = loader.loadModel("phase_3.5/models/props/glow.bam")
		glow.reparentTo(self.healthBar)
		glow.setScale(0.28)
		glow.setPos(-0.005, 0.01, 0.015)
		glow.setColor(self.healthGlowColors[0])
		button.flattenLight()
		self.healthBarGlow = glow
		self.condition = 0
		
	def updateHealthBar(self, hp):
		if hp > self.hp:
			self.hp = hp
		self.hp -= hp
		health = float(self.health) / float(self.maxHP)
		if health > 0.95:
			condition = 0
		elif health > 0.7:
			condition = 1
		elif health > 0.3:
			condition = 2
		elif health > 0.05:
			condition = 3
		elif health > 0.0:
			condition = 4
		else:
			condition = 5
			
		if self.condition != condition:
			if condition == 4:
				blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.75), Task(self.__blinkGray), Task.pause(0.1))
				taskMgr.add(blinkTask, self.taskName('blink-task'))
			elif condition == 5:
				if self.condition == 4:
					taskMgr.remove(self.taskName('blink-task'))
				blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.25), Task(self.__blinkGray), Task.pause(0.1))
				taskMgr.add(blinkTask, self.taskName('blink-task'))
			else:
				self.healthBar.setColor(self.healthColors[condition], 1)
				self.healthBarGlow.setColor(self.healthGlowColors[condition], 1)
			self.condition = condition
			
	def __blinkRed(self, task):
		self.healthBar.setColor(self.healthColors[3], 1)
		self.healthBarGlow.setColor(self.healthGlowColors[3], 1)
		if self.condition == 5:
			self.healthBar.setScale(1.17)
		return Task.done
		
	def __blinkGray(self, task):
		if not self.healthBar:
			return
		self.healthBar.setColor(self.healthColors[4], 1)
		self.healthBarGlow.setColor(self.healthGlowColors[4], 1)
		if self.condition == 5:
			self.healthBar.setScale(1.0)
		return Task.done
		
	def removeHealthBar(self):
		if self.healthMeter:
			self.healthBar.removeNode()
			self.healthBar = None
		if self.condition == 4 or self.condition == 5:
			taskMgr.remove(self.taskName('blink-task'))
		self.healthCondition = 0
		return
			
	def enterOff(self):
		self.anim = None
		return
		
	def exitOff(self):
		pass
		
	def exitGeneral(self):
		self.suit.stop()
		
	def enterNeutral(self):
		self.suit.loop("neutral")
		
	def exitNeutral(self):
		self.exitGeneral()
		
	def enterRollodex(self):
		self.suit.play("rollodex")
		
	def exitRollodex(self):
		self.exitGeneral()
		
	def enterWalk(self):
		self.suit.loop("walk")
		
	def exitWalk(self):
		self.exitGeneral()
		
	def generateLoserSuit(self):
		self.cleanupLoserSuit()
		if self.type == "A":
			if self.isSkele:
				self.loserSuit = Actor("phase_5/models/char/cogA_robot-lose-mod.bam")
			else:
				self.loserSuit = Actor("phase_4/models/char/suitA-lose-mod.bam")
			self.loserSuit.loadAnims({"lose": "phase_4/models/char/suitA-lose.bam"})
		if self.type == "B":
			if self.isSkele:
				self.loserSuit = Actor("phase_5/models/char/cogB_robot-lose-mod.bam")
			else:
				self.loserSuit = Actor("phase_4/models/char/suitB-lose-mod.bam")
			self.loserSuit.loadAnims({"lose": "phase_4/models/char/suitB-lose.bam"})
		if self.type == "C":
			if self.isSkele:
				self.loserSuit = Actor("phase_5/models/char/cogC_robot-lose-mod.bam")
			else:
				self.loserSuit = Actor("phase_3.5/models/char/suitC-lose-mod.bam")
			self.loserSuit.loadAnims({"lose": "phase_3.5/models/char/suitC-lose.bam"})
		if self.isSkele:
			self.loserSuit.find('**/tie').setTexture(self.suit_tie, 1)
			self.loserSuit.setTwoSided(1)
		else:
			self.loserSuit.find('**/hands').setColor(self.suit.find('**/hands').getColor())
			self.loserSuit.find('**/legs').setTexture(self.suit_leg, 1)
			self.loserSuit.find('**/arms').setTexture(self.suit_sleeve, 1)
			self.loserSuit.find('**/torso').setTexture(self.suit_blazer, 1)
		self.loserSuit.getGeomNode().setScale(self.suit.getScale())
		self.loserSuit.reparentTo(self)
		if not self.isSkele:
			self.suitHead.reparentTo(self.loserSuit.find('**/joint_head'))
		self.loserSuit.setPos(self.suit.getPos(render))
		self.loserSuit.setHpr(self.suit.getHpr(render))
		self.cleanupSuit()
		Avatar.Avatar.initShadow(self, self.avatarType)
		self.loserSuit.reparentTo(render)
		
	def enterDie(self):
		self.generateLoserSuit()
		self.state = "dead"
		self.loserSuit.play("lose")
		spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.ogg")
		deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg")
		#audio3d.attachSoundToObject(spinningSound, self.loserSuit)
		#audio3d.attachSoundToObject(deathSound, self.loserSuit)
		Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.4, node=self.loserSuit),
			SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=2.0, node=self.loserSuit),
			SoundInterval(deathSound, volume=0.32, node=self.loserSuit)).start()
		Sequence(Wait(0.8), Func(self.smallDeathParticles), Wait(4.2), Func(self.suitExplode),
				Wait(1.0), Func(self.delSuit)).start()
		
	def smallDeathParticles(self):
		self.smallExp = ParticleLoader.loadParticleEffect("phase_3.5/etc/gearExplosionSmall.ptf")
		self.smallExp.start(self.loserSuit)
		
	def suitExplode(self):
		self.smallExp.cleanup()
		self.largeExp = ParticleLoader.loadParticleEffect("phase_3.5/etc/gearExplosion.ptf")
		self.largeExp.start(self.loserSuit)
		self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam")
		self.explosion.setScale(0.5)
		self.explosion.reparentTo(render)
		self.explosion.setBillboardPointEye()
		if self.isSkele:
			self.explosion.setPos(self.loserSuit.find('**/joint_head').getPos(render) + (0, 0, 2))
		else:
			self.explosion.setPos(self.suitHead.getPos(render) + (0,0,2))
		
	def delSuit(self):
		self.cleanupLoserSuit()
		self.disableBodyCollisions()
		
	def exitDie(self):
		pass
		
	def enterFlyDown(self):
		self.fd_sfx = audio3d.loadSfx("phase_5/audio/sfx/ENC_propeller_in.ogg")
		self.prop = Actor("phase_4/models/props/propeller-mod.bam",
						{"chan": "phase_4/models/props/propeller-chan.bam"})
		audio3d.attachSoundToObject(self.fd_sfx, self.prop)
		self.fd_sfx.play()
		self.prop.reparentTo(self.suit.find('**/joint_head'))
		propTrack = Sequence(Func(self.prop.loop, 'chan', fromFrame=0, toFrame=3),
							Wait(1.75),
							Func(self.prop.play, 'chan', fromFrame=3))
		propTrack.start()
		if not self.hasSpawned:
			showSuit = Task.sequence(Task(self.hideSuit), Task.pause(0.3), Task(self.showSuit))
			taskMgr.add(showSuit, "showsuit")
			self.hasSpawned = True
		dur = self.suit.getDuration('land')
		suitTrack = Sequence(Func(self.suit.pose, 'land', 0),
							Wait(1.9),
							ActorInterval(self.suit, 'land', duration=dur))
		suitTrack.start()
		
	def hideSuit(self, task):
		self.hide()
		return Task.done
	
	def showSuit(self, task):
		self.show()
		fadeIn = Sequence(Func(self.setTransparency, 1), self.colorScaleInterval(0.6, colorScale=Vec4(1,1,1,1), startColorScale=Vec4(1,1,1,0)), Func(self.clearColorScale), Func(self.clearTransparency), Func(self.reparentTo, render))
		fadeIn.start()
		return Task.done
		
	def initializeLocalCollisions(self, name):
		Avatar.Avatar.initializeLocalCollisions(self, 1, 3, name)
		
	def initializeBodyCollisions(self):
		Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 2.25, 1, 4, 2)
		self.initializeRay(self.avatarType)
		self.collTube.setTangible(0)
		
	def deleteBean(self):
		if self.bean:
			self.bean.remove_node()
			self.bean = None
			
	def createJellyBean(self):
		self.deleteBean()
		money = int(self.maxHP / CIGlobals.SuitAttackDamageFactors['clipontie'])
		if money == 1:
			self.bean = loader.loadModel("phase_5.5/models/estate/jellyBean.bam")
			self.bean.set_two_sided(True)
			random_r = random.uniform(0, 1)
			random_g = random.uniform(0, 1)
			random_b = random.uniform(0, 1)
			self.bean.set_color(random_r, random_g, random_b, 1)
		else:
			self.bean = loader.loadModel("phase_5.5/models/estate/jellybeanJar.bam")
		self.bean.reparent_to(render)
		self.bean.set_pos(self.get_pos(render) + (0, 0, 1))
		bean_int = self.bean.hprInterval(1,
										Point3(360, 0, 0),
										startHpr=(0, 0, 0))
		bean_int.loop()
		
	def exitFlyDown(self):
		audio3d.detachSound(self.fd_sfx)
		self.prop.cleanup()
		self.prop = None
		
	def enterFlyAway(self):
		self.fa_sfx = audio3d.loadSfx("phase_5/audio/sfx/ENC_propeller_out.ogg")
		self.prop = Actor("phase_4/models/props/propeller-mod.bam",
						{"chan": "phase_4/models/props/propeller-chan.bam"})
		audio3d.attachSoundToObject(self.fa_sfx, self.prop)
		self.fa_sfx.play()
		self.prop.reparentTo(self.suit.find('**/joint_head'))
		self.prop.setPlayRate(-1.0, "chan")
		propTrack = Sequence(Func(self.prop.play, 'chan', fromFrame=3),
							Wait(1.75),
							Func(self.prop.play, 'chan', fromFrame=0, toFrame=3))
		propTrack.start()
		self.suit.setPlayRate(-1.0, 'land')
		self.suit.play('land')
		
	def exitFlyAway(self):
		audio3d.detachSound(self.fa_sfx)
		self.prop.cleanup()
		self.prop = None
		
	def enterAttack(self, attack):
		self.attack = attack
		
		self.weapon_state = 'start'
		
		if attack == "canned":
			self.weapon = loader.loadModel("phase_5/models/props/can.bam")
			self.weapon.setScale(15)
			self.weapon.setR(180)
			self.wss = CollisionSphere(0,0,0,0.05)
		elif attack == "clipontie":
			self.weapon = loader.loadModel("phase_5/models/props/power-tie.bam")
			self.weapon.setScale(4)
			self.weapon.setR(180)
			self.wss = CollisionSphere(0,0,0,0.2)
		elif attack == "sacked":
			self.weapon = loader.loadModel("phase_5/models/props/sandbag-mod.bam")
			self.weapon.setScale(2)
			self.weapon.setR(180)
			self.weapon.setP(90)
			self.weapon.setY(-2.8)
			self.weapon.setZ(-0.3)
			self.wss = CollisionSphere(0,0,0,1)
		elif attack == "playhardball":
			self.weapon = loader.loadModel("phase_5/models/props/baseball.bam")
			self.weapon.setScale(10)
			self.wss = CollisionSphere(0,0,0,0.1)
			self.weapon.setZ(-0.5)
		elif attack == "marketcrash":
			self.weapon = loader.loadModel("phase_5/models/props/newspaper.bam")
			self.weapon.setScale(3)
			self.weapon.setPos(0.41, -0.06, -0.06)
			self.weapon.setHpr(90, 0, 270)
			self.wss = CollisionSphere(0,0,0,0.35)
		elif attack == "glowerpower":
			self.weapon = loader.loadModel("phase_5/models/props/dagger.bam")
			self.wss = CollisionSphere(0,0,0,1)
		else:
			notify.warning("unknown attack!")
			
		self.throwObjectId = random.uniform(0, 101010101010)
		
		if attack == "canned" or attack == "playhardball":
			self.weapon.reparentTo(self.suit.find('**/joint_Rhold'))
			if self.type == "C":
				taskMgr.doMethodLater(2.2, self.throwObject, "throwObject" + str(self.throwObjectId))
			else:
				taskMgr.doMethodLater(3, self.throwObject, "throwObject" + str(self.throwObjectId))
			self.suit.play("throw-object")
		elif attack == "clipontie" or attack == "marketcrash" or attack == "sacked":
			self.weapon.reparentTo(self.suit.find('**/joint_Rhold'))
			if self.type == "C":
				taskMgr.doMethodLater(2.2, self.throwObject, "throwObject" + str(self.throwObjectId))
			else:
				taskMgr.doMethodLater(3, self.throwObject, "throwObject" + str(self.throwObjectId))
			self.suit.play("throw-paper")
		elif attack == "glowerpower":
			taskMgr.doMethodLater(1, self.throwObject, "throwObject" + str(self.throwObjectId))
			self.suit.play("glower")
		self.weaponSensorId = random.uniform(0, 1010101010101001)
		wsnode = CollisionNode('weaponSensor' + str(self.weaponSensorId))
		wsnode.addSolid(self.wss)
		self.wsnp = self.weapon.attachNewNode(wsnode)
		if attack == "sacked":
			self.wsnp.setZ(1)
		elif attack == "marketcrash":
			self.wsnp.setPos(-0.25, 0.3, 0)
			
	def delWeapon(self, task):
		if self.weapon:
			self.weapon.removeNode()
			self.weapon = None
		return task.done
		
	def interruptAttack(self):
		if self.wtrajectory:
			if self.wtrajectory.isStopped():
				if self.weapon:
					self.weapon.removeNode()
					self.weapon = None
		if self.throwObjectId:
			taskMgr.remove("throwObject" + str(self.throwObjectId))
		
	def handleWeaponTouch(self):
		if not self.attack == "glowerpower" or not self.attack == "clipontie":
			if self.weapon_sfx:
				self.weapon_sfx.stop()
		try: self.wtrajectory.pause()
		except: pass
		if self.weapon:
			self.weapon.removeNode()
			self.weapon = None
		
	def weaponCollisions(self):
		self.wsnp.setCollideMask(BitMask32(0))
		self.wsnp.node().setFromCollideMask(CIGlobals.EventBitmask)
			
		event = CollisionHandlerEvent()
		event.setInPattern("%fn-into")
		event.setOutPattern("%fn-out")
		base.cTrav.addCollider(self.wsnp, event)
		
	def throwObject(self, task):
		self.playWeaponSound()
		
		self.weaponNP = NodePath("weaponNP")
		self.weaponNP.setScale(render, 1)
		try: self.weaponNP.reparentTo(self.find('**/joint_nameTag'))
		except: return task.done
		self.weaponNP.setPos(0, 50, 0)
		self.weaponNP.setHpr(0, 0, 0)
		
		if self.weapon:
			self.weapon.setScale(self.weapon.getScale(render))
		try: self.weapon.reparentTo(render)
		except: return task.done
		
		self.weapon.setPos(0,0,0)
		self.weapon.setHpr(0,0,0)
		
		if self.attack == "glowerpower":
			self.weapon.setH(self.weaponNP.getH(render))
			self.wtrajectory = self.weapon.posInterval(0.5,
										Point3(self.weaponNP.getPos(render)),
										startPos=(self.getX(render), self.getY(render) + 3, self.find('**/joint_head').getZ(render)))
			self.wtrajectory.start()
		else:
			self.wtrajectory = ProjectileInterval(self.weapon,
										startPos = (self.suit.find('**/joint_Rhold').getPos(render)),
										endPos = self.weaponNP.getPos(render),
										gravityMult = 0.7, duration = 1)
			self.wtrajectory.start()
		if self.attack == "glowerpower":
			taskMgr.doMethodLater(0.5, self.delWeapon, "delWeapon")
		else:
			taskMgr.doMethodLater(1, self.delWeapon, "delWeapon")
		self.weapon_state = 'released'
		
	def playWeaponSound(self):
		if self.attack == "glowerpower":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_glower_power.ogg")
		elif self.attack == "canned":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg")
		elif self.attack == "clipontie":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_powertie_throw.ogg")
		elif self.attack == "sacked":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg")
		elif self.attack == "playhardball":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg")
		elif self.attack == "marketcrash":
			self.weapon_sfx = audio3d.loadSfx("phase_5/audio/sfx/SA_canned_tossup_only.ogg")
		if self.weapon:
			audio3d.attachSoundToObject(self.weapon_sfx, self.weapon)
			self.weapon_sfx.play()
			
	def exitAttack(self):
		pass
		
	def enterPie(self):
		self.suit.play("pie")
		
	def exitPie(self):
		self.exitGeneral()
		
	def enterWin(self):
		self.suit.play("win")
		
	def exitWin(self):
		self.exitGeneral()
示例#9
0
文件: Walk.py 项目: coginvasion/src
class Walk(StateData):
    notify = directNotify.newCategory('Walk')

    def __init__(self, doneEvent):
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('Walk', [State('off', self.enterOff, self.exitOff, ['walking', 'deadWalking']), State('walking', self.enterWalking, self.exitWalking), State('deadWalking', self.enterDeadWalking, self.exitDeadWalking)], 'off', 'off')
        self.fsm.enterInitialState()

    def load(self):
        pass

    def unload(self):
        del self.fsm

    def enter(self):
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()
        base.localAvatar.startBlink()
        base.localAvatar.attachCamera()
        base.localAvatar.startSmartCamera()
        base.localAvatar.collisionsOn()
        base.localAvatar.enableAvatarControls()
        base.localAvatar.enablePicking()

    def exit(self):
        base.localAvatar.lastState = None
        self.fsm.request('off')
        base.localAvatar.enablePicking()
        base.localAvatar.disableAvatarControls()
        base.localAvatar.detachCamera()
        base.localAvatar.stopSmartCamera()
        base.localAvatar.stopPosHprBroadcast()
        base.localAvatar.stopBlink()
        base.localAvatar.collisionsOff()
        base.localAvatar.controlManager.placeOnFloor()
        return

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterWalking(self):
        if base.localAvatar.getHealth() > 0:
            base.localAvatar.startTrackAnimToSpeed()
            base.localAvatar.setWalkSpeedNormal()
        else:
            self.fsm.request('deadWalking')

    def exitWalking(self):
        base.localAvatar.stopTrackAnimToSpeed()

    def enterDeadWalking(self):
        base.localAvatar.startTrackAnimToSpeed()
        base.localAvatar.setWalkSpeedSlow()
        base.taskMgr.add(self.__watchForPositiveHP, base.localAvatar.uniqueName('watchforPositiveHP'))

    def __watchForPositiveHP(self, task):
        if base.localAvatar.getHealth() > 0:
            self.fsm.request('walking')
            return task.done
        return task.cont

    def exitDeadWalking(self):
        base.taskMgr.remove(base.localAvatar.uniqueName('watchforPositiveHP'))
        base.localAvatar.stopTrackAnimToSpeed()
示例#10
0
class AvChooser(StateData):
    notify = directNotify.newCategory('AvChooser')

    def __init__(self, parentFSM):
        StateData.__init__(self, 'avChooseDone')
        self.avChooseFSM = ClassicFSM('avChoose', [
            State('getToonData', self.enterGetToonData, self.exitGetToonData),
            State('avChoose', self.enterAvChoose, self.exitAvChoose),
            State('waitForToonDelResponse', self.enterWaitForToonDelResponse,
                  self.exitWaitForToonDelResponse),
            State('off', self.enterOff, self.exitOff)
        ], 'off', 'off')
        self.avChooseFSM.enterInitialState()
        self.parentFSM = parentFSM
        self.parentFSM.getStateNamed('avChoose').addChild(self.avChooseFSM)
        self.pickAToon = None
        self.setAvatarsNone()
        return

    def enter(self):
        StateData.enter(self)
        base.transitions.noTransitions()
        self.avChooseFSM.request('getToonData')

    def exit(self):
        StateData.exit(self)
        self.setAvatarsNone()
        self.avChooseFSM.requestFinalState()

    def setAvatarsNone(self):
        self.avChoices = []

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterGetToonData(self):
        self.acceptOnce(base.cr.csm.getSetAvatarsEvent(), self.handleToonData)
        base.cr.csm.d_requestAvatars()

    def handleToonData(self, avatarList):
        for av in avatarList:
            avId = av[0]
            dna = av[1]
            name = av[2]
            slot = av[3]
            choice = AvChoice(dna, name, slot, avId)
            self.avChoices.append(choice)

        self.avChooseFSM.request('avChoose')

    def exitGetToonData(self):
        self.ignore(base.cr.csm.getSetAvatarsEvent())

    def enterAvChoose(self):
        if base.cr.holidayManager.getHoliday() == HolidayType.CHRISTMAS:
            base.cr.music.stop()
            base.cr.music = base.loadMusic(CIGlobals.getHolidayTheme())
            base.cr.music.setLoop(True)
            base.cr.music.setVolume(0.75)
            base.cr.music.play()
            whisper = WhisperPopup(HolidayGlobals.CHRISTMAS_TIME,
                                   CIGlobals.getToonFont(),
                                   ChatGlobals.WTSystem)
            whisper.manage(base.marginManager)
        self.pickAToon = CharSelection(self)
        self.pickAToon.load()

    def enterWaitForToonDelResponse(self, avId):
        self.acceptOnce(base.cr.csm.getToonDeletedEvent(),
                        self.handleDeleteToonResp)
        base.cr.csm.sendDeleteToon(avId)

    def exitWaitForToonDelResponse(self):
        self.ignore(base.cr.csm.getToonDeletedEvent())

    def hasToonInSlot(self, slot):
        if self.getAvChoiceBySlot(slot) != None:
            return True
        return False
        return

    def getNameInSlot(self, slot):
        return self.getAvChoiceBySlot(slot).getName()

    def getNameFromAvId(self, avId):
        for avChoice in self.avChoices:
            if avChoice.getAvId() == avId:
                return avChoice.getName()

    def getAvChoiceBySlot(self, slot):
        for avChoice in self.avChoices:
            if avChoice.getSlot() == slot:
                return avChoice

        return

    def getHeadInfo(self, slot):
        dna = self.getAvChoiceBySlot(slot).getDNA()
        self.pickAToon.dna.setDNAStrand(dna)
        return [
            self.pickAToon.dna.getGender(),
            self.pickAToon.dna.getAnimal(),
            self.pickAToon.dna.getHead(),
            self.pickAToon.dna.getHeadColor()
        ]

    def handleDeleteToonResp(self):
        base.cr.loginFSM.request('avChoose')

    def exitAvChoose(self):
        self.pickAToon.unload()
        self.pickAToon = None
        return
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode):
    notify = directNotify.newCategory('DistributedPieTurret')

    def __init__(self, cr):
        DistributedAvatar.__init__(self, cr)
        DistributedSmoothNode.__init__(self, cr)
        self.fsm = ClassicFSM(
            'DistributedPieTurret',
            [
                State('off', self.enterOff, self.exitOff),
                State('scan', self.enterScan, self.exitScan),
                State('shoot', self.enterShoot, self.exitShoot)
             ],
             'off', 'off'
         )
        self.fsm.enterInitialState()
        self.reloadTime = 0.25
        self.cannon = None
        self.track = None
        self.owner = None
        self.gag = None
        self.readyGag = None
        self.hitGag = None
        self.explosion = None
        self.wallCollNode = None
        self.eventCollNode = None
        self.event = None
        self.suit = None
        self.eventId = None
        self.entities = []
        self.upgradeID = None
        self.deathEvent = None

    def setOwner(self, avatar):
        self.owner = avatar

    def getOwner(self):
        return self.owner

    def setGag(self, upgradeId):
        gags = {0 : CIGlobals.WholeCreamPie, 1 : CIGlobals.WholeFruitPie, 2 : CIGlobals.BirthdayCake, 3 : CIGlobals.WeddingCake}
        self.gag = gags.get(upgradeId)
        if not self.readyGag:
            self.loadGagInTurret()

    def b_setGag(self, upgradeId):
        self.sendUpdate('setGag', [upgradeId])
        self.setGag(upgradeId)
        self.upgradeID = upgradeId

    def getGag(self):
        return self.gag

    def getGagID(self):
        return self.upgradeID

    def generate(self):
        DistributedAvatar.generate(self)
        DistributedSmoothNode.generate(self)

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        DistributedSmoothNode.announceGenerate(self)
        self.healthLabel.setScale(1.1)
        self.deathEvent = self.uniqueName('DistributedPieTurret-death')
        self.makeTurret()

    def disable(self):
        self.fsm.requestFinalState()
        del self.fsm

        # This should fix crashes related to Sequences.
        if self.track:
            self.track.pause()
            self.track = None

        # Cleanup entities.
        for ent in self.entities:
            ent.cleanup()
        self.entities = None

        # Get rid of explosions.
        if self.explosion:
            self.explosion.removeNode()
            self.explosion = None

        self.removeTurret()
        DistributedSmoothNode.disable(self)
        DistributedAvatar.disable(self)

    def showAndMoveHealthLabel(self):
        self.unstashHpLabel()
        self.stopMovingHealthLabel()
        moveTrack = LerpPosInterval(self.healthLabel,
                                duration = 0.5,
                                pos = Point3(0, 0, 5),
                                startPos = Point3(0, 0, 0),
                                blendType = 'easeOut')
        self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel))
        self.healthLabelTrack.start()

    # BEGIN STATES

    def enterShoot(self, suitId):
        if self.cannon:
            smoke = loader.loadModel("phase_4/models/props/test_clouds.bam")
            smoke.setBillboardPointEye()
            smoke.reparentTo(self.cannon.find('**/cannon'))
            smoke.setPos(0, 6, -3)
            smoke.setScale(0.5)
            smoke.wrtReparentTo(render)
            self.suit = self.cr.doId2do.get(suitId)
            self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head'))
            self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head'))
            self.track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode))
            self.track.start()
            self.createAndShootGag()

    def exitShoot(self):
        if hasattr(self, 'suit'):
            del self.suit

    def shoot(self, suitId):
        self.fsm.request('shoot', [suitId])

    def scan(self, timestamp = None, afterShooting = 0):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)

        self.fsm.request('scan', [ts, afterShooting])
        
    def buildScanTrack(self, ts = None):
        if self.track:
            self.track.pause()
            self.track = None
        self.track = Parallel(
            Sequence(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            ),
            Sequence(
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            )
        )
        if ts:
            self.track.loop(ts)
        else:
            self.track.loop()

    def enterScan(self, ts = 0, afterShooting = 0):
        if afterShooting:
            self.track = Parallel(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'),
                name = "afterShootTrack" + str(id(self))
            )
            self.track.setDoneEvent(self.track.getName())
            self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone)
            self.track.start(ts)
        else:
            self.buildScanTrack(ts)

    def exitScan(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    # END STATES

    def _afterShootTrackDone(self):
        self.buildScanTrack()

    def makeTurret(self):
        self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon.bam')
        self.cannon.reparentTo(self)
        self.loadGagInTurret()
        self.setupWallSphere()
        if self.isLocal():
            self.setupEventSphere()

    def removeTurret(self):
        self.removeWallSphere()
        self.removeGagInTurret()
        if self.cannon:
            self.cannon.removeNode()
            self.cannon = None

    def getCannon(self):
        return self.cannon.find('**/cannon')

    def setupWallSphere(self):
        sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0)
        node = CollisionNode('DistributedPieTurret.WallSphere')
        node.addSolid(sphere)
        node.setCollideMask(CIGlobals.WallBitmask)
        self.wallCollNode = self.cannon.attachNewNode(node)
        self.wallCollNode.setZ(2)
        self.wallCollNode.setY(1.0)

    def removeWallSphere(self):
        if self.wallCollNode:
            self.wallCollNode.removeNode()
            self.wallCollNode = None

    def createAndShootGag(self):
        if not self.readyGag:
            self.loadGagInTurret()
        if self.readyGag:
            self.readyGag.shoot(Point3(0, 200, -90))
            self.entities.append(self.readyGag)
            collideEventName = self.readyGag.getCollideEventName()
            self.readyGag = None
            if self.isLocal():
                self.acceptOnce(collideEventName, self.handleGagCollision)
        Sequence(Wait(self.reloadTime), Func(self.loadGagInTurret)).start()

    def loadGagInTurret(self):
        if self.cannon and self.gag:
            self.removeGagInTurret()
            self.eventId = random.uniform(0, 100000000)
            self.readyGag = TurretGag(self, self.uniqueName('pieTurretCollision') + str(self.eventId), self.gag)
            self.readyGag.build()

    def removeGagInTurret(self):
        if self.readyGag:
            self.readyGag.cleanup()
            self.readyGag = None

    def makeSplat(self, index, pos):
        if index >= len(self.entities):
            return
        ent = self.entities[index]
        gagClass = ent.gagClass
        splat = gagClass.buildSplat(gagClass.splatScale, gagClass.splatColor)
        base.audio3d.attachSoundToObject(gagClass.hitSfx, splat)
        splat.reparentTo(render)
        splat.setPos(pos[0], pos[1], pos[2])
        gagClass.hitSfx.play()
        Sequence(Wait(0.5), Func(splat.cleanup)).start()
        self.hitGag = None

    def d_makeSplat(self, index, pos):
        self.sendUpdate('makeSplat', [index, pos])

    def b_makeSplat(self, index, pos):
        self.d_makeSplat(index, pos)
        self.makeSplat(index, pos)

    def handleGagCollision(self, entry, ent):
        x, y, z = ent.getGag().getPos(render)
        self.b_makeSplat(self.entities.index(ent), [x, y, z])
        if self.isLocal():
            intoNP = entry.getIntoNodePath()
            avNP = intoNP.getParent()
            for key in self.cr.doId2do.keys():
                obj = self.cr.doId2do[key]
                if obj.__class__.__name__ == 'DistributedSuit':
                    if obj.getKey() == avNP.getKey():
                        if obj.getHealth() > 0:
                            obj.sendUpdate('hitByGag', [ent.getID()])
        ent.cleanup()

    def setHealth(self, hp):
        DistributedAvatar.setHealth(self, hp)
        if self.isLocal():
            base.localAvatar.getMyBattle().getTurretManager().updateTurretGui()

    def die(self):
        self.fsm.requestFinalState()
        turretPos = self.cannon.getPos(render)
        self.removeTurret()
        self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam")
        self.explosion.setScale(0.5)
        self.explosion.reparentTo(render)
        self.explosion.setBillboardPointEye()
        self.explosion.setPos(turretPos + (0, 0, 5))
        sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg")
        base.audio3d.attachSoundToObject(sfx, self)
        base.playSfx(sfx)
        messenger.send(self.deathEvent)

    def isLocal(self):
        return self.getOwner() == base.localAvatar.doId

    def getDeathEvent(self):
        return self.deathEvent
示例#12
0
class QuietZoneState(StateData):

    def __init__(self, doneEvent, moveOn = 1):
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('quietZone', [State('off', self.enterOff, self.exitOff, ['waitForQuietZoneResponse']),
         State('waitForQuietZoneResponse', self.enterWaitForQuietZoneResponse, self.exitWaitForQuietZoneResponse, ['waitForSetZoneResponse']),
         State('waitForSetZoneResponse', self.enterWaitForSetZoneResponse, self.exitWaitForSetZoneResponse, ['waitForSetZoneComplete']),
         State('waitForSetZoneComplete', self.enterWaitForSetZoneComplete, self.exitWaitForSetZoneComplete, ['off'])], 'off', 'off')
        self.fsm.enterInitialState()
        self.moveOn = moveOn

    def getSetZoneCompleteEvent(self):
        return 'setZoneComplete-%s' % id(self)

    def getQuietZoneResponseEvent(self):
        return 'quietZoneResponse-%s' % id(self)

    def getEnterWaitForSetZoneResponseMsg(self):
        return 'enterWaitForSetZoneResponse-%s' % id(self)

    def unload(self):
        StateData.unload(self)
        del self.fsm

    def enter(self, requestStatus):
        StateData.enter(self)
        self._requestStatus = requestStatus
        base.localAvatar.b_setAnimState('off')
        self.fsm.request('waitForQuietZoneResponse')

    def exit(self):
        StateData.exit(self)
        if self._requestStatus.get('how', None) != 'doorOut':
            base.transitions.noTransitions()
        del self._requestStatus
        self.fsm.request('off')
        return

    def getDoneStatus(self):
        return self._requestStatus

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def handleWaitForQuietZoneResponse(self, msgType, di):
        if msgType == CLIENT_ENTER_OBJECT_REQUIRED:
            base.cr.handleQuietZoneGenerateWithRequired(di)
        elif msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER:
            base.cr.handleQuietZoneGenerateWithRequiredOther(di)
        elif msgType == CLIENT_OBJECT_SET_FIELD:
            base.cr.handleQuietZoneUpdateField(di)
        else:
            base.cr.astronHandle(di)

    def enterWaitForQuietZoneResponse(self):
        self.setZoneDoneEvent = base.cr.getNextSetZoneDoneEvent()
        self.acceptOnce(self.setZoneDoneEvent, self._handleQuietZoneResponse)
        base.cr.sendQuietZoneRequest()

    def _handleQuietZoneResponse(self):
        if self.moveOn:
            self.fsm.request('waitForSetZoneResponse')
        else:
            messenger.send('enteredQuietZone')

    def exitWaitForQuietZoneResponse(self):
        self.ignore(self.setZoneDoneEvent)
        del self.setZoneDoneEvent

    def enterWaitForZoneRedirect(self):
        self.fsm.request('waitForSetZoneResponse')

    def exitWaitForZoneRedirect(self):
        pass

    def enterWaitForSetZoneResponse(self):
        zoneId = self._requestStatus['zoneId']
        base.cr.sendSetZoneMsg(zoneId)
        self.fsm.request('waitForSetZoneComplete')

    def exitWaitForSetZoneResponse(self):
        pass

    def enterWaitForSetZoneComplete(self):
        self.setZoneDoneEvent = base.cr.getLastSetZoneDoneEvent()
        self.acceptOnce(self.setZoneDoneEvent, self._announceDone)

    def exitWaitForSetZoneComplete(self):
        self.ignore(self.setZoneDoneEvent)
        del self.setZoneDoneEvent

    def _announceDone(self):
        doneEvent = self.doneEvent
        requestStatus = self._requestStatus
        messenger.send(self.getSetZoneCompleteEvent(), [requestStatus])
        messenger.send(doneEvent)

    def getRequestStatus(self):
        return self._requestStatus
示例#13
0
class CogBrain(DirectObject):
    PANIC_SPEED = 0.15
    PANIC_DELAY = 0.5
    RUNAWAY_SPEED = 0.1
    RUNAWAY_SAFE_DISTANCE = 50
    MAX_BOSS_HELPERS = 5
    PANIC_HP_FACTOR = 0.222
    ATTACK_DISTANCE = 40.0
    MAX_ATTACKERS = 3
    Difficulty2MaxAttackThrows = {}
    for level in range(1, 5):
        Difficulty2MaxAttackThrows[level] = 3

    for level in range(5, 10):
        Difficulty2MaxAttackThrows[level] = 4

    for level in range(9, 13):
        Difficulty2MaxAttackThrows[level] = 5

    def __init__(self, suit):
        self.suit = suit
        self.panicHP = self.suit.getMaxHealth() * self.PANIC_HP_FACTOR
        self.fsm = ClassicFSM('CogBrain', [State('off', self.enterOff, self.exitOff),
         State('neutral', self.enterNeutral, self.exitNeutral),
         State('followBoss', self.enterFollowBoss, self.exitFollowBoss),
         State('panic', self.enterPanic, self.exitPanic),
         State('runAway', self.enterRunAway, self.exitRunAway)], 'off', 'off')
        self.fsm.enterInitialState()

    def start(self):
        taskMgr.add(self.__think, self.suit.uniqueName('think'))

    def end(self, andGoOff = 1):
        taskMgr.remove(self.suit.uniqueName('think'))
        if andGoOff:
            self.fsm.request('off')

    def __think(self, task = None):
        if task:
            task.delayTime = 1
        if self.suit.getAttacking():
            if task:
                return task.again
            else:
                return
        _help_priority = 0
        _panic_priority = 0
        _run_priority = 0
        _helper_suits = 0
        boss = None
        for av in self.suit.getManager().suits.values():
            if av.doId != self.suit.doId:
                if av.head in ('vp',):
                    boss = av
                    for suit in self.suit.getManager().suits.values():
                        if suit.doId != self.suit.doId:
                            if suit.brain:
                                if suit.brain.fsm.getCurrentState().getName() == 'followBoss':
                                    _helper_suits += 1

        if _helper_suits == self.MAX_BOSS_HELPERS - 1:
            _help_priority = 2
        elif _helper_suits == self.MAX_BOSS_HELPERS - 2:
            _help_priority = 2.5
        elif _helper_suits == self.MAX_BOSS_HELPERS - 3:
            _help_priority = 3.5
        elif _helper_suits == self.MAX_BOSS_HELPERS - 4:
            _help_priority = 4
        elif _helper_suits == self.MAX_BOSS_HELPERS - 5:
            _help_priority = 4.5
        if boss == None or _helper_suits == self.MAX_BOSS_HELPERS:
            _help_priority = 0
        if self.fsm.getCurrentState().getName() == 'followBoss':
            if self.bossSpotKey != boss.boss.spot:
                self.fsm.request('followBoss', [boss])
                return task.again
        _toons_in_range = 0
        in_range = 15
        for av in self.suit.air.doId2do.values():
            if av.__class__.__name__ == 'DistributedToonAI':
                if av.zoneId == self.suit.zoneId:
                    if self.suit.getDistance(av) <= in_range:
                        _toons_in_range += 1

        if self.fsm.getCurrentState().getName() == 'followBoss':
            _panic_priority = _toons_in_range / 0.85
        else:
            _panic_priority = _toons_in_range / 0.75
        if self.fsm.getCurrentState().getName() == 'panic' and _toons_in_range > 0:
            _run_priority = 5
        if self.suit.getHealth() <= self.panicHP:
            if _panic_priority < 4:
                _panic_priority = 4
        if _run_priority == 5:
            self.fsm.request('runAway', [av])
            del _help_priority
            del _panic_priority
            del _run_priority
            del _helper_suits
            del boss
            del in_range
            del _toons_in_range
            try:
                del av
            except:
                pass

            if task:
                return task.done
            else:
                return
        elif _panic_priority <= 2 and _help_priority <= 2:
            state_num = random.randint(0, 2)
            if state_num == 0 or state_num == 1:
                new_state = 'neutral'
            else:
                new_state = 'followBoss'
            if boss == None or _help_priority == 0:
                if self.fsm.getCurrentState().getName() != 'neutral':
                    self.fsm.request('neutral')
            else:
                new_state = 'neutral'
                if self.fsm.getCurrentState().getName() != new_state:
                    if self.fsm.getCurrentState().getName() == 'followBoss':
                        del _help_priority
                        del _panic_priority
                        del _run_priority
                        del _helper_suits
                        del boss
                        del in_range
                        del _toons_in_range
                        try:
                            del args
                        except:
                            pass

                        try:
                            del new_state
                        except:
                            pass

                        try:
                            del state_num
                        except:
                            pass

                        try:
                            del av
                        except:
                            pass

                        if task:
                            return task.again
                        else:
                            return
                    args = []
                    if new_state == 'followBoss':
                        args = [boss]
                    self.fsm.request(new_state, args)
        elif _panic_priority > _help_priority:
            if self.fsm.getCurrentState().getName() != 'panic':
                self.fsm.request('panic')
                del _help_priority
                del _panic_priority
                del _run_priority
                del _helper_suits
                del boss
                del in_range
                del _toons_in_range
                try:
                    del args
                except:
                    pass

                try:
                    del new_state
                except:
                    pass

                try:
                    del state_num
                except:
                    pass

                try:
                    del av
                except:
                    pass

                if task:
                    return task.done
                else:
                    return
        elif _panic_priority < _help_priority:
            if self.fsm.getCurrentState().getName() != 'followBoss':
                self.fsm.request('followBoss', [boss])
        elif _panic_priority == _help_priority:
            new_state = random.choice(['panic', 'followBoss'])
            if self.fsm.getCurrentState().getName() != new_state:
                args = []
                if new_state == 'followBoss':
                    args = [boss]
                self.fsm.request(new_state, args)
        del _help_priority
        del _panic_priority
        del _run_priority
        del _helper_suits
        del boss
        del in_range
        del _toons_in_range
        try:
            del args
        except:
            pass

        try:
            del new_state
        except:
            pass

        try:
            del state_num
        except:
            pass

        try:
            del av
        except:
            pass

        if task:
            return task.again
        else:
            return

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterNeutral(self):
        self.suit.createPath(fromCurPos=True)
        self.numAttacksThrown = 0
        if not self.suit.isBackup():
            self.neutral_startLookingForToons()

    def neutral_startLookingForToons(self):
        taskMgr.add(self.__lookForToons, self.suit.uniqueName('lookForToon'))

    def neutral_stopLookingForToons(self):
        taskMgr.remove(self.suit.uniqueName('lookForToon'))

    def __lookForToons(self, task):
        if self.suit.isBackup() or not hasattr(self, 'numAttacksThrown'):
            return task.done
        elif self.suit.getAttacking():
            task.delayTime = 1.0
            return task.again
        elif self.numAttacksThrown >= self.Difficulty2MaxAttackThrows[self.suit.getLevel()]:
            self.numAttacksThrown = 0
            if not self.suit.isWalking():
                self.suit.createPath(path_key=self.suit.currentPath, fromCurPos=True)
            task.delayTime = 10
            return task.again
        else:
            closestToonOrTurret = None
            obj2range = {}
            for obj in base.air.doId2do.values():
                if obj.__class__.__name__ in ('DistributedToonAI', 'DistributedPieTurretAI'):
                    if obj.zoneId == self.suit.zoneId:
                        if not obj.isDead():
                            if obj.__class__.__name__ == 'DistributedToonAI':
                                if obj.getNumAttackers() < self.MAX_ATTACKERS:
                                    dist = obj.getDistance(self.suit)
                                    if dist <= self.ATTACK_DISTANCE:
                                        obj2range[obj] = dist
                            else:
                                dist = obj.getDistance(self.suit)
                                if dist <= self.ATTACK_DISTANCE:
                                    obj2range[obj] = dist

            ranges = []
            for distance in obj2range.values():
                ranges.append(distance)

            ranges.sort()
            for obj in obj2range.keys():
                distance = obj2range[obj]
                if distance == ranges[0]:
                    closestToonOrTurret = obj

            if closestToonOrTurret != None and not self.suit.getAttacking():
                if self.suit.head != 'vp':
                    if self.suit.walkTrack:
                        self.ignore(self.suit.walkTrack.getName())
                        self.suit.walkTrack.clearToInitial()
                        self.suit.walkTrack = None
                self.suit.b_setSuitState(3, -1, -1)
                self.suit.b_setAnimState('neutral')
                self.end(0)
                self.suit.headsUp(closestToonOrTurret)
                self.suit.attackToon(closestToonOrTurret)
                self.suit.setAttacking(True)
                if closestToonOrTurret.__class__.__name__ == 'DistributedToonAI':
                    closestToonOrTurret.addNewAttacker(self.suit.doId)
                self.numAttacksThrown += 1
                return task.done
            if self.numAttacksThrown > 0:
                if not self.suit.isWalking():
                    self.suit.createPath(path_key=self.suit.currentPath, fromCurPos=True)
            elif not self.suit.isWalking():
                self.suit.createPath(fromCurPos=True)
            self.numAttacksThrown = 0
            task.delayTime = 3.5
            return task.again

    def exitNeutral(self):
        self.neutral_stopLookingForToons()
        del self.numAttacksThrown

    def enterPanic(self):
        taskMgr.add(self.__panic, self.suit.uniqueName('panic'))

    def __panic(self, task):
        self.suit.createPath(durationFactor=self.PANIC_SPEED, fromCurPos=True)
        if task.time == 2.0:
            self.__think(None)
        task.delayTime = self.PANIC_DELAY
        return task.again

    def exitPanic(self):
        taskMgr.remove(self.suit.uniqueName('panic'))

    def enterFollowBoss(self, boss):
        self.boss = boss
        if boss.boss.spot == None:
            self.bossSpot = boss.getPos(render)
        else:
            self.bossSpot = CIGlobals.SuitSpawnPoints[self.suit.hood][boss.boss.spot]
        if self.suit.currentPath == boss.boss.spot:
            self.suit.createPath(path_key=boss.boss.spot, fromCurPos=True)
        else:
            self.suit.currentPathQueue = SuitPathFinder.find_path(self.suit.hood, self.suit.currentPath, boss.boss.spot)
            self.suit.currentPathQueue.remove(self.suit.currentPathQueue[0])
            self.suit.createPath(fromCurPos=True)
        taskMgr.add(self.__followBoss, self.suit.uniqueName('followBoss'))
        self.bossSpotKey = boss.boss.spot
        return

    def __followBoss(self, task):
        if self.boss not in self.suit.getManager().suits.values():
            self.fsm.request('neutral')
            return task.done
        elif self.suit.getDistance(self.boss) <= 4:
            self.suit.b_setSuitState(3, -1, -1)
            if self.suit.walkTrack:
                self.suit.ignore(self.suit.walkTrack.getDoneEvent())
                self.suit.walkTrack.pause()
                self.suit.walkTrack = None
                self.suit.b_setAnimState('neutral')
                self.suit.setH(self.suit.getH() - 180)
                self.suit.d_setH(self.suit.getH())
            return task.done
        else:
            return task.cont

    def exitFollowBoss(self):
        self.suit.resetPathQueue()
        taskMgr.remove(self.suit.uniqueName('followBoss'))
        del self.boss
        del self.bossSpot
        del self.bossSpotKey

    def enterRunAway(self, toon):
        self.toon = toon
        self.suit.createPath(durationFactor=self.RUNAWAY_SPEED, fromCurPos=True)
        taskMgr.add(self.__runAway, self.suit.uniqueName('runAway'))

    def __runAway(self, task):
        try:
            if self.suit.getDistance(self.toon) >= self.RUNAWAY_SAFE_DISTANCE:
                self.start()
                return task.done
            if self.suit.walkTrack == None or self.suit.walkTrack.isStopped():
                self.suit.createPath(durationFactor=self.RUNAWAY_SPEED, fromCurPos=True)
            return task.cont
        except:
            self.fsm.request('neutral')
            return task.done

        return

    def exitRunAway(self):
        taskMgr.remove(self.suit.uniqueName('runAway'))
        del self.toon
class MasterHuman(HumanBase.HumanBase, Biped.Biped):
    notify = DirectNotifyGlobal.directNotify.newCategory('Human')
    prebuiltAnimData = { }

    def __init__(self, other = None):
        Biped.Biped.__init__(self, other, HumanAnimationMixer)
        self.model = None
        self.useFaceTex = True
        self.joints = { }
        self.jointTrans = { }
        self.jointTrans2 = { }
        self.zombie = False
        self.crazyColorSkin = False
        self.crazyColorSkinIndex = 0
        self.flattenPending = None
        self.optimizeLOD = base.config.GetBool('optimize-avatar-lod', 1)
        self.master = 0
        self.loaded = 0
        self.playingRate = None
        self.shadowFileName = 'models/misc/drop_shadow'
        self.setFont(PiratesGlobals.getInterfaceFont())
        self._MasterHuman__blinkName = 'blink-' + str(self.this)
        self.eyeLids = None
        self.eyeBalls = None
        self.eyeIris = None
        self.reducedAnimList = None
        self.rootScale = 1.0
        self.headNode = None
        self.extraNode = None
        self.scaleNode = None
        self.rootNode = None
        self.floorOffsetZ = 0.0
        self.headFudgeHpr = Vec3(0, 0, 0)
        self.frozeSomething = True
        self.randGen = random.Random()
        self.randGen.seed(random.random())
        self.eyeFSM = ClassicFSM('eyeFSM', [
            State('off', self.enterEyeFSMOff, self.exitEyeFSMOff, [
                'open',
                'closed']),
            State('open', self.enterEyeFSMOpen, self.exitEyeFSMOpen, [
                'closed',
                'off']),
            State('closed', self.enterEyeFSMClosed, self.exitEyeFSMClosed, [
                'open',
                'off'])], 'off', 'off')
        self.eyeFSM.enterInitialState()
        if other != None:
            self.copyHuman(other)

        self.isPaid = False


    def removeCopiedNodes(self):
        self.dropShadow = self.find('**/drop_shadow*')
        if not self.dropShadow.isEmpty():
            self.deleteDropShadow()
        else:
            self.dropShadow = None


    def flattenHuman(self):
        self.deleteNametag3d()
        self.getWeaponJoints()


    def _MasterHuman__doneFlattenHuman(self, models):
        self.flattenPending = None
        self.getWeaponJoints()


    def copyHuman(self, other):
        self.gender = other.gender
        self.loaded = other.loaded
        self.type = other.type
        self.loadAnimatedHead = other.loadAnimatedHead
        self.model = None


    def delete(self):

        try:
            pass
        except:
            self.Human_deleted = 1
            taskMgr.remove(self._MasterHuman__blinkName)
            if self.dropShadow and not self.dropShadow.isEmpty():
                self.deleteDropShadow()

            del self.eyeFSM
            self.controlShapes = None
            self.sliderNames = None
            if self.model:
                self.model.delete()
                del self.model

            Biped.Biped.delete(self)



    def isDeleted(self):

        try:
            if self.Human_deleted == 1:
                return True
        except:
            return False



    def fixEyes(self):
        self.eyeLids = { }
        self.eyeBalls = { }
        self.eyeIris = { }
        for lodName in self.getLODNames():
            geom = self.getPart('head', lodName)
            self.eyeLids[lodName] = geom.findAllMatches('**/*eyelid*')
            self.eyeBalls[lodName] = geom.findAllMatches('**/eye_ball*')
            self.eyeIris[lodName] = geom.findAllMatches('**/eye_iris*')
            self.eyeLids[lodName].stash()
            self.eyeBalls[lodName].unstash()
            self.eyeIris[lodName].unstash()



    def getCrazyColorSkinIndex(self):
        return self.crazyColorSkinIndex


    def setCrazyColorSkinIndex(self, index):
        if len(HumanDNA.crazySkinColors) > index:
            self.crazyColorSkinIndex = index
        else:
            self.notify.warning('(MasterHuman)index: %d is out of bounds for crazyColorSkin: %d' % (index, len(HumanDNA.crazySkinColors)))


    def generateSkinColor(self):
        skinColor = self.style.getSkinColor()
        lowColor = self.model.lowLODSkinColor
        color = VBase4(lowColor[0] * skinColor[0], lowColor[1] * skinColor[1], lowColor[2] * skinColor[2], 1.0)
        self.model.faces[0].setColorScale(skinColor)
        if self.model.newAvatars:
            self.model.currentBody.setColorScale(skinColor)
            if self.optimizeLOD:
                self.model.currentBody[2].setColorScale(color)
                self.model.faces[0][2].setColorScale(color)

        else:
            numPaths = self.model.body.getNumPaths()
            medIdx = numPaths / 3
            lowIdx = (numPaths / 3) * 2
            if self.zombie:
                self.model.body.setColorScale(Vec4(1, 1, 1, 1))
                if self.optimizeLOD:
                    color = VBase4(121 / 255.0, 124 / 255.0, 103 / 255.0, 1.0)
                    for i in xrange(lowIdx, numPaths):
                        self.model.body[i].setColorScale(color)

                    self.model.faceZomb[2].setColorScale(color)

            else:
                self.model.body.setColorScale(skinColor)
                lowColor = self.model.lowLODSkinColor
                if self.optimizeLOD:
                    color = VBase4(lowColor[0] * skinColor[0], lowColor[1] * skinColor[1], lowColor[2] * skinColor[2], 1.0)
                    for i in xrange(lowIdx, numPaths):
                        self.model.body[i].setColorScale(color)




    def generateSkinTexture(self):
        bodyTextureIdx = self.style.body.skin
        if self.zombie:
            if self.gender == 'f':
                bodyTextureIdx = PirateFemale.ZOMB_BODY_TEXTURE
            else:
                bodyTextureIdx = PirateMale.ZOMB_BODY_TEXTURE

        if self.gender == 'f':
            body_textures = PirateFemale.body_textures[self.style.body.shape]
        else:
            body_textures = PirateMale.body_textures[0] #self.style.body.shape]
        tex_name = self.getTrySafe(body_textures, bodyTextureIdx)
        if tex_name != None:
            tex = self.model.bodyTextures.findTexture(tex_name)
        else:
            return None
        if tex:
            for parts in self.model.bodys:
                numPaths = parts.getNumPaths()
                for i in xrange(numPaths):
                    parts[i].setTexture(tex, 1)





    def generateFaceTexture(self, default):
        if default:
            faceTextureIdx = 0
        else:
            faceTextureIdx = self.style.head.texture
        if faceTextureIdx >= len(self.model.faceTexturesSet):
            faceTextureIdx = 0

        self.model.faces[0].setTexture(self.model.faceTexturesSet[faceTextureIdx])


    def generateHairColor(self, colorName = None, colorModel = None):
        self.model.setHairBaseColor()


    def getTrySafe(self, list, idx):

        try:
            if type(idx) == str:
                lookup = idx.split('_cut')[0]
            else:
                lookup = idx
            return list[lookup]
        except:
            return None



    def generateEyesTexture(self):
        eyesTextureIdx = self.style.head.eyes.color
        if self.gender == 'f':
            eye_iris_textures = PirateFemale.eye_iris_textures
        else:
            eye_iris_textures = PirateMale.eye_iris_textures
        tex_name = self.getTrySafe(eye_iris_textures, eyesTextureIdx)
        if tex_name != None:
            tex = self.eyeIrisTextures.findTexture(tex_name)
        else:
            return None
        if tex:
            self.model.irises.setTexture(tex, 1)



    def generateHatColor(self):
        style = self.model.dna
        if self.zombie:
            style = self.model.dnaZomb

        hatColor = style.lookupHatColor()
        geom = self.getGeomNode()
        parts = geom.findAllMatches('**/hat_band*')
        parts.setColorScale(hatColor)


    def generateClothesColor(self):
        style = self.model.dna
        if self.zombie:
            style = self.model.dnaZomb

        clothesTopColor = style.lookupClothesTopColor()
        clothesBotColor = style.lookupClothesBotColor()
        geom = self.getGeomNode()
        if self.optimizeLOD:

            def tempColorParts(parts, ct):
                numPaths = parts.getNumPaths()
                lowIdx = (numPaths / 3) * 2
                for j in xrange(lowIdx):
                    parts[j].setColorScale(ct)

                for j in xrange(lowIdx, numPaths):
                    cl = parts[j].getColorScale()
                    compoundColor = VBase4(cl[0] * ct[0], cl[1] * ct[1], cl[2] * ct[2], 1.0)
                    parts[j].setColorScale(compoundColor)


        else:

            def tempColorParts(parts, ct):
                parts.setColorScale(ct)

        colorParts = tempColorParts
        parts = geom.findAllMatches('**/clothing_layer1_shirt*')
        colorParts(parts, clothesTopColor[0])
        parts = geom.findAllMatches('**/clothing_layer2_vest*')
        colorParts(parts, clothesTopColor[1])
        parts = geom.findAllMatches('**/clothing_layer3_coat*')
        colorParts(parts, clothesTopColor[2])
        parts = geom.findAllMatches('**/clothing_layer1_pant*')
        colorParts(parts, clothesBotColor[0])
        del colorParts


    def generateTexture(self):
        self.generateFaceTexture(not (self.useFaceTex))
        self.generateEyesTexture()


    def generateColor(self):
        self.generateSkinColor()
        self.generateHairColor()
        self.generateHatColor()


    def makeAnimDict(self, gender, animNames):
        self.animTable = []
        for currAnim in animNames:
            anim = animNames.get(currAnim)
            for currAnimName in anim:
                self.animTable.append([
                    currAnimName,
                    currAnimName])


        self.reducedAnimList = self.animTable


    def forceLoadAnimDict(self):
        for anim in self.animTable:
            self.getAnimControls(anim[0])



    def createAnimDict(self, customList = None):
        if self.reducedAnimList is None:
            self.animDict = self.prebuiltAnimData[self.gender + self.type]
            return None

        if self.gender == 'f':
            filePrefix = 'models/char/f'
            genderPrefix = 'f'
        else:
            filePrefix = 'models/char/m'
            genderPrefix = 'm'
        filePrefix += 'p'
        animList = self.reducedAnimList
        if animList is None:
            animList = AnimListDict[self.type]

        self.animDict = { }
        for anim in animList:
            animSuffix = ''
            for i in range(0, len(CustomAnimDict[genderPrefix + self.type])):
                if anim[0] == CustomAnimDict[genderPrefix + self.type][i]:
                    animSuffix = '_' + genderPrefix + NewModelDict.get(self.type)
                    break
                    continue

            self.animDict[anim[0]] = filePrefix + '_' + anim[1] + animSuffix

        if self.reducedAnimList is None:
            self.animDict.pop('intro')

        return filePrefix


    def generateBody(self, copy = 1):
        if self.gender == 'm':
            filePrefix = 'models/char/mp'
        else:
            filePrefix = 'models/char/fp'
        messenger.send('tick')
        lodString = '2000'
        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '2000', copy)
        messenger.send('tick')
        if loader.loadModel(filePrefix + '_' + '1000', allowInstance = True) != None:
            lodString = '1000'

        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '1000', copy)
        messenger.send('tick')
        if loader.loadModel(filePrefix + '_' + '500', allowInstance = True) != None:
            lodString = '500'

        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '500', copy)
        messenger.send('tick')
        self.makeSubpart('head', [
            'zz_head01'], [])
        self.makeSubpart('torso', [
            'zz_spine01'], [
            'zz_head01'])
        self.makeSubpart('legs', [
            'dx_root'], [
            'zz_spine01'])
        self.setSubpartsComplete(True)
        self.eyeIrisTextures = loader.loadModel('models/misc/eye_iris.bam')


    def setLODs(self):
        self.setLODNode()
        avatarDetail = base.config.GetString('avatar-detail', 'high')
        if avatarDetail == 'high':
            dist = [
                0,
                20,
                80,
                1000000000]
        elif avatarDetail == 'med':
            dist = [
                0,
                10,
                20,
                1000000000]
        elif avatarDetail == 'low':
            dist = [
                0,
                0,
                10,
                1000000000]
        else:
            raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
        self.addLOD(2000, dist[1], dist[0])
        self.addLOD(1000, dist[2], dist[1])
        self.addLOD(500, dist[3], dist[2])
        if self.optimizeLOD:
            lowLOD = self.getLOD('500')
            lowLOD.setTransparency(0, 1000)

        self.getLODNode().setCenter(Point3(0, 0, 5))


    def showLOD(self, lodName):
        self.generateTexture()
        self.model.setFromDNA()
        tex = self.model.faces[0][2].findTexture('*face*')


    def loadHuman(self, gender = 'm', other = None):
        self.gender = gender
        if self.gender == 'f':
            controlShapes = PirateFemale.ControlShapes
            sliderNames = PirateFemale.SliderNames
        else:
            controlShapes = PirateMale.ControlShapes
            sliderNames = PirateMale.SliderNames
        self.setLODs()
        self.loadAnimatedHead = True
        self.generateBody()
        if self.gender == 'f':
            self.type = BodyDefs.femaleFrames[self.style.getBodyShape()]
            self.model = PirateFemale.PirateFemale(self, self.style)
        else:
            self.type = BodyDefs.maleFrames[self.style.getBodyShape()]
            self.model = PirateMale.PirateMale(self, self.style)
        self.faceAwayFromViewer()
        self.lods = self.getLODNames()
        if self.gender == 'f':
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 1
        else:
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 0
        messenger.send('tick')
        self.model.setupHead(2000)
        messenger.send('tick')
        self.model.setupBody(2000)
        messenger.send('tick')
        self.model.setupClothing(2000)
        messenger.send('tick')
        if self.master:
            self.model.setupSelectionChoices('NPC')

        self.showNormal()
        self.createAnimDict()
        messenger.send('tick')
        self.initAnimsOnAllLODs([
            'head',
            'legs',
            'torso',
            'modelRoot'])
        messenger.send('tick')
        self.controlShapes = controlShapes
        self.sliderNames = sliderNames
        self.initHeadControlShapes()
        self.storeJoints()
        self.find('**/nametag3d').detachNode()
        self.findAllMatches('**/name_tag').detach()
        self.rootNode = self.getLOD('2000').find('**/dx_root')
        self.floorOffsetZ = self.rootNode.getZ()
        messenger.send('tick')
        root = self.getLOD('500')
        gr = SceneGraphReducer()
        gr.applyAttribs(root.node(), gr.TTTransform | gr.TTTexMatrix | gr.TTOther)
        gr.makeCompatibleFormat(root.node(), 0)
        gr.premunge(root.node(), RenderState.makeEmpty())
        gr.decompose(root.node())
        stashedSet = root.findAllMatches('**/@@*')
        stashedSet.unstash()
        gr.makeCompatibleFormat(root.node(), 0)
        stashedSet.stash()
        messenger.send('tick')
        for face in self.model.faces[0]:
            node = face.node()
            for i in range(node.getNumGeoms()):
                face.node().setGeomState(i, RenderState.makeEmpty())




    def initializeMiscNodes(self):
        self.initializeNametag3d()
        self.initializeDropShadow()
        if self.getLOD('2000') == None:
            return None

        exposedHeadJoint = self.getLOD('2000').find('**/def_head01')
        if not exposedHeadJoint.isEmpty():
            idx = 0
            if self.gender == 'f':
                idx = 1

            exposedHeadJoint.setScale(1)
            self.headNode.reparentTo(exposedHeadJoint)
            self.headNode.setScale(HeadScales[idx][self.style.getBodyShape()])



    def undoControlJoints(self):
        self.getGeomNode().getParent().findAllMatches('def_*').detach()
        self.getGeomNode().getParent().findAllMatches('trs_*').detach()
        self.findAllMatches('def_*').detach()
        self.findAllMatches('trs_*').detach()


    def cleanupHuman(self, gender = 'm'):
        self.eyeFSM.request('off')
        self.undoControlJoints()
        self.eyeLids = { }
        self.eyeBalls = { }
        self.eyeIris = { }
        self.flush()
        self.loaded = 0
        self.master = 0


    def generateHuman(self, gender = 'm'):
        self.loadHuman(self.style.gender)


    def getShadowJoint(self):
        return self


    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('legs', lodName)
            joint = bundle.findChild('name_tag')
            if joint:
                joints.append(joint)
                continue

        return joints


    def _MasterHuman__blinkOpenEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() == 'closed':
            self.eyeFSM.request('open')

        r = self.randGen.random()
        if r < 0.10000000000000001:
            t = 0.20000000000000001
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self._MasterHuman__blinkCloseEyes, self._MasterHuman__blinkName)
        return Task.done


    def _MasterHuman__blinkCloseEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() != 'open':
            taskMgr.doMethodLater(4.0, self._MasterHuman__blinkCloseEyes, self._MasterHuman__blinkName)
        else:
            self.eyeFSM.request('closed')
            taskMgr.doMethodLater(0.125, self._MasterHuman__blinkOpenEyes, self._MasterHuman__blinkName)
        return Task.done


    def startBlink(self):
        taskMgr.remove(self._MasterHuman__blinkName)
        if self.eyeLids:
            self.openEyes()

        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1, self._MasterHuman__blinkCloseEyes, self._MasterHuman__blinkName)


    def stopBlink(self):
        taskMgr.remove(self._MasterHuman__blinkName)
        if self.eyeLids:
            self.eyeFSM.request('open')



    def closeEyes(self):
        self.eyeFSM.request('closed')


    def openEyes(self):
        self.eyeFSM.request('open')


    def enterEyeFSMOff(self):
        pass


    def exitEyeFSMOff(self):
        pass


    def enterEyeFSMOpen(self):
        for lodName in self.getLODNames():
            if not self.eyeLids[lodName].isEmpty():
                self.eyeLids[lodName].hide()
                self.eyeBalls[lodName].show()
                self.eyeIris[lodName].show()
                continue



    def exitEyeFSMOpen(self):
        pass


    def enterEyeFSMClosed(self):
        return None
        for lodName in self.getLODNames():
            if not self.eyeLids[lodName].isEmpty():
                self.eyeLids[lodName].show()
                self.eyeBalls[lodName].hide()
                self.eyeIris[lodName].hide()
                continue



    def exitEyeFSMClosed(self):
        pass


    def setControlValue(self, r, name):
        if self.style.getGender() == 'f':
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixI = FemaleHeadShapeInitialControlJointMatrix
        else:
            matrixF = MaleHeadShapeControlJointMatrix
            matrixI = MaleHeadShapeInitialControlJointMatrix
        shapes = self.controlShapes
        ctl = shapes[name]
        slider = ctl[0]
        if r < 0.0:
            if len(ctl) > 1:
                slider = ctl[1]


        for i in range(0, len(slider)):
            jointName = slider[i][0]
            jointCtls = self.findAllMatches(jointName)
            posI = matrixI[jointName][0]
            hprI = matrixI[jointName][1]
            sclI = matrixI[jointName][2]
            posF = VBase3(posI[0], posI[1], posI[2])
            hprF = VBase3(hprI[0], hprI[1], hprI[2])
            sclF = VBase3(sclI[0], sclI[1], sclI[2])
            self.notify.debug('scv: %s initial %s' % (jointName, posI))
            dr = slider[i][4] * r
            ctl[0][i][5] = dr
            posDelta = VBase3(0, 0, 0)
            hprDelta = VBase3(0, 0, 0)
            sclDelta = VBase3(0, 0, 0)
            for sliderIdx in xrange(0, len(matrixF[jointName])):
                sliderName = matrixF[jointName][sliderIdx]
                jointSet = shapes[sliderName][0]
                for jointIdx in xrange(0, len(jointSet)):
                    if jointSet[jointIdx][0] == jointName:
                        if jointSet[jointIdx][1] == TX:
                            posDelta.setX(posDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == TY:
                            posDelta.setY(posDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == TZ:
                            posDelta.setZ(posDelta.getZ() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RX:
                            hprDelta.setX(hprDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RY:
                            hprDelta.setY(hprDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RZ:
                            hprDelta.setZ(hprDelta.getZ() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SX:
                            if r < 0.0:
                                sclDelta.setX(sclDelta.getX() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setX(sclDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SY:
                            if r < 0.0:
                                sclDelta.setY(sclDelta.getY() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setY(sclDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SZ:
                            if r < 0.0:
                                sclDelta.setZ(sclDelta.getZ() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setZ(sclDelta.getZ() + jointSet[jointIdx][5])
                        else:
                            self.notify.warning('scv:wrong element = %s' % jointSet[jointIdx][1])
                    jointSet[jointIdx][1] == TX


            self.notify.debug('scv: %s composite posDelta = %s' % (jointName, posDelta))
            posF.setX(posI[0] + posDelta[0])
            posF.setY(posI[1] + posDelta[1])
            posF.setZ(posI[2] + posDelta[2])
            self.notify.debug('scv: %s final posDelta%s' % (jointName, posF))
            self.notify.debug('scv: %s composite hprDelta = %s' % (jointName, hprDelta))
            hprF.setX(hprI[0] + hprDelta[0])
            hprF.setY(hprI[1] + hprDelta[1])
            hprF.setZ(hprI[2] + hprDelta[2])
            self.notify.debug('scv: %s final hprDelta%s' % (jointName, hprF))
            self.notify.debug('scv: %s composite sclDelta = %s' % (jointName, sclDelta))
            sclF.setX(sclI[0] + sclDelta[0])
            sclF.setY(sclI[1] + sclDelta[1])
            sclF.setZ(sclI[2] + sclDelta[2])
            self.notify.debug('scv: %s final sclDelta%s' % (jointName, sclF))
            for j in range(0, jointCtls.getNumPaths()):
                jointCtl = jointCtls[j]
                jointCtl.setPosHprScale(posF, hprF, sclF)




    def applyBodyShaper(self):
        if self.style.getGender() == 'f':
            tjs = FemaleBodyShapeTranslateJoints
            sjs = FemaleBodyShapeScaleJoints
            matrix = FemaleBodyShapeControlJointMatrix
        else:
            tjs = MaleBodyShapeTranslateJoints
            sjs = MaleBodyShapeScaleJoints
            matrix = MaleBodyShapeControlJointMatrix
        type = 0 #self.style.getBodyShape()
        for jointName in tjs:
            transData = self.jointTrans[jointName]
            vector = matrix[jointName][type]
            self.joints[jointName].applyFreezeMatrix(vector, transData[1], transData[2])

        for jointName in sjs:
            transData = self.jointTrans[jointName]
            vector = matrix[jointName][type]
            self.joints[jointName].applyFreezeMatrix(transData[0], transData[1], vector)

        value = self.style.getHeadSize()
        mappedValue = 0.90000000000000002 + (1 + value) * 0.10000000000000001
        transData = self.jointTrans['def_extra_jt']
        self.joints['def_extra_jt'].applyFreezeMatrix(transData[0], transData[1], Vec3(2 - mappedValue, mappedValue, 1))
        transData = self.jointTrans['def_head01']
        idx = 0
        if self.style.gender == 'f':
            idx = 1

        self.joints['def_head01'].applyFreezeMatrix(transData[0], transData[1], Vec3(HeadScales[idx][0])) #self.style.getBodyShape()]))
        self.setGlobalScale(self.calcBodyScale())


    def undoBodyShaper(self):
        if self.style.getGender() == 'f':
            cjs = FemaleBodyShapeControlJoints
        else:
            cjs = MaleBodyShapeControlJoints


    def applyHeadShaper(self):
        self.setHeadControlShapeValues()


    def undoHeadShaper(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
        else:
            cjs = MaleHeadShapeControlJoints


    def createControlJoints(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
        else:
            cjs = MaleHeadShapeControlJoints
        for jointName in cjs:
            for lodName in self.getLODNames():
                if lodName == '2000':
                    joint = self.controlJoint(None, 'legs', jointName, lodName)
                    continue
                if lodName == '1000':
                    continue
                    continue
                if lodName == '500':
                    continue
                    continue




    def initHeadControlShapes(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixI = FemaleHeadShapeInitialControlJointMatrix
            matrixIHelper = FemaleHeadInitHelper
        else:
            cjs = MaleHeadShapeControlJoints
            matrixF = MaleHeadShapeControlJointMatrix
            matrixI = MaleHeadShapeInitialControlJointMatrix
            matrixIHelper = MaleHeadInitHelper
        if len(matrixF['initialized']) > 0:
            return None

        initializedMatrixI = len(matrixI['initialized'])
        initializedMatrixF = len(matrixF['initialized'])
        for jointName in cjs:
            transform = TransformState.makeMat(self.getJointTransform('legs', jointName, '2000'))
            pos = Vec3(transform.getPos())
            hpr = Vec3(transform.getHpr())
            scale = Vec3(transform.getScale())
            matrixI[jointName].append(pos)
            matrixI[jointName].append(hpr)
            matrixI[jointName].append(scale)
            matrixIHelper[jointName] = [
                pos[0],
                pos[1],
                pos[2],
                hpr[0],
                hpr[1],
                hpr[2],
                scale[0],
                scale[1],
                scale[2]]

        matrixI['initialized'].append('initialized')
        shapes = self.controlShapes
        names = self.sliderNames
        for i in xrange(0, len(shapes)):
            slider = shapes[names[i]]
            for k in xrange(0, len(slider[0])):
                slider[0][k][4] = slider[0][k][2]
                if len(slider) > 1:
                    slider[1][k][4] = slider[1][k][2]
                    continue


        for i in xrange(0, len(shapes)):
            slider = shapes[names[i]]
            for k in xrange(0, len(slider[0])):
                jointCtl = slider[0][k]
                jointName = jointCtl[0]
                matrixF[jointName].append(names[i])
                pos = matrixI[jointName][0]
                hpr = matrixI[jointName][1]
                scl = matrixI[jointName][2]
                if jointCtl[1] < 3:
                    posDelta = jointCtl[4] - pos[jointCtl[1]]
                    jointCtl[4] = posDelta
                    if len(slider) > 1:
                        jointCtl = slider[1][k]
                        jointCtl[4] = posDelta

                len(slider) > 1
                if jointCtl[1] > 2 and jointCtl[1] < 6:
                    hprDelta = jointCtl[4] - hpr[jointCtl[1] - 3]
                    jointCtl[4] = hprDelta
                    if len(slider) > 1:
                        jointCtl = slider[1][k]
                        jointCtl[4] = hprDelta

                len(slider) > 1
                sclDelta = 12 #jointCtl[4] - scl[jointCtl[1] - 6]
                jointCtl[4] = sclDelta
                if len(slider) > 1:
                    jointCtl = slider[1][k]
                    jointCtl[4] = sclDelta
                    continue


        matrixF['initialized'].append('initialized')


    def setHeadControlShapeValues_old(self):
        value = self.style.getHeadSize()
        mappedValue = 0.90000000000000002 + (1 + value) * 0.10000000000000001
        self.setControlValue(self.style.getHeadWidth(), 'headWidth')
        self.setControlValue(self.style.getHeadHeight(), 'headHeight')
        self.setControlValue(self.style.getHeadRoundness(), 'headRoundness')
        self.setControlValue(self.style.getJawWidth(), 'jawWidth')
        self.setControlValue(self.style.getJawAngle(), 'jawChinAngle')
        self.setControlValue(self.style.getJawChinSize(), 'jawChinSize')
        self.setControlValue(self.style.getJawLength(), 'jawLength')
        self.setControlValue(self.style.getMouthWidth(), 'mouthWidth')
        self.setControlValue(self.style.getMouthLipThickness(), 'mouthLipThickness')
        self.setControlValue(self.style.getCheekFat(), 'cheekFat')
        self.setControlValue(self.style.getBrowProtruding(), 'browProtruding')
        self.setControlValue(self.style.getEyeCorner(), 'eyeCorner')
        self.setControlValue(self.style.getEyeOpeningSize(), 'eyeOpeningSize')
        self.setControlValue(self.style.getEyeBulge(), 'eyeSpacing')
        self.setControlValue(self.style.getNoseBridgeWidth(), 'noseBridgeWidth')
        self.setControlValue(self.style.getNoseNostrilWidth(), 'noseNostrilWidth')
        self.setControlValue(self.style.getNoseLength(), 'noseLength')
        self.setControlValue(self.style.getNoseBump(), 'noseBump')
        self.setControlValue(self.style.getNoseNostrilHeight(), 'noseNostrilHeight')
        self.setControlValue(self.style.getNoseNostrilAngle(), 'noseNostrilAngle')
        self.setControlValue(self.style.getNoseBridgeBroke(), 'noseBridgeBroke')
        self.setControlValue(self.style.getNoseNostrilBroke(), 'noseNostrilBroke')
        self.setControlValue(self.style.getEarScale(), 'earScale')
        self.setControlValue(self.style.getEarFlapAngle(), 'earFlap')
        self.setControlValue(self.style.getEarPosition(), 'earPosition')


    def getGlobalScale(self):
        return self.scaleNode.getScale()


    def setGlobalScale(self, scale):
        transData = self.jointTrans['def_head01']
        pos = Vec3(transData[0])
        pos.setZ(-(self.floorOffsetZ * (1 - scale)))
        self.joints['def_scale_jt'].applyFreezeMatrix(pos, transData[1], Vec3(scale))
        self.rootScale = scale


    def calcBodyScale(self):
        idx = 0
        if self.gender == 'f':
            idx = 1

        mappedValue = (0.80000000000000004 + (1 + self.style.getBodyHeight()) * 0.20000000000000001) * BodyScales[idx][0]#self.style.getBodyShape()]
        return mappedValue


    def showZombie(self):
        self.model.irises.stash()
        self.model.faces[0].stash()
        self.model.faceZomb.unstash()
        self.generateSkinTexture()


    def showNormal(self):
        self.model.irises.unstash()
        self.model.faces[0].unstash()
        self.model.faceZomb.stash()
        self.generateSkinTexture()


    def takeAwayTexture(self, geoms, omitFace = False):
        emptyRenderState = RenderState.makeEmpty()
        eyeIrisColor = VBase4(0, 0, 0, 1)
        for i in range(0, geoms.getNumPaths()):
            element = geoms[i]
            if 'eye_iris' in element.getName():
                element.setColorScale(eyeIrisColor)
            elif omitFace and 'master_face' in element.getName():
                continue

            element.setTextureOff()
            geom = element.node()
            for j in range(0, geom.getNumGeoms()):
                geom.setGeomState(j, emptyRenderState)




    def optimizeMedLOD(self):
        medLOD = self.getLOD('1000')
        geoms = medLOD.findAllMatches('**/teeth*')
        geoms.stash()
        self.medSkinGone = False
        geoms = medLOD.find('**/body_forearm*')
        if geoms.isEmpty():
            self.medSkinGone = True
            geoms = medLOD.findAllMatches('**/body_*')
            self.takeAwayTexture(geoms, True)

        geoms = medLOD.findAllMatches('**/hair_*')
        self.takeAwayTexture(geoms)
        if self.gender != 'f':
            geoms = medLOD.findAllMatches('**/beard_*')
            self.takeAwayTexture(geoms)
            geoms = medLOD.findAllMatches('**/mustache_*')
            self.takeAwayTexture(geoms)

        geoms = medLOD.findAllMatches('**/eye_*')
        self.takeAwayTexture(geoms)
        geoms = medLOD.findAllMatches('**/clothing_layer2_belt_*')
        self.takeAwayTexture(geoms)
        geoms = medLOD.findAllMatches('**/clothing_layer1_shoe_*')
        self.takeAwayTexture(geoms)


    def optimizeLowLOD(self):
        lowLOD = self.getLOD('500')
        geoms = lowLOD.findAllMatches('**/teeth*')
        geoms.stash()
        geoms = lowLOD.findAllMatches('**/+GeomNode')
        self.takeAwayTexture(geoms)


    def setHeadControlShapeValues(self):
        value = self.style.getHeadSize()
        mappedValue = 0.90000000000000002 + (1 + value) * 0.10000000000000001
        self.setControlValue_new(self.style.getHeadWidth(), 'headWidth')
        self.setControlValue_new(self.style.getHeadHeight(), 'headHeight')
        self.setControlValue_new(self.style.getHeadRoundness(), 'headRoundness')
        self.setControlValue_new(self.style.getJawWidth(), 'jawWidth')
        self.setControlValue_new(self.style.getJawAngle(), 'jawChinAngle')
        self.setControlValue_new(self.style.getJawChinSize(), 'jawChinSize')
        self.setControlValue_new(self.style.getJawLength(), 'jawLength')
        self.setControlValue_new(self.style.getMouthWidth(), 'mouthWidth')
        self.setControlValue_new(self.style.getMouthLipThickness(), 'mouthLipThickness')
        self.setControlValue_new(self.style.getCheekFat(), 'cheekFat')
        self.setControlValue_new(self.style.getBrowProtruding(), 'browProtruding')
        self.setControlValue_new(self.style.getEyeCorner(), 'eyeCorner')
        self.setControlValue_new(self.style.getEyeOpeningSize(), 'eyeOpeningSize')
        self.setControlValue_new(self.style.getEyeBulge(), 'eyeSpacing')
        self.setControlValue_new(self.style.getNoseBridgeWidth(), 'noseBridgeWidth')
        self.setControlValue_new(self.style.getNoseNostrilWidth(), 'noseNostrilWidth')
        self.setControlValue_new(self.style.getNoseLength(), 'noseLength')
        self.setControlValue_new(self.style.getNoseBump(), 'noseBump')
        self.setControlValue_new(self.style.getNoseNostrilHeight(), 'noseNostrilHeight')
        self.setControlValue_new(self.style.getNoseNostrilAngle(), 'noseNostrilAngle')
        self.setControlValue_new(self.style.getNoseBridgeBroke(), 'noseBridgeBroke')
        self.setControlValue_new(self.style.getNoseNostrilBroke(), 'noseNostrilBroke')
        self.setControlValue_new(self.style.getEarScale(), 'earScale')
        self.setControlValue_new(self.style.getEarFlapAngle(), 'earFlap')
        self.setControlValue_new(self.style.getEarPosition(), 'earPosition')
        self.postProcess_setHeadControlShapeValues()


    def setControlValue_new(self, r, name):
        ctl = self.controlShapes[name]
        zeroindex = ctl[0]
        sliders = zeroindex
        if r < 0.0:
            if len(ctl) > 1:
                sliders = ctl[1]


        for i in range(0, len(sliders)):
            zeroindex[i][5] = sliders[i][4] * r



    def postProcess_setHeadControlShapeValues(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixIHelper = FemaleHeadInitHelper
        else:
            cjs = MaleHeadShapeControlJoints
            matrixF = MaleHeadShapeControlJointMatrix
            matrixIHelper = MaleHeadInitHelper
        for jointName in cjs:
            transList = list(matrixIHelper[jointName])
            for sliderName in matrixF[jointName]:
                for sliderJoint in self.controlShapes[sliderName][0]:
                    if sliderJoint[0] == jointName:
                        transList[sliderJoint[1]] += sliderJoint[5]
                        continue


            self.joints[jointName].applyFreezeMatrix(Vec3(*transList[0:3]), Vec3(*transList[3:6]), Vec3(*transList[6:9]))



    def quickGetJointTransform(self, jointName):
        return self.joints[jointName][0].getDefaultValue()


    def storeJoints(self):
        if self.style.gender == 'm':
            bJoints = MaleBodyShapeControlJoints
            hJoints = MaleHeadShapeControlJoints
        else:
            bJoints = FemaleBodyShapeControlJoints
            hJoints = FemaleHeadShapeControlJoints
        for name in bJoints + hJoints + ('def_head01', 'def_extra_jt', 'def_scale_jt'):
            joint = self.getJoints(jointName = name)
            self.joints[name] = joint[0]
            ts = TransformState.makeMat(joint[0].getDefaultValue())
            self.jointTrans[name] = (Vec3(ts.getPos()), Vec3(ts.getHpr()), Vec3(ts.getScale()))



    def setupAnimDicts(cls):
        for t in BodyDefs.maleFrames:
            cls.storeAnimDict('models/char/mp', 'm', t)

        for t in BodyDefs.femaleFrames:
            cls.storeAnimDict('models/char/fp', 'f', t)


    setupAnimDicts = classmethod(setupAnimDicts)

    def storeAnimDict(cls, prefix, gender, type):
        qualifier = gender + type
        animList = AnimListDict[type]
        cls.prebuiltAnimData[qualifier] = { }
        for anim in animList:
            animSuffix = ''
            for i in range(0, len(CustomAnimDict[qualifier])):
                if anim[0] == CustomAnimDict[qualifier][i]:
                    animSuffix = '_' + gender + NewModelDict.get(type)
                    break
                    continue

            cls.prebuiltAnimData[qualifier][anim[0]] = prefix + '_' + anim[1] + animSuffix

        cls.prebuiltAnimData[qualifier].pop('intro')

    storeAnimDict = classmethod(storeAnimDict)
示例#15
0
class DistributedEagleGame(DistributedMinigame):
    notify = directNotify.newCategory('DistributedEagleGame')
    Round2MusicSpeed = {1: 1.0,
     2: 1.15,
     3: 1.35}

    def __init__(self, cr):
        DistributedMinigame.__init__(self, cr)
        self.platformPositions = {0: (-5, 0.5, -0.5),
         1: (-15, 0.5, -0.5),
         2: (5, 0.5, -0.5),
         3: (15, 0.5, -0.5)}
        self.fsm.addState(State('roundCountdown', self.enterRoundCountdown, self.exitRoundCountdown, ['play']))
        self.fsm.addState(State('roundOver', self.enterRoundOver, self.exitRoundOver, ['finalScores', 'roundCountdown']))
        self.fsm.addState(State('finalScores', self.enterFinalScores, self.exitFinalScores, ['gameOver']))
        self.fsm.getStateNamed('waitForOthers').addTransition('roundCountdown')
        self.fsm.getStateNamed('play').addTransition('roundOver')
        self.fsm.getStateNamed('gameOver').addTransition('finalScores')
        self.cannonFSM = ClassicFSM('Cannon', [State('off', self.enterOff, self.exitOff), State('control', self.enterControlCannon, self.exitControlCannon), State('fly', self.enterFly, self.exitFly)], 'off', 'off')
        self.cannonFSM.enterInitialState()
        self.hitEagleSfx = None
        self.toonOof = None
        self.cannonMoveSfx = None
        self.fallSfx = None
        self.bgColor = (0.05, 0.05, 0.05)
        self.cannonId = None
        self.cannonBarrel = '**/cannon'
        self.fog = None
        self.platforms = []
        self.round = 0
        self.world = None
        self.worldModelPath = 'phase_5/models/cogdominium/tt_m_ara_cfg_quadrant2.bam'
        self.nodesToStash = ['lights',
         'streamers',
         'tt_m_ara_cfg_girders2b:Rwall_col',
         'tt_m_ara_cfg_girders2b:Lwall_col']
        self.triggers = ['tt_m_ara_cfg_clump2:col_clump2',
         'tt_m_ara_cfg_clump4:col_clump4',
         'tt_m_ara_cfg_clump5:col_clump5',
         'tt_m_ara_cfg_clump6:col_clump6',
         'tt_m_ara_cfg_clump7:col_clump7',
         'tt_m_ara_cfg_base:ceiling_collision']
        return

    def allRoundsEnded(self):
        self.fsm.request('finalScores')

    def roundOver(self):
        if self.cannonId == None:
            self.__handleMissedEagle()
        self.fsm.request('roundOver')
        return

    def enterControlCannon(self):
        self.__setupCamera(1)
        self.cannon = self.cr.doId2do.get(self.cannonId)
        array = []
        array.append(inputState.watchWithModifiers('cannonUp', 'arrow_up', inputSource=inputState.ArrowKeys))
        array.append(inputState.watchWithModifiers('cannonDown', 'arrow_down', inputSource=inputState.ArrowKeys))
        array.append(inputState.watchWithModifiers('cannonLeft', 'arrow_left', inputSource=inputState.ArrowKeys))
        array.append(inputState.watchWithModifiers('cannonRight', 'arrow_right', inputSource=inputState.ArrowKeys))
        self.cist = array
        taskMgr.add(self.__handleCannonControls, 'DEagleGame-handleCannonControls')
        taskMgr.add(self.__broadcastCannonAndLTTask, 'DEagleGame-broadcastCannonAndLT')
        self.acceptOnce('control', self.controlKeyPressed)

    def broadcastLTPos(self):
        lt = base.localAvatar
        lt.d_setPosHpr(lt.getX(render), lt.getY(render), lt.getZ(render), lt.getH(render), lt.getP(render), lt.getR(render))

    def __broadcastCannonAndLTTask(self, task):
        self.cannon.d_setBarrelOrientation(self.cannon.find(self.cannonBarrel).getH(), self.cannon.find(self.cannonBarrel).getP())
        self.broadcastLTPos()
        task.delayTime = 0.5
        return task.again

    def __handleCannonControls(self, task):
        up = inputState.isSet('cannonUp')
        down = inputState.isSet('cannonDown')
        left = inputState.isSet('cannonLeft')
        right = inputState.isSet('cannonRight')
        dt = globalClock.getDt()
        upAmount = 30 * dt
        downAmount = 45 * dt
        leftAmount = 45 * dt
        rightAmount = 45 * dt
        if up:
            self.cannon.find(self.cannonBarrel).setP(self.cannon.find(self.cannonBarrel).getP() + upAmount)
        elif down:
            self.cannon.find(self.cannonBarrel).setP(self.cannon.find(self.cannonBarrel).getP() - downAmount)
        if left:
            self.cannon.find(self.cannonBarrel).setH(self.cannon.find(self.cannonBarrel).getH() + leftAmount)
        elif right:
            self.cannon.find(self.cannonBarrel).setH(self.cannon.find(self.cannonBarrel).getH() - rightAmount)
        if up or down or left or right:
            if self.cannonMoveSfx.status() == self.cannonMoveSfx.READY:
                base.playSfx(self.cannonMoveSfx)
        elif self.cannonMoveSfx.status() == self.cannonMoveSfx.PLAYING:
            self.cannonMoveSfx.stop()
        return task.cont

    def exitControlCannon(self):
        self.ignore('control')
        taskMgr.remove('DEagleGame-handleCannonControls')
        taskMgr.remove('DEagleGame-broadcastCannonAndLT')
        for token in self.cist:
            token.release()

        del self.cist
        del self.cannon

    def controlKeyPressed(self):
        self.cannon.d_shoot()
        self.cannon.shoot()
        self.cannonFSM.request('fly')

    def __handleEagleHit(self, eagleId):
        self.toonOof.play()
        self.hitEagleSfx.play()
        self.sendUpdate('hitEagle', [eagleId])

    def enterFly(self):
        self.acceptOnce(EGG.EAGLE_HIT_EVENT, self.__handleEagleHit)
        self.__setupCamera()
        cannon = self.cr.doId2do.get(self.cannonId)
        base.localAvatar.b_lookAtObject(0, 0, 0, blink=0)
        base.localAvatar.b_setAnimState('swim')
        dummyNode = NodePath('dummyNode')
        dummyNode.reparentTo(base.localAvatar)
        dummyNode.setPos(0, 160, -90)
        base.localAvatar.setPos(base.localAvatar.getPos(render))
        base.localAvatar.setHpr(cannon.find(self.cannonBarrel).getHpr(render))
        base.localAvatar.reparentTo(render)
        self.flyProjectile = FlightProjectileInterval(base.localAvatar, startPos=cannon.find(self.cannonBarrel).getPos(render) + (0, 5.0, 0), endPos=dummyNode.getPos(render), duration=5.0, name='DEagleGame-localAvatarFly', gravityMult=0.25)
        self.flyProjectile.setDoneEvent(self.flyProjectile.getName())
        self.acceptOnce(self.flyProjectile.getDoneEvent(), self.__handleMissedEagle)
        self.flyProjectile.start()
        dummyNode.removeNode()
        del dummyNode
        self.cannonId = None
        del cannon
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()
        return

    def __handleMissedEagle(self):
        base.playSfx(self.fallSfx)
        self.sendUpdate('missedEagle', [])

    def exitFly(self):
        self.ignore(EGG.EAGLE_HIT_EVENT)
        self.ignore(self.flyProjectile.getDoneEvent())
        self.flyProjectile.pause()
        del self.flyProjectile

    def __setupCamera(self, inCannon = 0):
        if inCannon:
            cannon = self.cr.doId2do.get(self.cannonId)
            camera.reparentTo(cannon)
        else:
            camera.reparentTo(base.localAvatar)
        camera.setPos(0.0, -14.75, 6.33)
        camera.setP(356.82)

    def enterPlay(self):
        DistributedMinigame.enterPlay(self)
        self.music.setPlayRate(self.Round2MusicSpeed[self.getRound()])
        self.createTimer()
        if self.cannonId != None:
            self.cannonFSM.request('control')
        return

    def exitPlay(self):
        self.cannonFSM.request('off')
        self.deleteTimer()
        DistributedMinigame.exitPlay(self)

    def enterCannon(self, cannonId):
        self.cannonId = cannonId
        self.cannon = self.cr.doId2do.get(cannonId)
        base.localAvatar.stopPosHprBroadcast()
        base.localAvatar.d_clearSmoothing()
        self.broadcastLTPos()
        base.localAvatar.reparentTo(self.cannon.find(self.cannonBarrel))
        base.localAvatar.setPosHpr(0, 3.5, 0, 90, -90, 90)
        base.localAvatar.b_setAnimState('neutral')
        base.localAvatar.b_lookAtObject(0, 90, 0, blink=0)
        base.localAvatar.animFSM.request('off')
        self.broadcastLTPos()
        if self.fsm.getCurrentState().getName() == 'play':
            self.cannonFSM.request('control')
        else:
            self.__setupCamera(1)

    def startRound(self, roundNum):
        self.round = roundNum
        self.fsm.request('roundCountdown', [roundNum])

    def getRound(self):
        return self.round

    def enterRoundCountdown(self, roundNum):
        self.text = getGameText()
        self.track = Sequence(Func(self.text.setText, 'Round {0}'.format(roundNum)), getRoundIval(self.text), Func(self.text.setText, '3'), getCountdownIval(self.text), Func(self.text.setText, '2'), getCountdownIval(self.text), Func(self.text.setText, '1'), getCountdownIval(self.text), Func(self.fsm.request, 'play'))
        self.track.start()

    def exitRoundCountdown(self):
        self.track.pause()
        del self.track
        self.text.destroy()
        del self.text

    def enterRoundOver(self):
        self.text = getGameText()
        self.track = Sequence(Func(self.text.setText, "Time's Up!"), getRoundIval(self.text), Func(base.transitions.fadeOut, 1.0), Wait(2.0), Func(base.transitions.fadeIn, 1.0))
        self.track.start()

    def exitRoundOver(self):
        self.track.pause()
        del self.track
        self.text.destroy()
        del self.text

    def allPlayersReady(self):
        self.waitLbl.hide()

    def load(self):
        self.hitEagleSfx = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.mp3')
        self.hitObstacleSfx = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_tower.mp3')
        self.toonOof = base.loadSfx('phase_5/audio/sfx/tt_s_ara_cfg_toonHit.mp3')
        self.cannonMoveSfx = base.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.mp3')
        self.cannonMoveSfx.setLoop(True)
        self.fallSfx = base.loadSfx('phase_4/audio/sfx/MG_sfx_vine_game_fall.mp3')
        self.setMinigameMusic('phase_9/audio/bgm/CHQ_FACT_bg.mid')
        self.setDescription('Shoot as many flying Legal Eagles as you can using your cannon. Use the arrow keys to aim your cannon and press the control key to fire.')
        self.setWinnerPrize(60)
        self.setLoserPrize(20)
        base.setBackgroundColor(*self.bgColor)
        self.world = loader.loadModel(self.worldModelPath)
        for nodeName in self.nodesToStash:
            node = self.world.find('**/' + nodeName)
            node.removeNode()

        self.world.find('**/tt_m_ara_cfg_clump7:clump7').setY(30.0)
        self.world.find('**/tt_m_ara_cfg_eagleNest:eagleNest_mesh').setY(30.0)
        self.world.setColorScale(0.75, 0.75, 0.75, 1.0)
        self.world.reparentTo(base.render)
        self.world.setZ(-5.0)
        for i in range(len(self.platformPositions.keys())):
            platform = loader.loadModel('phase_9/models/cogHQ/platform1.bam')
            platform.find('**/platformcollision').removeNode()
            platform.reparentTo(render)
            platform.setPos(*self.platformPositions[i])
            self.platforms.append(platform)

        for triggerName in self.triggers:
            trigger = self.world.find('**/' + triggerName)
            trigger.setCollideMask(CIGlobals.WallBitmask)
            self.accept('enter' + triggerName, self.__handleHitWall)

        self.fog = Fog('DEagleGame-sceneFog')
        self.fog.setColor(*self.bgColor)
        self.fog.setExpDensity(0.01)
        render.setFog(self.fog)
        DistributedMinigame.load(self)

    def __handleHitWall(self, entry):
        self.toonOof.play()
        self.hitObstacleSfx.play()
        self.sendUpdate('missedEagle')

    def playMinigameMusic(self):
        DistributedMinigame.playMinigameMusic(self)
        self.music.setVolume(0.3)

    def announceGenerate(self):
        DistributedMinigame.announceGenerate(self)
        base.localAvatar.disableChatInput()
        self.load()

    def disable(self):
        for triggerName in self.triggers:
            self.ignore('enter' + triggerName)

        base.localAvatar.createChatInput()
        camera.reparentTo(render)
        camera.setPosHpr(0, 0, 0, 0, 0, 0)
        render.clearFog()
        self.triggers = None
        self.toonOof = None
        self.hitEagleSfx = None
        self.hitObstacleSfx = None
        self.cannonMoveSfx = None
        self.fallSfx = None
        if self.world:
            self.world.removeNode()
            self.world = None
        self.worldModelPath = None
        self.nodesToStash = None
        self.fog = None
        self.round = None
        for platform in self.platforms:
            platform.removeNode()

        self.platforms = None
        self.cannonId = None
        self.cannonBarrel = None
        self.platformPositions = None
        base.setBackgroundColor(CIGlobals.DefaultBackgroundColor)
        self.bgColor = None
        DistributedMinigame.disable(self)
        return
示例#16
0
class DistributedRaceGame(DistributedMinigame.DistributedMinigame):

    def __init__(self, cr):
        try:
            self.DistributedRaceGame_initialized
            return
        except:
            self.DistributedRaceGame_initialized = 1

        DistributedMinigame.DistributedMinigame.__init__(self, cr)
        self.movement = RaceGameMovement.RaceGameMovement(base.localAvatar)
        self.skyUtil = SkyUtil()
        self.raceFSM = ClassicFSM('DistributedRaceGame', [State('race', self.enterRace, self.exitRace), State('raceTransition', self.enterRaceTransition, self.exitRaceTransition), State('off', self.enterRaceOff, self.exitRaceOff)], 'off', 'off')
        self.raceFSM.enterInitialState()
        self.cr = cr
        self.track = None
        self.sky = None
        self.countSfx = base.loadSfx('phase_5/audio/sfx/firehydrant_popup.mp3')
        self.goSfx = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.mp3')
        self.game = CIGlobals.RaceGame
        self.trackPath = 'phase_4/models/minigames/sprint_track.egg'
        self.skyPath = 'phase_3.5/models/props/TT_sky.bam'
        self.lanePos = [(-22.0, -205.0, 0.0),
         (-11.66, -205.0, 0.0),
         (0.0, -205.0, 0.0),
         (-33.66, -205.0, 0.0)]
        self.initialCamPos = {'pos': (41.1, -145.0, 25.88),
         'hpr': (135.0, 345.96, 0.0)}
        self.raceCamPos = (-24.52, -37.22, 25.0)
        self.lane = 0
        return

    def load(self):
        self.deleteWorld()
        self.track = loader.loadModel(self.trackPath)
        self.track.reparentTo(render)
        self.sky = loader.loadModel(self.skyPath)
        self.sky.reparentTo(self.track)
        self.skyUtil.startSky(self.sky)
        self.setMinigameMusic('phase_4/audio/bgm/MG_toontag.mid')
        self.setDescription('Tap the left and right arrow keys repeatedly, in turns, as fast as ' + 'you can to win the race! Every time your power bar hits the top, the boost bar starts' + ' to fill. When the boost bar is full, press CTRL to boost for a few seconds.')
        self.setWinnerPrize(20)
        self.setLoserPrize(5)
        self.d_requestToonLane()
        camera.reparentTo(render)
        camera.setPos(self.initialCamPos['pos'])
        camera.setHpr(self.initialCamPos['hpr'])
        DistributedMinigame.DistributedMinigame.load(self)

    def enterPlay(self):
        DistributedMinigame.DistributedMinigame.enterPlay(self)
        self.raceFSM.request('raceTransition')

    def exitPlay(self):
        DistributedMinigame.DistributedMinigame.exitPlay(self)
        self.raceFSM.request('off')

    def enterRace(self):
        self.startMovement()

    def exitRace(self):
        self.stopMovement()

    def enterRaceOff(self):
        pass

    def exitRaceOff(self):
        pass

    def enterRaceTransition(self):
        self.raceTrans = Sequence(Wait(0.5), Func(self.moveCameraToToon), Wait(4.5), Func(self.moveCameraToTop), Wait(4.5), Func(self.startCountdown))
        self.raceTrans.start()

    def exitRaceTransition(self):
        self.raceTrans.pause()
        del self.raceTrans

    def startMovement(self):
        self.movement.createGui()
        self.movement.fsm.request('run')

    def enterGameOver(self, winner = 0, winnerDoId = 0, allPrize = 0):
        self.raceFSM.request('off')
        DistributedMinigame.DistributedMinigame.enterGameOver(self, winner, winnerDoId, allPrize)

    def stopMovement(self):
        self.movement.cleanup()
        self.movement.deleteGui()

    def startCountdown(self):
        """ Start the countdown to the start of the race. """
        self.countdownLbl = DirectLabel(text='', text_scale=0.3, text_font=CIGlobals.getMickeyFont(), text_fg=(1, 1, 0, 1), pos=(0, 0, 0.5))
        Sequence(Func(self.setCountdownText, '3'), Wait(1.0), Func(self.setCountdownText, '2'), Wait(1.0), Func(self.setCountdownText, '1'), Wait(1.0), Func(self.setCountdownText, 'GO!'), Wait(1.5), Func(self.deleteCountdownLabel)).start()

    def setCountdownText(self, number):
        self.countdownLbl['text'] = number
        if number == 'GO!':
            self.countdownLbl['text_fg'] = (0, 1, 0, 1)
            self.goSfx.play()
            self.raceFSM.request('race')
        else:
            self.countSfx.play()

    def deleteCountdownLabel(self):
        self.countdownLbl.destroy()
        del self.countdownLbl

    def moveCameraToToon(self):
        camPInt = LerpPosInterval(camera, duration=3.0, pos=self.localAv.getPos(render) + (0, 15, 3), startPos=camera.getPos(render), blendType='easeInOut')
        camQInt = camera.quatInterval(3.0, hpr=Vec3(180, 0, 0), blendType='easeInOut')
        camPInt.start()
        camQInt.start()

    def moveCameraToTop(self):
        camera.setPos(camera.getPos(self.localAv))
        camera.reparentTo(self.localAv)
        oldPos = camera.getPos()
        camera.setPos(self.raceCamPos)
        oldHpr = camera.getHpr()
        camera.lookAt(self.localAv.getPart('head'))
        newHpr = camera.getHpr()
        camera.setHpr(oldHpr)
        camera.setPos(oldPos)
        camPInt = LerpPosInterval(camera, duration=3.0, pos=self.raceCamPos, startPos=oldPos, blendType='easeInOut')
        camQInt = camera.quatInterval(3.0, hpr=newHpr, blendType='easeInOut')
        camPInt.start()
        camQInt.start()

    def deleteWorld(self):
        if self.track:
            self.track.removeNode()
            self.track = None
        if self.sky:
            self.skyUtil.stopSky()
            self.sky.removeNode()
            self.sky = None
        return

    def setToonLane(self, lane):
        self.lane = lane
        base.localAvatar.setPos(self.lanePos[lane])
        base.localAvatar.setHpr(0, 0, 0)

    def getToonLane(self):
        return self.lane

    def d_requestToonLane(self):
        self.sendUpdate('requestToonLane', [])

    def announceGenerate(self):
        DistributedMinigame.DistributedMinigame.announceGenerate(self)
        self.load()

    def disable(self):
        DistributedMinigame.DistributedMinigame.disable(self)
        self.deleteWorld()
        self.raceFSM.requestFinalState()
        del self.raceFSM
        self.countSfx = None
        self.goSfx = None
        return
示例#17
0
class ShtickerBook(StateData):

    def __init__(self, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('ShtickerBook', [State('off', self.enterOff, self.exitOff),
         State('optionPage', self.enterOptionPage, self.exitOptionPage, ['districtPage', 'off']),
         State('districtPage', self.enterDistrictPage, self.exitDistrictPage, ['optionPage', 'questPage', 'off']),
         State('questPage', self.enterQuestPage, self.exitQuestPage, ['inventoryPage', 'districtPage', 'off']),
         State('inventoryPage', self.enterInventoryPage, self.exitInventoryPage, ['mapPage', 'questPage', 'off']),
         State('mapPage', self.enterMapPage, self.exitMapPage, ['releaseNotesPage', 'inventoryPage', 'off']),
         State('releaseNotesPage', self.enterReleaseNotesPage, self.exitReleaseNotesPage, ['mapPage', 'off']),
         State('adminPage', self.enterAdminPage, self.exitAdminPage, ['releaseNotesPage', 'off'])], 'off', 'off')
        if base.localAvatar.getAdminToken() > -1:
            self.fsm.getStateNamed('releaseNotesPage').addTransition('adminPage')
        self.fsm.enterInitialState()
        self.entered = 0
        self.parentFSM.getStateNamed('shtickerBook').addChild(self.fsm)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def load(self):
        StateData.load(self)
        self.book_contents = loader.loadModel('phase_3.5/models/gui/stickerbook_gui.bam')
        self.book_texture = self.book_contents.find('**/big_book')
        self.book_open = loader.loadSfx('phase_3.5/audio/sfx/GUI_stickerbook_open.mp3')
        self.book_close = loader.loadSfx('phase_3.5/audio/sfx/GUI_stickerbook_delete.mp3')
        self.book_turn = loader.loadSfx('phase_3.5/audio/sfx/GUI_stickerbook_turn.mp3')

    def unload(self):
        self.book_texture.removeNode()
        del self.book_texture
        self.book_contents.removeNode()
        del self.book_contents
        loader.unloadSfx(self.book_open)
        del self.book_open
        loader.unloadSfx(self.book_close)
        del self.book_close
        loader.unloadSfx(self.book_turn)
        del self.book_turn
        del self.fsm
        del self.parentFSM
        del self.entered
        StateData.unload(self)

    def enter(self):
        if self.entered:
            return
        self.entered = 1
        StateData.enter(self)
        render.hide()
        base.setBackgroundColor(0.05, 0.15, 0.4)
        self.book_img = OnscreenImage(image=self.book_texture, scale=(2, 1, 1.5))
        self.book_open.play()
        if base.localAvatar.getAdminToken() > -1:
            self.fsm.request('adminPage')
        else:
            self.fsm.request('mapPage')

    def exit(self):
        if not self.entered:
            return
        self.entered = 0
        base.setBackgroundColor(CIGlobals.DefaultBackgroundColor)
        render.show()
        self.book_img.destroy()
        del self.book_img
        self.book_close.play()
        self.fsm.request('off')
        StateData.exit(self)

    def enterDistrictPage(self):
        self.createPageButtons('optionPage', 'questPage')
        self.setTitle('Districts')
        currDistrictName = base.cr.myDistrict.getDistrictName()
        if not currDistrictName.isalpha():
            currDistrictName = currDistrictName[:-1]
        self.infoLbl = OnscreenText(text='Each District is a copy of the Cog Invasion world.\n\n\nYou are currently in the "%s" District' % currDistrictName, pos=(0.05, 0.3), align=TextNode.ALeft, wordwrap=12)
        self.populationLbl = OnscreenText(text='Population: %d' % base.cr.myDistrict.getPopulation(), pos=(0.44, -0.3), align=TextNode.ACenter)
        textRolloverColor = Vec4(1, 1, 0, 1)
        textDownColor = Vec4(0.5, 0.9, 1, 1)
        textDisabledColor = Vec4(0.4, 0.8, 0.4, 1)
        self.shardButtons = []
        for shard in base.cr.activeDistricts.values():
            shardName = shard.getDistrictName()
            shardId = shard.doId
            btn = DirectButton(relief=None, text=shardName, text_scale=0.07, text_align=TextNode.ALeft, text1_bg=textDownColor, text2_bg=textRolloverColor, text3_fg=textDisabledColor, textMayChange=0, command=self.__handleShardButton, extraArgs=[shardId], text_pos=(0, 0, 0.0))
            if shardId == base.localAvatar.parentId:
                btn['state'] = DGG.DISABLED
            else:
                btn['state'] = DGG.NORMAL
            self.shardButtons.append(btn)

        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        listXorigin = -0.02
        listFrameSizeX = 0.625
        listZorigin = -0.96
        listFrameSizeZ = 1.04
        arrowButtonScale = 1.3
        itemFrameXorigin = -0.237
        itemFrameZorigin = 0.365
        buttonXstart = itemFrameXorigin + 0.293
        self.districtList = DirectScrolledList(relief=None, pos=(-0.54, 0, 0.08), incButton_image=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), incButton_relief=None, incButton_scale=(arrowButtonScale, arrowButtonScale, -arrowButtonScale), incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999), incButton_image3_color=Vec4(1, 1, 1, 0.2), decButton_image=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), decButton_relief=None, decButton_scale=(arrowButtonScale, arrowButtonScale, arrowButtonScale), decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125), decButton_image3_color=Vec4(1, 1, 1, 0.2), itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin), itemFrame_scale=1.0, itemFrame_relief=DGG.SUNKEN, itemFrame_frameSize=(listXorigin,
         listXorigin + listFrameSizeX,
         listZorigin,
         listZorigin + listFrameSizeZ), itemFrame_frameColor=(0.85, 0.95, 1, 1), itemFrame_borderWidth=(0.01, 0.01), numItemsVisible=15, forceHeight=0.075, items=self.shardButtons)
        base.taskMgr.add(self.__updateDistrictPopTask, 'SB.updateDistrictPopTask')
        return

    def __handleShardButton(self, shardId):
        self.finished('switchShard', shardId)

    def __updateDistrictPopTask(self, task):
        population = base.cr.myDistrict.getPopulation()
        self.populationLbl.setText('Population: %d' % population)
        task.delayTime = 5.0
        return task.again

    def exitDistrictPage(self):
        base.taskMgr.remove('SB.updateDistrictPopTask')
        for btn in self.shardButtons:
            btn.destroy()

        del self.shardButtons
        self.districtList.destroy()
        del self.districtList
        self.infoLbl.destroy()
        del self.infoLbl
        self.populationLbl.destroy()
        del self.populationLbl
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterQuestPage(self):
        self.createPageButtons('districtPage', 'inventoryPage')
        self.setTitle('Quests')
        self.notes = base.localAvatar.questManager.makeQuestNotes()
        for note in self.notes:
            note.show()

        self.infoText = OnscreenText(text='Return completed Quests to an HQ Officer at any Toon HQ building.', pos=(0, -0.6), scale=0.045)

    def exitQuestPage(self):
        self.infoText.destroy()
        del self.infoText
        for note in self.notes:
            note.destroy()

        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterInventoryPage(self):
        self.createPageButtons('questPage', 'mapPage')
        self.setTitle('Gags')
        self.gui = BackpackGUI()
        self.gui.createGUI()

    def exitInventoryPage(self):
        self.gui.deleteGUI()
        del self.gui
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterMapPage(self):
        self.createPageButtons('inventoryPage', 'releaseNotesPage')
        self.setTitle('')
        themap = loader.loadModel('phase_3.5/models/gui/toontown_map.bam')
        self.frame = DirectFrame(parent=aspect2d, relief=None, image=themap, image_scale=(1.8, 1, 1.35), scale=0.97, pos=(0, 0, 0.0775))
        cloudpos = [[(-0.61, 0, 0.18), (0.55, 0.25, 0.37), (180, 0, 0)],
         [(-0.54, 0, 0.34), (0.76, 0.4, 0.55), (180, 0, 0)],
         [(-0.55, 0, -0.09), (0.72, 0.4, 0.55), (0, 0, 0)],
         [(-0.67, 0, -0.51), (0.5, 0.29, 0.38), (180, 0, 0)],
         [(-0.67, 0, 0.51), (0.5, 0.29, 0.38), (0, 0, 0)],
         [(0.67, 0, 0.51), (0.5, 0.29, 0.38), (0, 0, 0)],
         [(0.35, 0, -0.46), (0.63, 0.35, 0.45), (0, 0, 0)],
         [(0.18, 0, -0.45), (0.52, 0.27, 0.32), (0, 0, 0)],
         [(0.67, 0, -0.44), (0.63, 0.35, 0.48), (180, 0, 0)]]
        hoodclouds = [[(0.63, 0, -0.13),
          (0.63, 0.35, 0.4),
          (0, 0, 0),
          CIGlobals.DonaldsDock],
         [(0.51, 0, 0.25),
          (0.57, 0.35, 0.4),
          (0, 0, 0),
          CIGlobals.TheBrrrgh],
         [(0.03, 0, 0.19),
          (0.63, 0.35, 0.4),
          (180, 0, 0),
          CIGlobals.MinniesMelodyland],
         [(-0.08, 0, 0.46),
          (0.54, 0.35, 0.4),
          (0, 0, 0),
          CIGlobals.DonaldsDreamland],
         [(-0.28, 0, -0.49),
          (0.6, 0.35, 0.45),
          (0, 0, 0),
          CIGlobals.DaisyGardens]]
        self.clouds = []
        self.labels = []
        for pos, scale, hpr in cloudpos:
            cloud = loader.loadModel('phase_3.5/models/gui/cloud.bam')
            cloud.reparentTo(self.frame)
            cloud.setPos(pos)
            cloud.setScale(scale)
            cloud.setHpr(hpr)
            self.clouds.append(cloud)

        for pos, scale, hpr, hood in hoodclouds:
            if not base.localAvatar.hasDiscoveredHood(ZoneUtil.getZoneId(hood)):
                cloud = loader.loadModel('phase_3.5/models/gui/cloud.bam')
                cloud.reparentTo(self.frame)
                cloud.setPos(pos)
                cloud.setScale(scale)
                cloud.setHpr(hpr)
                self.clouds.append(cloud)

        labeldata = [[(0, 0, -0.2), CIGlobals.ToontownCentral],
         [(0.65, 0, -0.125), CIGlobals.DonaldsDock],
         [(0.07, 0, 0.18), CIGlobals.MinniesMelodyland],
         [(-0.1, 0, 0.45), CIGlobals.DonaldsDreamland],
         [(0.5, 0, 0.25), CIGlobals.TheBrrrgh],
         [(-0.37, 0, -0.525), CIGlobals.DaisyGardens]]
        for pos, name in labeldata:
            if base.localAvatar.hasDiscoveredHood(ZoneUtil.getZoneId(name)):
                text = name
                if base.localAvatar.hasTeleportAccess(ZoneUtil.getZoneId(name)):
                    text = 'Go To\n' + text
                label = DirectButton(parent=self.frame, relief=None, pos=pos, pad=(0.2, 0.16), text=('', text, text), text_bg=Vec4(1, 1, 1, 0.4), text_scale=0.055, text_wordwrap=8, rolloverSound=None, clickSound=None, pressEffect=0, sortOrder=1, text_font=CIGlobals.getToonFont())
                if base.localAvatar.hasTeleportAccess(ZoneUtil.getZoneId(name)):
                    label['command'] = self.finished
                    label['extraArgs'] = [ZoneUtil.getZoneId(name)]
                label.resetFrameSize()
                self.labels.append(label)

        currHoodName = base.cr.playGame.hood.id
        currLocation = ''
        if base.localAvatar.zoneId == CIGlobals.MinigameAreaId:
            currLocation = ''
        elif base.localAvatar.getMyBattle() != None:
            currLocation = 'CogTropolis'
        elif ZoneUtil.getWhereName(base.localAvatar.zoneId) == 'playground':
            currLocation = 'Playground'
        elif ZoneUtil.getWhereName(base.localAvatar.zoneId) in ('street', 'interior'):
            currLocation = CIGlobals.BranchZone2StreetName[ZoneUtil.getBranchZone(base.localAvatar.zoneId)]
        self.infoLabel = DirectLabel(relief=None, text='You are in: {0}\n{1}'.format(currHoodName, currLocation), scale=0.06, pos=(-0.4, 0, -0.74), parent=self.frame, text_align=TextNode.ACenter)
        if currHoodName in [CIGlobals.MinigameArea, CIGlobals.BattleTTC]:
            currHoodName = base.cr.playGame.lastHood
        self.BTPButton = DirectButton(relief=None, text='Back to Playground', geom=CIGlobals.getDefaultBtnGeom(), text_pos=(0, -0.018), geom_scale=(1.3, 1.11, 1.11), text_scale=0.06, parent=self.frame, text_font=CIGlobals.getToonFont(), pos=(0.25, 0, -0.75), command=self.finished, extraArgs=[ZoneUtil.getZoneId(currHoodName)], scale=0.7)
        if base.localAvatar.zoneId != CIGlobals.MinigameAreaId:
            self.MGAButton = DirectButton(relief=None, text='Minigame Area', geom=CIGlobals.getDefaultBtnGeom(), text_pos=(0, -0.018), geom_scale=(1, 1.11, 1.11), text_scale=0.06, parent=self.frame, text_font=CIGlobals.getToonFont(), pos=(0.625, 0, -0.75), command=self.finished, extraArgs=[CIGlobals.MinigameAreaId], scale=0.7)
        return

    def exitMapPage(self):
        for label in self.labels:
            label.destroy()

        del self.labels
        for cloud in self.clouds:
            cloud.removeNode()

        del self.clouds
        self.frame.destroy()
        del self.frame
        self.infoLabel.destroy()
        del self.infoLabel
        self.BTPButton.destroy()
        del self.BTPButton
        if hasattr(self, 'MGAButton'):
            self.MGAButton.destroy()
            del self.MGAButton
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterZonePage(self):
        self.createPageButtons('inventoryPage', 'releaseNotesPage')
        self.setTitle('Places')
        self.ttc_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.045, text=CIGlobals.ToontownCentral, command=self.finished, extraArgs=[CIGlobals.ToontownCentralId], pos=(-0.45, 0.15, 0.5), text_pos=(0, -0.01))
        self.tbr_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.055, text=CIGlobals.TheBrrrgh, command=self.finished, extraArgs=[CIGlobals.TheBrrrghId], pos=(-0.45, 0.15, 0.38), text_pos=(0, -0.01))
        self.ddl_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.044, text=CIGlobals.DonaldsDreamland, command=self.finished, extraArgs=[CIGlobals.DonaldsDreamlandId], pos=(-0.45, 0.15, 0.26), text_pos=(0, -0.01))
        self.mml_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.0425, text=CIGlobals.MinniesMelodyland, command=self.finished, extraArgs=[CIGlobals.MinniesMelodylandId], pos=(-0.45, 0.35, 0.14), text_pos=(0, -0.01))
        self.dg_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.045, text=CIGlobals.DaisyGardens, command=self.finished, extraArgs=[CIGlobals.DaisyGardensId], pos=(-0.45, 0.35, 0.02), text_pos=(0, -0.01))
        self.dd_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.045, text=CIGlobals.DonaldsDock, command=self.finished, extraArgs=[CIGlobals.DonaldsDockId], pos=(-0.45, 0.35, -0.1), text_pos=(0, -0.01))
        self.minigame_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.055, text=CIGlobals.MinigameArea, command=self.finished, extraArgs=[CIGlobals.MinigameAreaId], pos=(-0.45, 0.35, -0.34), text_pos=(0, -0.01))
        return

    def __updateGamePopulation(self, task):
        population = 0
        for district in base.cr.activeDistricts.values():
            population += district.getPopulation()

        self.populationLbl.setText('Game Population:\n' + str(population))
        recordPopulation = base.cr.myDistrict.getPopRecord()
        self.popRecordLbl.setText('Record Population:\n' + str(recordPopulation))
        task.delayTime = 5.0
        return task.again

    def exitZonePage(self):
        self.dd_btn.destroy()
        del self.dd_btn
        self.ddl_btn.destroy()
        del self.ddl_btn
        self.ttc_btn.destroy()
        del self.ttc_btn
        self.tbr_btn.destroy()
        del self.tbr_btn
        self.minigame_btn.destroy()
        del self.minigame_btn
        self.mml_btn.destroy()
        del self.mml_btn
        self.dg_btn.destroy()
        del self.dg_btn
        self.deletePageButtons(True, True)
        self.clearTitle()

    def createPageButtons(self, back, fwd):
        if back:
            self.btn_prev = DirectButton(geom=(self.book_contents.find('**/arrow_button'), self.book_contents.find('**/arrow_down'), self.book_contents.find('**/arrow_rollover')), relief=None, pos=(-0.838, 0, -0.661), scale=(-0.1, 0.1, 0.1), command=self.pageDone, extraArgs=[back])
        if fwd:
            self.btn_next = DirectButton(geom=(self.book_contents.find('**/arrow_button'), self.book_contents.find('**/arrow_down'), self.book_contents.find('**/arrow_rollover')), relief=None, pos=(0.838, 0, -0.661), scale=(0.1, 0.1, 0.1), command=self.pageDone, extraArgs=[fwd])
        return

    def deletePageButtons(self, back, fwd):
        if back:
            self.btn_prev.destroy()
            del self.btn_prev
        if fwd:
            self.btn_next.destroy()
            del self.btn_next

    def setTitle(self, title):
        self.page_title = OnscreenText(text=title, pos=(0, 0.62, 0), scale=0.12)

    def clearTitle(self):
        self.page_title.destroy()
        del self.page_title

    def enterReleaseNotesPage(self):
        if base.localAvatar.getAdminToken() > -1:
            self.createPageButtons('mapPage', 'adminPage')
        else:
            self.createPageButtons('mapPage', None)
        self.setTitle('Release Notes')
        self.frame = DirectScrolledFrame(canvasSize=(-1, 1, -3.5, 1), frameSize=(-1, 1, -0.6, 0.6))
        self.frame.setPos(0, 0, 0)
        self.frame.setScale(0.8)
        self.release_notes = DirectLabel(text=open('release_notes.txt', 'r').read(), text_align=TextNode.ALeft, pos=(-0.955, 0, 0.93), relief=None, text_fg=(0, 0, 0, 1), text_wordwrap=37.0, text_scale=0.05, parent=self.frame.getCanvas())
        return

    def exitReleaseNotesPage(self):
        self.frame.destroy()
        del self.frame
        self.release_notes.destroy()
        del self.release_notes
        self.clearTitle()
        if base.localAvatar.getAdminToken() > -1:
            self.deletePageButtons(True, True)
        else:
            self.deletePageButtons(True, False)

    def enterAdminPage(self):
        self.adminPageStateData = AdminPage(self, self.fsm)
        self.adminPageStateData.load()
        self.adminPageStateData.enter()

    def exitAdminPage(self):
        self.adminPageStateData.exit()
        self.adminPageStateData.unload()
        del self.adminPageStateData

    def pageDone(self, nextPage):
        self.fsm.request(nextPage)
        self.book_turn.play()

    def enterOptionPage(self):
        self.optionPageStateData = OptionPage(self, self.fsm)
        self.optionPageStateData.load()
        self.optionPageStateData.enter()

    def exitOptionPage(self):
        self.optionPageStateData.exit()
        self.optionPageStateData.unload()
        del self.optionPageStateData

    def prevPage(self, currentPage):
        self.clearCurrentPage()
        if self.currentPage == 2:
            self.optionPage()
        elif self.currentPage == 3:
            self.zonePage()
        elif self.currentPage == 4:
            self.releaseNotesPage()

    def nextPage(self, currentPage):
        self.clearCurrentPage()
        if self.currentPage == 1:
            self.zonePage()
        elif self.currentPage == 2:
            self.releaseNotesPage()
        elif self.currentPage == 3:
            self.adminPage()

    def clearCurrentPage(self):
        self.book_turn.play()
        for m in base.bookpgnode.getChildren():
            m.removeNode()

    def finished(self, zone, shardId = None):
        if base.localAvatar.getHealth() < 1 and type(zone) == type(1):
            return
        else:
            doneStatus = {}
            if zone in [CIGlobals.ToontownCentralId,
             CIGlobals.MinigameAreaId,
             CIGlobals.TheBrrrghId,
             CIGlobals.DonaldsDreamlandId,
             CIGlobals.MinniesMelodylandId,
             CIGlobals.DaisyGardensId,
             CIGlobals.DonaldsDockId]:
                doneStatus['mode'] = 'teleport'
                doneStatus['zoneId'] = zone
                doneStatus['hoodId'] = ZoneUtil.getHoodId(zone)
                doneStatus['where'] = ZoneUtil.getWhereName(zone)
                doneStatus['how'] = 'teleportIn'
                doneStatus['avId'] = base.localAvatar.doId
                doneStatus['shardId'] = None
                doneStatus['loader'] = ZoneUtil.getLoaderName(zone)
            else:
                doneStatus['mode'] = zone
                if zone == 'switchShard':
                    doneStatus['shardId'] = shardId
            self.doneStatus = doneStatus
            messenger.send(self.doneEvent)
            return

    def closeBook(self):
        self.book_close.play()
        base.bookpgnode.removeNode()
        base.booknode.removeNode()
示例#18
0
class SafeZoneLoader(StateData):
    notify = directNotify.newCategory('SafeZoneLoader')

    def __init__(self, hood, parentFSMState, doneEvent):
        StateData.__init__(self, doneEvent)
        self.hood = hood
        self.parentFSMState = parentFSMState
        self.fsm = ClassicFSM('safeZoneLoader', [State('off', self.enterOff, self.exitOff),
         State('playground', self.enterPlayground, self.exitPlayground, ['quietZone']),
         State('toonInterior', self.enterToonInterior, self.exitToonInterior, ['quietZone']),
         State('quietZone', self.enterQuietZone, self.exitQuietZone, ['playground', 'toonInterior'])], 'off', 'off')
        self.placeDoneEvent = 'placeDone'
        self.place = None
        self.playground = None
        self.battleMusic = None
        self.invasionMusic = None
        self.invasionMusicFiles = None
        self.interiorMusic = None
        self.bossBattleMusic = None
        self.music = None
        self.tournamentMusic = None
        self.linkTunnels = []
        return

    def findAndMakeLinkTunnels(self):
        for tunnel in self.geom.findAllMatches('**/*linktunnel*'):
            dnaRootStr = tunnel.getName()
            link = LinkTunnel.SafeZoneLinkTunnel(tunnel, dnaRootStr)
            self.linkTunnels.append(link)

    def load(self):
        StateData.load(self)
        if self.pgMusicFilename:
            self.music = base.loadMusic(self.pgMusicFilename)
        if self.battleMusicFile:
            self.battleMusic = base.loadMusic(self.battleMusicFile)
        if self.invasionMusicFiles:
            self.invasionMusic = None
        if self.bossBattleMusicFile:
            self.bossBattleMusic = base.loadMusic(self.bossBattleMusicFile)
        if self.interiorMusicFilename:
            self.interiorMusic = base.loadMusic(self.interiorMusicFilename)
        if self.tournamentMusicFiles:
            self.tournamentMusic = None
        self.createSafeZone(self.dnaFile)
        self.parentFSMState.addChild(self.fsm)
        width, height, fs, music, sfx, tex_detail, model_detail, aa, af = SettingsManager().getSettings('settings.json')
        if af == 'on':
            self.notify.info('Anisotropic Filtering is on, applying to textures.')
            for nodepath in self.geom.findAllMatches('*'):
                try:
                    for node in nodepath.findAllMatches('**'):
                        try:
                            node.findTexture('*').setAnisotropicDegree(8)
                        except:
                            pass

                except:
                    continue

        return

    def unload(self):
        StateData.unload(self)
        self.parentFSMState.removeChild(self.fsm)
        del self.parentFSMState
        self.geom.removeNode()
        del self.geom
        del self.fsm
        del self.hood
        del self.playground
        del self.music
        del self.interiorMusic
        del self.battleMusic
        del self.bossBattleMusic
        del self.tournamentMusic
        self.ignoreAll()
        ModelPool.garbageCollect()
        TexturePool.garbageCollect()

    def enter(self, requestStatus):
        StateData.enter(self)
        if base.localAvatar.zoneId < 61000:
            self.findAndMakeLinkTunnels()
        self.fsm.enterInitialState()
        messenger.send('enterSafeZone')
        self.setState(requestStatus['where'], requestStatus)
        partyGate = self.geom.find('**/prop_party_gate_DNARoot')
        if not partyGate.isEmpty():
            partyGate.removeNode()
        del partyGate
        petShop = self.geom.find('**/prop_pet_shop_DNARoot')
        if not petShop.isEmpty():
            petShop.removeNode()
        del petShop

    def exit(self):
        StateData.exit(self)
        messenger.send('exitSafeZone')
        for link in self.linkTunnels:
            link.cleanup()

        self.linkTunnels = []

    def setState(self, stateName, requestStatus):
        self.fsm.request(stateName, [requestStatus])

    def createSafeZone(self, dnaFile):
        if self.szStorageDNAFile:
            loader.loadDNAFile(self.hood.dnaStore, self.szStorageDNAFile)
        node = loader.loadDNAFile(self.hood.dnaStore, dnaFile)
        if node.getNumParents() == 1:
            self.geom = NodePath(node.getParent(0))
            self.geom.reparentTo(hidden)
        else:
            self.geom = hidden.attachNewNode(node)
        self.makeDictionaries(self.hood.dnaStore)
        if self.__class__.__name__ not in ('TTSafeZoneLoader',):
            self.geom.flattenMedium()
        gsg = base.win.getGsg()
        if gsg:
            self.geom.prepareScene(gsg)

    def makeDictionaries(self, dnaStore):
        self.nodeList = []
        for i in xrange(dnaStore.getNumDNAVisGroups()):
            groupFullName = dnaStore.getDNAVisGroupName(i)
            groupName = base.cr.hoodMgr.extractGroupName(groupFullName)
            groupNode = self.geom.find('**/' + groupFullName)
            if groupNode.isEmpty():
                self.notify.error('Could not find visgroup')
            if self.__class__.__name__ not in ('TTSafeZoneLoader',):
                groupNode.flattenMedium()
            self.nodeList.append(groupNode)

        self.hood.dnaStore.resetPlaceNodes()
        self.hood.dnaStore.resetDNAGroups()
        self.hood.dnaStore.resetDNAVisGroups()
        self.hood.dnaStore.resetDNAVisGroupsAI()

    def enterPlayground(self, requestStatus):
        try:
            self.hood.stopSuitEffect()
        except:
            pass

        self.acceptOnce(self.placeDoneEvent, self.handlePlaygroundDone)
        self.place = self.playground(self, self.fsm, self.placeDoneEvent)
        self.place.load()

    def exitPlayground(self):
        self.ignore(self.placeDoneEvent)
        self.place.exit()
        self.place.unload()
        self.place = None
        base.cr.playGame.setPlace(self.place)
        return

    def handlePlaygroundDone(self):
        status = self.place.doneStatus
        if self.hood.isSameHood(status) and status['loader'] == 'safeZoneLoader' and status['where'] not in ('minigame',):
            self.fsm.request('quietZone', [status])
        else:
            self.doneStatus = status
            messenger.send(self.doneEvent)

    def enterToonInterior(self, requestStatus):
        self.acceptOnce(self.placeDoneEvent, self.handleToonInteriorDone)
        self.place = ToonInterior.ToonInterior(self, self.fsm, self.placeDoneEvent)
        self.place.load()

    def enterThePlace(self, requestStatus):
        base.cr.playGame.setPlace(self.place)
        self.place.enter(requestStatus)

    def exitToonInterior(self):
        self.ignore(self.placeDoneEvent)
        self.place.exit()
        self.place.unload()
        self.place = None
        base.cr.playGame.setPlace(self.place)
        return

    def handleToonInteriorDone(self):
        status = self.place.doneStatus
        if status['loader'] == 'safeZoneLoader' and self.hood.isSameHood(status) and status['shardId'] == None or status['how'] == 'doorOut':
            self.fsm.request('quietZone', [status])
        else:
            self.doneStatus = status
            messenger.send(self.doneEvent)
        return

    def enterQuietZone(self, requestStatus):
        self.fsm.request(requestStatus['where'], [requestStatus], exitCurrent=0)
        self.quietZoneDoneEvent = uniqueName('quietZoneDone')
        self.acceptOnce(self.quietZoneDoneEvent, self.handleQuietZoneDone)
        self.quietZoneStateData = QuietZoneState(self.quietZoneDoneEvent)
        self.quietZoneStateData.load()
        self.quietZoneStateData.enter(requestStatus)

    def exitQuietZone(self):
        self.ignore(self.quietZoneDoneEvent)
        del self.quietZoneDoneEvent
        self.quietZoneStateData.exit()
        self.quietZoneStateData.unload()
        self.quietZoneStateData = None
        return

    def handleQuietZoneDone(self):
        status = self.quietZoneStateData.getDoneStatus()
        self.exitQuietZone()
        if status['where'] == 'estate' or status['loader'] == 'townLoader':
            self.doneStatus = status
            messenger.send(self.doneEvent)
        else:
            self.enterThePlace(status)

    def enterOff(self):
        pass

    def exitOff(self):
        pass
class Playground(Place.Place):
    notify = directNotify.newCategory("Playground")

    def __init__(self, loader, parentFSM, doneEvent):
        Place.Place.__init__(self, loader, doneEvent)
        self.fsm = ClassicFSM('Playground', [
            State(
                'start', self.enterStart, self.exitStart,
                ['walk', 'teleportIn', 'tunnelOut', 'doorOut', 'trolleyOut']),
            State('teleportIn', self.enterTeleportIn, self.exitTeleportIn,
                  ['walk', 'acknowledgeDeath']),
            State('walk', self.enterWalk, self.exitWalk,
                  ['teleportOut', 'stop', 'shtickerBook', 'died', 'tunnelIn']),
            State('teleportOut', self.enterTeleportOut, self.exitTeleportOut,
                  ['teleportIn', 'stop']),
            State('stop', self.enterStop, self.exitStop,
                  ['walk', 'died', 'station', 'teleportOut', 'doorIn']),
            State('shtickerBook', self.enterShtickerBook,
                  self.exitShtickerBook, ['teleportOut', 'walk']),
            State('tunnelOut', self.enterTunnelOut, self.exitTeleportOut,
                  ['walk']),
            State('final', self.enterFinal, self.exitFinal, ['start']),
            State('died', self.enterDied, self.exitDied, ['final']),
            State('station', self.enterStation, self.exitStation,
                  ['teleportOut', 'walk']),
            State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
            State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
            State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
            State('acknowledgeDeath', self.enterAcknowledgeDeath,
                  self.exitAcknowledgeDeath, ['walk']),
            State('trolleyOut', self.enterTrolleyOut, self.exitTrolleyOut,
                  ['walk', 'stop'])
        ], 'start', 'final')
        self.parentFSM = parentFSM
        return

    def enter(self, requestStatus):
        self.fsm.enterInitialState()
        self.loader.hood.enableOutdoorLighting()

        messenger.send('enterPlayground')

        base.playMusic(self.loader.safeZoneSong)

        self.loader.geom.reparentTo(render)
        base.enablePhysicsNodes(self.loader.geom)
        #self.loader.hood.startSky()

        self.zoneId = requestStatus['zoneId']
        if base.cr.playGame.suitManager:
            base.cr.playGame.suitManager.d_requestSuitInfo()
        how = requestStatus['how']
        self.fsm.request(how, [requestStatus])

        Place.Place.enter(self)

    def exit(self):
        self.ignoreAll()
        messenger.send('exitPlayground')

        self.loader.geom.reparentTo(hidden)
        base.disablePhysicsNodes(self.loader.geom)

        base.stopMusic()

        self.loader.hood.disableOutdoorLighting()

        Place.Place.exit(self)

    def load(self):
        Place.Place.load(self)
        self.parentFSM.getStateNamed('playground').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('playground').removeChild(self.fsm)
        del self.parentFSM
        del self.fsm
        self.ignoreAll()
        Place.Place.unload(self)
        return

    def enterStation(self):
        pass

    def exitStation(self):
        pass

    def enterWalk(self, teleportIn=0, wantMouse=1):
        Place.Place.enterWalk(self, teleportIn, wantMouse)

    def enterTeleportIn(self, requestStatus):
        if base.localAvatar.getHealth() < 1:
            requestStatus['nextState'] = 'acknowledgeDeath'
        else:
            requestStatus['nextState'] = 'walk'

        x, y, z, h, p, r = base.cr.hoodMgr.getPlaygroundCenterFromId(
            self.loader.hood.id)
        dropLocation = self.loader.geom.attachNewNode('dropLocation')
        dropLocation.setPos(x, y, z)
        dropLocation.setHpr(h, p, r)

        base.localAvatar.gotoNode(dropLocation)
        base.localAvatar.setHpr(h, p, r)
        dropLocation.removeNode()

        Place.Place.enterTeleportIn(self, requestStatus)
        return
示例#20
0
class BRWater:
    notify = directNotify.newCategory('BRWater')

    def __init__(self, playground):
        self.playground = playground
        self.fsm = ClassicFSM('BRWater', [State('off', self.enterOff, self.exitOff),
         State('freezeUp', self.enterFreezeUp, self.exitFreezeUp),
         State('coolDown', self.enterCoolDown, self.exitCoolDown),
         State('frozen', self.enterFrozen, self.exitFrozen)], 'off', 'off')
        self.fsm.enterInitialState()
        self.freezeUpSfx = base.loadSfx('phase_8/audio/sfx/freeze_up.mp3')
        self.frozenSfxArray = [base.loadSfx('phase_8/audio/sfx/frozen_1.mp3'), base.loadSfx('phase_8/audio/sfx/frozen_2.mp3'), base.loadSfx('phase_8/audio/sfx/frozen_3.mp3')]
        self.coolSfxArray = [base.loadSfx('phase_8/audio/sfx/cool_down_1.mp3'), base.loadSfx('phase_8/audio/sfx/cool_down_2.mp3')]
        self.freezeUpSfx.setVolume(12)
        for sfx in self.frozenSfxArray:
            sfx.setVolume(12)

        for sfx in self.coolSfxArray:
            sfx.setVolume(12)

    def attachSound(self, sound):
        base.localAvatar.audio3d.attachSoundToObject(sound, base.localAvatar)

    def enterOff(self):
        self.playground.startWaterWatch()

    def exitOff(self):
        self.playground.stopWaterWatch()

    def loadIceCube(self):
        self.iceCube = loader.loadModel('phase_8/models/props/icecube.bam')
        for node in self.iceCube.findAllMatches('**/billboard*'):
            node.removeNode()

        for node in self.iceCube.findAllMatches('**/drop_shadow*'):
            node.removeNode()

        for node in self.iceCube.findAllMatches('**/prop_mailboxcollisions*'):
            node.removeNode()

        self.iceCube.reparentTo(base.localAvatar)
        self.iceCube.setScale(1.2, 1.0, base.localAvatar.getHeight() / 1.7)
        self.iceCube.setTransparency(1)
        self.iceCube.setColorScale(0.76, 0.76, 1.0, 0.0)

    def unloadIceCube(self):
        self.iceCube.removeNode()
        del self.iceCube

    def enterFreezeUp(self):
        length = 1.0
        base.playSfx(self.freezeUpSfx)
        self.fucsIval = Sequence(LerpColorScaleInterval(base.localAvatar.getGeomNode(), duration=length, colorScale=VBase4(0.5, 0.5, 1.0, 1.0), startColorScale=base.localAvatar.getGeomNode().getColorScale(), blendType='easeOut'), Func(self.fsm.request, 'frozen'))
        self.fucsIval.start()
        self.playground.startWaterWatch(0)

    def exitFreezeUp(self):
        self.fucsIval.pause()
        del self.fucsIval
        self.playground.stopWaterWatch()

    def enterFrozen(self):
        self.loadIceCube()
        base.cr.playGame.getPlace().fsm.request('stop', [0])
        base.localAvatar.stop()
        base.playSfx(choice(self.frozenSfxArray))
        self.iccsIval = LerpColorScaleInterval(self.iceCube, duration=0.5, colorScale=VBase4(0.76, 0.76, 1.0, 1.0), startColorScale=self.iceCube.getColorScale(), blendType='easeInOut')
        self.iccsIval.start()
        props = WindowProperties()
        props.setCursorHidden(True)
        base.win.requestProperties(props)
        self.frame = DirectFrame(pos=(0, 0, 0.7))
        self.powerBar = DirectWaitBar(frameColor=(1, 1, 1, 1), range=100, value=0, scale=(0.4, 0.5, 0.25), parent=self.frame, barColor=(0.55, 0.7, 1.0, 1.0))
        self.label = OnscreenText(text='SHAKE MOUSE', shadow=(0, 0, 0, 1), fg=(0.55, 0.7, 1.0, 1.0), pos=(0, -0.1, 0), parent=self.frame)
        taskMgr.add(self.__watchMouseMovement, 'BRWater-watchMouseMovement')
        taskMgr.add(self.__lowerPowerBar, 'BRWater-lowerPowerBar')
        mw = base.mouseWatcherNode
        if mw.hasMouse():
            self.lastMouseX = mw.getMouseX()

    def __lowerPowerBar(self, task):
        if self.powerBar['value'] <= 0:
            self.powerBar.update(0)
        decrement = 1
        self.powerBar.update(self.powerBar['value'] - decrement)
        task.delayTime = 0.1
        return task.again

    def __watchMouseMovement(self, task):
        if self.powerBar['value'] >= self.powerBar['range']:
            self.fsm.request('coolDown', [1])
            return task.done
        mw = base.mouseWatcherNode
        if mw.hasMouse():
            if not self.lastMouseX or self.lastMouseX != mw.getMouseX():
                value = 3 * self.lastMouseX - mw.getMouseX()
                self.lastMouseX = mw.getMouseX()
                self.powerBar.update(self.powerBar['value'] + abs(value))
        return task.cont

    def exitFrozen(self):
        props = WindowProperties()
        props.setCursorHidden(False)
        base.win.requestProperties(props)
        self.iccsIval.pause()
        del self.iccsIval
        self.unloadIceCube()
        taskMgr.remove('BRWater-lowerPowerBar')
        taskMgr.remove('BRWater-watchMouseMovement')
        self.label.destroy()
        del self.label
        self.powerBar.destroy()
        del self.powerBar
        self.frame.destroy()
        del self.frame
        del self.lastMouseX
        base.cr.playGame.getPlace().fsm.request('walk')
        base.localAvatar.b_setAnimState('neutral')

    def enterCoolDown(self, fromFrozen = 0):
        if fromFrozen:
            self.loadIceCube()
            self.iceCube.setColorScale(0.76, 0.76, 1.0, 1.0)
            self.iccdIval = LerpColorScaleInterval(self.iceCube, duration=0.5, colorScale=VBase4(0.76, 0.76, 1.0, 0.0), startColorScale=self.iceCube.getColorScale(), blendType='easeInOut')
            self.iccdIval.start()
        length = 1.0
        base.playSfx(choice(self.coolSfxArray))
        self.cdcsIval = Sequence(LerpColorScaleInterval(base.localAvatar.getGeomNode(), duration=length, colorScale=VBase4(1.0, 1.0, 1.0, 1.0), startColorScale=base.localAvatar.getGeomNode().getColorScale(), blendType='easeOut'), Func(self.fsm.request, 'off'))
        self.cdcsIval.start()

    def exitCoolDown(self):
        if hasattr(self, 'iccdIval'):
            self.iccdIval.pause()
            del self.iccdIval
            self.unloadIceCube()
        self.cdcsIval.pause()
        del self.cdcsIval

    def cleanup(self):
        self.fsm.requestFinalState()
        self.playground.stopWaterWatch()
        del self.fsm
        del self.freezeUpSfx
        del self.frozenSfxArray
        del self.coolSfxArray
        del self.playground
示例#21
0
class BaseLocalControls(DirectObject):
    SlideFactor = 0.75
    DiagonalFactor = math.sqrt(2.0) / 2.0
    CrouchSpeedFactor = 0.3
    FootstepIval = 0.6
    FootstepVolumeMod = 1.0

    BattleNormalSpeed = 320 / 16.0
    BattleRunSpeed = 416 / 16.0
    BattleWalkSpeed = 190 / 16.0

    SwimGravityMod = 0.5

    # Mode
    MThirdPerson = 0
    MFirstPerson = 1

    # Scheme
    SDefault = 0
    SSwim = 1

    def __init__(self):
        DirectObject.__init__(self)

        self.fsm = ClassicFSM('ControlMode', [
            State('off', self.enterOff, self.exitOff),
            State('firstperson', self.enterFirstPerson, self.exitFirstPerson),
            State('thirdperson', self.enterThirdPerson, self.exitThirdPerson)
        ], 'off', 'off')
        self.fsm.enterInitialState()

        self.controller = None
        self.staticFriction = 0.8
        self.dynamicFriction = 0.3
        self.speeds = Vec3(0)
        self.lastSpeeds = Vec3(0)

        self.idealFwd = 0
        self.idealRev = 0
        self.idealRot = 0
        self.idealJump = 0

        self.fwdSpeed = CIGlobals.ToonForwardSpeed
        self.revSpeed = CIGlobals.ToonReverseSpeed
        self.turnSpeed = CIGlobals.ToonRotateSpeed

        self.controlsEnabled = False
        self.airborne = False
        self.crouching = False

        self.defaultSounds = [
            base.loadSfx("phase_14/audio/sfx/footsteps/default1.ogg"),
            base.loadSfx("phase_14/audio/sfx/footsteps/default2.ogg")
        ]
        self.defaultOverride = None  #"concrete"

        self.standingUp = True
        self.footstepIval = self.FootstepIval
        self.lastFootstepTime = 0
        self.currentSurface = None
        self.footstepSounds = {}
        self.currFootstepSound = None
        self.lastFoot = True
        self.setCurrentSurface('default')

        self.currentObjectUsing = None
        self.lastUseObjectTime = 0.0

        self.mode = self.MThirdPerson
        self.scheme = self.SDefault
        self.fpsCam = FPSCamera()

        self.movementTokens = []

        self.active = False

        self.charUpdateTaskName = "controllerUpdateTask-" + str(id(self))

        self.useInvalidSound = base.loadSfx("phase_4/audio/sfx/ring_miss.ogg")

        # Debug stuff
        self.printFootstepInfo = False
        #base.localAvatar.accept('i', self.toggleDiagnostic)

    def getHighestSpeed(self):
        return self.BattleRunSpeed

    def cleanup(self):
        if self.fpsCam:
            self.fpsCam.cleanup()
        self.fpsCam = None

    def toggleDiagnostic(self):
        self.printFootstepInfo = not self.printFootstepInfo
        print("Toggled footstep info")

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def setControlScheme(self, scheme):
        self.scheme = scheme
        if scheme == self.SSwim:
            self.controller.setMovementState(MOVEMENTSTATE_SWIMMING)
            self.controller.setGravity(base.physicsWorld.getGravity()[2] *
                                       LocalControls.SwimGravityMod)
            self.staticFriction = 0.15
            self.dynamicFriction = 0.08
            self.allowCrouch = False
            self.allowJump = False
        else:
            if self.controller.getMovementState() == MOVEMENTSTATE_SWIMMING:
                self.controller.setMovementState(MOVEMENTSTATE_GROUND)
            self.controller.setGravity(base.physicsWorld.getGravity()[2])
            self.staticFriction = 0.8
            self.dynamicFriction = 0.3
            self.allowCrouch = True
            self.allowJump = True

    def attachCamera(self):
        self.fpsCam.attachCamera()

    def enterFirstPerson(self):
        self.fpsCam.setup()

        if self.controlsEnabled:
            self.fp_enable()

        self.revSpeed = CIGlobals.ToonForwardSpeed

    def fp_enable(self, wantMouse=0):
        if wantMouse:
            self.fpsCam.enableMouseMovement()
        else:
            # At least allow them to engage the mouse.
            self.fpsCam.acceptEngageKeys()

        base.localAvatar.resetHeadHpr(True)

        if base.localAvatar.hasEquippedAttack():
            base.localAvatar.showCrosshair()
            if base.localAvatar.isFirstPerson():
                self.fpsCam.getViewModel().show()
            base.localAvatar.b_setLookMode(base.localAvatar.LMCage)
        else:
            base.localAvatar.b_setLookMode(base.localAvatar.LMHead)

        base.camLens.setMinFov(70.0 / (4. / 3.))

        base.localAvatar.enableGagKeys()

    def exitFirstPerson(self):
        self.fpsCam.disableMouseMovement()
        base.localAvatar.hideCrosshair()

    def enterThirdPerson(self):
        #base.localAvatar.b_setLookMode(base.localAvatar.LMOff)
        #base.localAvatar.getGeomNode().show()
        #self.tp_attachCamera()
        #base.localAvatar.hideCrosshair()
        #self.fpsCam.getViewModel().hide()
        #self.revSpeed = CIGlobals.ToonReverseSpeed\

        self.fpsCam.setup()

        if self.controlsEnabled:
            self.fp_enable()
            base.localAvatar.startSmartCamera()

        self.revSpeed = CIGlobals.ToonForwardSpeed

    def tp_attachCamera(self):
        camera.reparentTo(base.localAvatar)
        base.localAvatar.smartCamera.setCameraPositionByIndex(
            base.localAvatar.smartCamera.cameraIndex)
        #camera.setPos(base.localAvatar.smartCamera.getIdealCameraPos())
        #camera.lookAt(base.localAvatar.smartCamera.getLookAtPoint())
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4. / 3.))

    def exitThirdPerson(self):
        base.localAvatar.stopSmartCamera()

    def setMode(self, mode):
        self.mode = mode

        if mode == self.MFirstPerson:
            self.fsm.request('firstperson')
        elif mode == self.MThirdPerson:
            self.fsm.request('thirdperson')
        else:
            self.notify.warning("unknown control mode {0}".format(mode))
            return

        self.watchMovementInputs()

    def switchMode(self):
        if self.mode == self.MFirstPerson:
            self.setMode(self.MThirdPerson)
        elif self.mode == self.MThirdPerson:
            self.setMode(self.MFirstPerson)

    def getCollisionsActive(self):
        return self.active

    def setWalkSpeed(self, fwd, jump, rev, rot):
        self.idealFwd = fwd
        self.idealJump = jump
        self.idealRev = rev
        self.idealRot = rot

        self.fwdSpeed = fwd
        self.revSpeed = rev
        self.turnSpeed = rot

    def setCollisionsActive(self, flag, andPlaceOnGround=0):
        if not flag:

            # There may be times when we need to return the avatar to the
            # ground so they don't break the laws of physics. Such as
            # when we disable collisions when moving a player through
            # a tunnel.
            if andPlaceOnGround:
                self.exitControlsWhenGrounded = True
            else:
                self.stopControllerUpdate()
        else:
            self.startControllerUpdate()

    def getSpeeds(self):
        return self.speeds

    def isMoving(self):
        return self.speeds.length() != 0

    def isCrouching(self):
        return self.crouching

    def getFootstepSoundsDir(self):
        return "phase_14/audio/sfx/footsteps/"

    def footstepSoundCompare(self, surface, basename):
        return surface == basename[:len(surface)]

    def getCorrectedFootstepSound(self, surface):
        return surface

    def setCurrentSurface(self, surface):
        surface = self.getCorrectedFootstepSound(surface)
        if self.currentSurface == surface:
            return

        self.currentSurface = surface

        if surface == self.getCorrectedFootstepSound(
                "default") and self.defaultOverride is not None:
            surface = self.getCorrectedFootstepSound(self.defaultOverride)

        if not surface in self.footstepSounds:
            self.footstepSounds[surface] = []
            vfs = VirtualFileSystem.getGlobalPtr()
            for vFile in vfs.scanDirectory(self.getFootstepSoundsDir()):
                fullPath = vFile.getFilename().getFullpath()
                if self.footstepSoundCompare(
                        surface,
                        vFile.getFilename().getBasenameWoExtension()):
                    sound = base.loadSfx(fullPath)
                    self.footstepSounds[surface].append(sound)

    def getCurrentSurface(self):
        if self.currentSurface == "default" and self.defaultOverride is not None:
            return self.defaultOverride

        return self.currentSurface

    def enableControls(self, wantMouse=0):
        if self.controlsEnabled:
            return

        base.taskMgr.add(self.__handlePlayerControls,
                         "LocalControls.handlePlayerControls")
        base.taskMgr.add(self.__handleFootsteps,
                         "LocalControls.handleFootsteps",
                         taskChain="fpsIndependentStuff")

        self.watchMovementInputs()

        if base.localAvatar.battleControls:
            base.taskMgr.add(self.__handleUse,
                             "LocalControls.handleUse",
                             taskChain="fpsIndependentStuff")

            if self.mode == self.MFirstPerson:
                self.fp_enable(wantMouse)
            elif self.mode == self.MThirdPerson:
                self.fp_enable(wantMouse)
                base.localAvatar.startSmartCamera()

            self.idealFwd = self.BattleNormalSpeed
            self.idealRev = self.BattleNormalSpeed
            self.fwdSpeed = self.idealFwd
            self.revSpeed = self.idealRev
        else:
            self.tp_attachCamera()
            base.localAvatar.startSmartCamera()
            self.accept(base.inputStore.NextCameraPosition,
                        base.localAvatar.smartCamera.nextCameraPos, [1])
            self.accept(base.inputStore.PreviousCameraPosition,
                        base.localAvatar.smartCamera.nextCameraPos, [0])
            self.accept(base.inputStore.LookUp,
                        base.localAvatar.smartCamera.pageUp)
            self.accept(base.inputStore.LookDown,
                        base.localAvatar.smartCamera.pageDown)

        self.controlsEnabled = True
        self.exitControlsWhenGrounded = False

    def isOnGround(self):
        if self.controller:
            return self.controller.isOnGround()
        return False

    def __controllerUpdate(self, task):
        if self.controller:
            self.controller.update(globalClock.getDt())
            self.setCurrentSurface(self.controller.getCurrentMaterial())

        return task.cont

    def startControllerUpdate(self):
        self.stopControllerUpdate()

        self.active = True
        self.controller.placeOnGround()
        taskMgr.add(self.__controllerUpdate, self.charUpdateTaskName, sort=50)

    def stopControllerUpdate(self):
        taskMgr.remove(self.charUpdateTaskName)
        self.active = False

    def setupControls(self):
        self.controller = PhysicsCharacterController(
            base.bspLoader, base.physicsWorld, render, render,
            base.localAvatar.getHeight(),
            base.localAvatar.getHeight() / 2.0, 0.3, 1.0,
            base.physicsWorld.getGravity()[2], CIGlobals.WallGroup,
            CIGlobals.FloorGroup | CIGlobals.StreetVisGroup,
            CIGlobals.EventGroup)
        self.controller.setDefaultMaterial(self.getDefaultSurface())
        self.controller.setMaxSlope(75.0, False)
        self.controller.setCollideMask(CIGlobals.LocalAvGroup)

        capsules = [
            self.controller.getWalkCapsule(),
            self.controller.getCrouchCapsule(),
            self.controller.getEventSphere()
        ]
        for cap in capsules:
            cap.setPythonTag("localAvatar", base.localAvatar)

        self.controller.setStandUpCallback(self.__handleStandUp)
        self.controller.setFallCallback(self.__handleLand)
        self.controller.setEventEnterCallback(self.__handleEventEnter)
        self.controller.setEventExitCallback(self.__handleEventExit)

        base.localAvatar.reparentTo(self.controller.getMovementParent())
        base.localAvatar.assign(self.controller.getMovementParent())
        base.cr.doId2do[base.localAvatar.doId] = base.localAvatar

        print(taskMgr)

        self.setControlScheme(self.SDefault)

    def __handleEventEnter(self, np):
        print('enter' + np.getName())
        messenger.send('enter' + np.getName(), [np])

    def __handleEventExit(self, np):
        print('exit' + np.getName())
        messenger.send('exit' + np.getName(), [np])

    def releaseMovementInputs(self):
        for tok in self.movementTokens:
            tok.release()
        self.movementTokens = []

    def watchMovementInputs(self):
        self.releaseMovementInputs()

        if base.localAvatar.battleControls:
            self.movementTokens.append(
                inputState.watchWithModifiers('forward',
                                              'w',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('reverse',
                                              's',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('slideLeft',
                                              'a',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('slideRight',
                                              'd',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('jump',
                                              'space',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('crouch',
                                              'control',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('sprint',
                                              'shift',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('walk',
                                              'alt',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('use',
                                              'e',
                                              inputSource=inputState.WASD))
        else:
            self.movementTokens.append(
                inputState.watchWithModifiers('forward',
                                              'arrow_up',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('reverse',
                                              'arrow_down',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('turnLeft',
                                              'arrow_left',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('turnRight',
                                              'arrow_right',
                                              inputSource=inputState.WASD))
            self.movementTokens.append(
                inputState.watchWithModifiers('jump',
                                              'control',
                                              inputSource=inputState.WASD))

    def disableControls(self, chat=False):
        if not self.controlsEnabled:
            return

        if base.localAvatar.battleControls:
            self.fpsCam.disableMouseMovement(False, not chat)

        self.ignore('alt')
        self.ignore(base.inputStore.NextCameraPosition)
        self.ignore(base.inputStore.PreviousCameraPosition)

        if not chat and (base.localAvatar.isThirdPerson()
                         or not base.localAvatar.battleControls):
            base.localAvatar.stopSmartCamera()

        inputState.set('forward', False, inputSource=inputState.WASD)
        inputState.set('reverse', False, inputSource=inputState.WASD)
        inputState.set('slideLeft', False, inputSource=inputState.WASD)
        inputState.set('slideRight', False, inputSource=inputState.WASD)
        inputState.set('jump', False, inputSource=inputState.WASD)
        inputState.set('crouch', False, inputSource=inputState.WASD)
        inputState.set('walk', False, inputSource=inputState.WASD)
        inputState.set('sprint', False, inputSource=inputState.WASD)
        inputState.set('use', False, inputSource=inputState.WASD)
        base.taskMgr.remove("LocalControls.handlePlayerControls")
        base.taskMgr.remove("LocalControls.handleFootsteps")
        base.taskMgr.remove("LocalControls.handleUse")
        self.controller.setLinearMovement(Vec3(0))
        self.controller.setAngularMovement(0)
        self.controlsEnabled = False

    def __handleStandUp(self):
        self.standingUp = True

    def __handleLand(self, fallDistance):
        if self.controlsEnabled:

            if fallDistance > 8:
                base.localAvatar.handleJumpHardLand()
                self.playFootstep(1.5)
                #if self.mode == LocalControls.MFirstPerson:
                #    self.fpsCam.handleJumpHardLand()
            else:
                base.localAvatar.handleJumpLand()

        if self.exitControlsWhenGrounded:
            self.stopControllerUpdate()
            self.exitControlsWhenGrounded = False

    def getDefaultSurface(self):
        return "default"

    def playFootstep(self, volume=1.0):
        surfSounds = self.footstepSounds[self.getCurrentSurface()]
        numSounds = len(surfSounds)
        if numSounds > 0:
            self.lastFoot = not self.lastFoot
            mid = int(numSounds / 2)
            if self.lastFoot:
                choices = surfSounds[:mid]
            else:
                choices = surfSounds[mid:]
            if self.currFootstepSound:
                self.currFootstepSound.stop()
            sound = random.choice(choices)
            sound.setVolume(volume * self.FootstepVolumeMod)
            #sound.play()
            if True:  #self.currentSurface != self.getDefaultSurface():
                # if it's not the default footstep sound, put the default toon step sound behind it
                # to sound more like feet running
                default = self.defaultSounds[int(self.lastFoot)]
                default.setVolume(volume * self.FootstepVolumeMod)
                default.play()
            self.currFootstepSound = sound

            if self.printFootstepInfo:
                print("Playing Footstep")
                print("Num Footstep Tasks: " + str(
                    len(
                        base.taskMgr.getTasksNamed(
                            "LocalControls.handleFootsteps"))))
        self.lastFootstepTime = globalClock.getFrameTime()

    def getFootstepIval(self, speed):
        return CIGlobals.remapVal(speed, self.BattleNormalSpeed,
                                  self.BattleRunSpeed, 0.4, 0.3)

    def getFootstepVolume(self, speed):
        return min(1, speed / self.BattleNormalSpeed)

    def __handleFootsteps(self, task):
        time = globalClock.getFrameTime()
        speeds = self.speeds.length()
        if speeds > 0.1 and (self.isOnGround() or self.scheme == self.SSwim):
            self.footstepIval = self.getFootstepIval(speeds)
            if self.scheme == self.SSwim:
                self.footstepIval *= 6.0

            if time - self.lastFootstepTime >= self.footstepIval:
                self.playFootstep(self.getFootstepVolume(speeds))
        return task.cont

    def __handleUse(self, task):
        #if self.mode == LocalControls.MThirdPerson:
        #    return task.cont

        time = globalClock.getFrameTime()
        use = inputState.isSet('use')
        if use:
            # see if there is anything for us to use.

            distance = 7.5
            camQuat = base.camera.getQuat(render)
            camFwd = camQuat.xform(Vec3.forward())
            camPos = base.camera.getPos(render)
            if self.mode == self.MFirstPerson:
                start = camPos
            else:
                # Move the line out to their character.
                # This prevents the player from using things that
                # are behind their character, but in front of
                # the camera.
                laPos = base.localAvatar.getPos(render)
                camToPlyr = (camPos.getXy() - laPos.getXy()).length()
                start = camPos + (camFwd * camToPlyr)
            stop = start + (camFwd * distance)
            hit = PhysicsUtils.rayTestClosestNotMe(base.localAvatar, start,
                                                   stop,
                                                   CIGlobals.UseableGroup)

            somethingToUse = False
            if hit is not None:
                node = hit.getNode()
                if node.hasPythonTag("useableObject"):
                    somethingToUse = True
                    obj = node.getPythonTag("useableObject")
                    if obj.canUse():
                        if self.currentObjectUsing != obj:
                            if self.currentObjectUsing is not None:
                                self.currentObjectUsing.stopUse()
                            obj.startUse()
                            self.lastUseObjectTime = time
                        elif time - self.lastUseObjectTime >= obj.useIval:
                            obj.use()
                            self.lastUseObjectTime = time

                        self.currentObjectUsing = obj

            if not somethingToUse and not self.lastUse:
                self.useInvalidSound.play()
        else:
            if self.currentObjectUsing is not None:
                self.currentObjectUsing.stopUse()
                self.currentObjectUsing = None

        self.lastUse = use
        return task.cont

    def __handlePlayerControls(self, task):
        dt = globalClock.getDt()
        time = globalClock.getFrameTime()

        forward = inputState.isSet('forward')
        reverse = inputState.isSet('reverse')
        slideLeft = inputState.isSet('slideLeft')
        slideRight = inputState.isSet('slideRight')
        turnLeft = inputState.isSet('turnLeft')
        turnRight = inputState.isSet('turnRight')
        jump = inputState.isSet('jump')
        crouch = inputState.isSet('crouch')
        sprint = inputState.isSet('sprint')
        walk = inputState.isSet('walk')

        # Determine goal speeds
        speed = Vec3(0)

        if forward:
            speed.setY(self.fwdSpeed)
        elif reverse:
            speed.setY(-self.revSpeed)
        else:
            speed.setY(0)

        if reverse and slideLeft:
            speed.setX(-self.revSpeed * self.SlideFactor)
        elif reverse and slideRight:
            speed.setX(self.revSpeed * self.SlideFactor)
        elif slideLeft:
            speed.setX(-self.fwdSpeed * self.SlideFactor)
        elif slideRight:
            speed.setX(self.fwdSpeed * self.SlideFactor)
        else:
            speed.setX(0)

        if speed.getX() != 0 and speed.getY() != 0:
            speed.setX(speed.getX() * self.DiagonalFactor)
            speed.setY(speed.getY() * self.DiagonalFactor)

        if turnLeft:
            speed.setZ(self.turnSpeed)
        elif turnRight:
            speed.setZ(-self.turnSpeed)
        else:
            speed.setZ(0)

        self.speeds = Vec3(speed)
        if base.localAvatar.battleControls:
            # Apply smoothed out movement in battle controls.

            sFriction = 1 - math.pow(1 - self.staticFriction, dt * 30.0)
            dFriction = 1 - math.pow(1 - self.dynamicFriction, dt * 30.0)

            # Apply friction to the goal speeds
            if abs(self.speeds.getX()) < abs(self.lastSpeeds.getX()):
                self.lastSpeeds.setX(self.speeds.getX() * dFriction +
                                     self.lastSpeeds.getX() * (1 - dFriction))
            else:
                self.lastSpeeds.setX(self.speeds.getX() * sFriction +
                                     self.lastSpeeds.getX() * (1 - sFriction))

            if abs(self.speeds.getY()) < abs(self.lastSpeeds.getY()):
                self.lastSpeeds.setY(self.speeds.getY() * dFriction +
                                     self.lastSpeeds.getY() * (1 - dFriction))
            else:
                self.lastSpeeds.setY(self.speeds.getY() * sFriction +
                                     self.lastSpeeds.getY() * (1 - sFriction))

            if abs(self.speeds.getZ()) < abs(self.lastSpeeds.getZ()):
                self.lastSpeeds.setZ(self.speeds.getZ() * dFriction +
                                     self.lastSpeeds.getZ() * (1 - dFriction))
            else:
                self.lastSpeeds.setZ(self.speeds.getZ() * sFriction +
                                     self.lastSpeeds.getZ() * (1 - sFriction))
        else:
            self.lastSpeeds = self.speeds

        self.speeds = Vec3(self.lastSpeeds)

        if abs(self.speeds.getX()) < 0.1:
            self.speeds.setX(0)
        if abs(self.speeds.getY()) < 0.1:
            self.speeds.setY(0)
        if abs(self.speeds.getZ()) < 0.1:
            self.speeds.setZ(0)

        linearSpeed = Vec3(self.speeds[0], self.speeds[1], 0.0)

        if self.scheme == self.SSwim and self.mode == self.MFirstPerson:
            # When swimming in first person, move in the direction we are looking, like flying.
            linearSpeed = self.fpsCam.camRoot.getQuat(render).xform(
                linearSpeed)
        else:
            linearSpeed = base.localAvatar.getQuat(render).xform(linearSpeed)

        self.controller.setLinearMovement(linearSpeed)
        self.controller.setAngularMovement(self.speeds.getZ())

        onGround = self.isOnGround()
        if jump and onGround and not self.airborne and (
                self.allowJump and not base.localAvatar.isDead()):
            self.controller.startJump(3.0)
            self.playFootstep(1.5)
            self.airborne = True
        elif onGround and self.controller.getMovementState(
        ) == MOVEMENTSTATE_GROUND:
            # We landed
            self.airborne = False

        if walk:
            fctr = 0.6
            self.fwdSpeed = self.BattleWalkSpeed
            self.revSpeed = self.BattleWalkSpeed
        elif sprint:
            self.fwdSpeed = self.BattleRunSpeed
            self.revSpeed = self.BattleRunSpeed
        elif not self.crouching:
            self.fwdSpeed = self.idealFwd
            self.revSpeed = self.idealRev

        if crouch and not self.crouching and self.allowCrouch:
            fctr = self.CrouchSpeedFactor
            self.fwdSpeed = self.idealFwd * fctr
            self.revSpeed = self.idealRev * fctr
            self.controller.startCrouch()
            self.crouching = True
            self.standingUp = False
        elif not crouch and self.crouching:
            self.controller.stopCrouch()
            if self.standingUp:
                self.fwdSpeed = self.idealFwd
                self.revSpeed = self.idealRev
                self.crouching = False

        moveBits = 0

        if self.isMoving():
            moveBits |= CIGlobals.MB_Moving
        if self.crouching:
            moveBits |= CIGlobals.MB_Crouching
        if walk:
            moveBits |= CIGlobals.MB_Walking

        if moveBits != base.localAvatar.moveBits:
            base.localAvatar.b_setMoveBits(moveBits)

        return task.cont
示例#22
0
class RemoteToonBattleAvatar(RemoteAvatar):
    notify = directNotify.newCategory('RemoteToonBattleAvatar')

    def __init__(self, mg, cr, avId, gunName = 'pistol'):
        RemoteAvatar.__init__(self, mg, cr, avId)
        self.track = None
        self.gunName = gunName
        self.fsm = ClassicFSM('RemoteToonBattleAvatar', [State('off', self.enterOff, self.exitOff),
         State('shoot', self.enterShoot, self.exitShoot),
         State('die', self.enterDie, self.exitDie),
         State('dead', self.enterDead, self.exitDead)], 'off', 'off')
        self.fsm.enterInitialState()
        self.soundGrunt = None
        self.retrieveAvatar()
        return

    def setGunName(self, gunName):
        self.gunName = gunName
        self.avatar.attachGun(gunName)

    def getGunName(self):
        return self.gunName

    def retrieveAvatar(self):
        RemoteAvatar.retrieveAvatar(self)
        if self.avatar:
            self.avatar.attachGun(self.gunName)
            self.soundGrunt = base.loadSfx('phase_4/audio/sfx/target_impact_grunt1.mp3')

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def grunt(self):
        base.playSfx(self.soundGrunt, node=self.avatar)

    def enterDead(self):
        if self.avatar:
            self.avatar.stash()

    def exitDead(self):
        if self.avatar:
            self.avatar.unstash()
            self.avatar.clearColorScale()
            self.avatar.getGeomNode().clearColorScale()
            self.avatar.clearTransparency()
            self.avatar.getGeomNode().clearTransparency()
            self.avatar.getNameTag().clearColorScale()

    def enterDie(self, ts):
        if self.avatar:
            dieSound = base.audio3d.loadSfx(self.avatar.getToonAnimalNoise('exclaim'))
            base.audio3d.attachSoundToObject(dieSound, self.avatar)
            self.avatar.setTransparency(1)
            self.avatar.getGeomNode().setTransparency(1)
            self.track = Sequence(Func(dieSound.play), Parallel(LerpColorScaleInterval(self.avatar.getGeomNode(), colorScale=VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1), duration=0.5), LerpColorScaleInterval(self.avatar.getNameTag(), colorScale=VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1), duration=0.5), ActorInterval(self.avatar, 'fallb')), Func(self.fsm.request, 'dead'))
            self.track.start(ts)
            del dieSound

    def exitDie(self):
        self.resetTrack()

    def resetTrack(self):
        if self.track:
            self.track.pause()
            self.track = None
        return

    def run(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('run', partName='legs')
            else:
                self.avatar.loop('run')

    def stand(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('neutral', partName='legs')
            else:
                self.avatar.loop('neutral')

    def jump(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('jump', partName='legs')
            else:
                self.avatar.loop('jump')

    def enterShoot(self, ts):
        if self.avatar:

            def createBullet():
                if self.gunName == 'pistol':
                    Bullet(self.mg, self.avatar.gun.find('**/joint_nozzle'), 0, self.gunName)
                elif self.gunName == 'shotgun':
                    b1 = Bullet(self.mg, self.avatar.gun.find('**/joint_nozzle'), 0, self.gunName)
                    b2 = Bullet(self.mg, self.avatar.gun.find('**/joint_nozzle'), 0, self.gunName)

            def changeToLegAnim():
                self.avatar.loop(self.avatar.getCurrentAnim(partName='legs'))

            if self.gunName == 'pistol':
                gunSound = base.audio3d.loadSfx('phase_4/audio/sfx/pistol_shoot.wav')
            elif self.gunName == 'shotgun':
                gunSound = base.audio3d.loadSfx('phase_4/audio/sfx/shotgun_shoot.wav')
            base.audio3d.attachSoundToObject(gunSound, self.avatar)
            self.track = Sequence(Func(createBullet), Func(gunSound.play), ActorInterval(self.avatar, 'squirt', partName='torso', startFrame=48, endFrame=58), ActorInterval(self.avatar, 'squirt', partName='torso', startFrame=107, endFrame=126, playRate=3), Func(changeToLegAnim))
            self.track.start(ts)
            del gunSound
            self.mg.makeSmokeEffect(self.avatar.gun.find('**/joint_nozzle').getPos(render))

    def exitShoot(self):
        self.resetTrack()

    def cleanup(self):
        if self.avatar:
            self.avatar.detachGun()
        self.soundGrunt = None
        if self.track:
            self.track.pause()
        del self.track
        RemoteAvatar.cleanup(self)
        return
class ShtickerBook(StateData):
    def __init__(self, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('ShtickerBook', [
            State('off', self.enterOff, self.exitOff),
            State('optionPage', self.enterOptionPage, self.exitOptionPage,
                  ['districtPage', 'off']),
            State('districtPage', self.enterDistrictPage,
                  self.exitDistrictPage, ['optionPage', 'questPage', 'off']),
            State('questPage', self.enterQuestPage, self.exitQuestPage,
                  ['inventoryPage', 'districtPage', 'off']),
            State('inventoryPage', self.enterInventoryPage,
                  self.exitInventoryPage, ['mapPage', 'questPage', 'off']),
            State('mapPage', self.enterMapPage, self.exitMapPage,
                  ['inventoryPage', 'off']),
            State('releaseNotesPage', self.enterReleaseNotesPage,
                  self.exitReleaseNotesPage, ['mapPage', 'off']),
            State('adminPage', self.enterAdminPage, self.exitAdminPage,
                  ['mapPage', 'namePage', 'off']),
            State('namePage', self.enterNamePage, self.exitNamePage,
                  ['adminPage', 'off'])
        ], 'off', 'off')
        if base.localAvatar.getAdminToken() > -1:
            self.fsm.getStateNamed('mapPage').addTransition('adminPage')
        self.fsm.enterInitialState()
        self.entered = 0
        self.parentFSM.getStateNamed('shtickerBook').addChild(self.fsm)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def load(self):
        StateData.load(self)
        self.book_contents = loader.loadModel(
            "phase_3.5/models/gui/stickerbook_gui.bam")
        self.book_texture = self.book_contents.find('**/big_book')
        self.book_open = loader.loadSfx(
            "phase_3.5/audio/sfx/GUI_stickerbook_open.ogg")
        self.book_close = loader.loadSfx(
            "phase_3.5/audio/sfx/GUI_stickerbook_delete.ogg")
        self.book_turn = loader.loadSfx(
            "phase_3.5/audio/sfx/GUI_stickerbook_turn.ogg")

    def unload(self):
        self.book_texture.removeNode()
        del self.book_texture
        self.book_contents.removeNode()
        del self.book_contents
        loader.unloadSfx(self.book_open)
        del self.book_open
        loader.unloadSfx(self.book_close)
        del self.book_close
        loader.unloadSfx(self.book_turn)
        del self.book_turn
        del self.fsm
        del self.parentFSM
        del self.entered
        StateData.unload(self)

    def enter(self, page):
        if self.entered:
            return
        self.entered = 1
        StateData.enter(self)
        render.hide()
        base.setBackgroundColor(0.05, 0.15, 0.4)
        self.book_img = OnscreenImage(image=self.book_texture,
                                      scale=(2, 1, 1.5))
        self.book_open.play()
        if base.localAvatar.getAdminToken() > -1:
            self.fsm.request('adminPage')
        else:
            self.fsm.request(page)

    def exit(self):
        if not self.entered:
            return
        self.entered = 0
        base.setBackgroundColor(CIGlobals.DefaultBackgroundColor)
        render.show()
        self.book_img.destroy()
        del self.book_img
        self.book_close.play()
        self.fsm.request('off')
        StateData.exit(self)

    def enterDistrictPage(self):
        self.createPageButtons('optionPage', 'questPage')
        self.setTitle("Districts")

        currDistrictName = base.cr.myDistrict.getDistrictName()
        if not currDistrictName.isalpha():
            currDistrictName = currDistrictName[:-1]
        self.infoLbl = OnscreenText(
            text='Each District is a copy of the Cog Invasion world.\n'
            '\n\nYou are currently in the "%s" District' % currDistrictName,
            pos=(0.05, 0.3),
            align=TextNode.ALeft,
            wordwrap=12)
        self.populationLbl = OnscreenText(text="Population: %d" %
                                          base.cr.myDistrict.getPopulation(),
                                          pos=(0.44, -0.3),
                                          align=TextNode.ACenter)

        textRolloverColor = Vec4(1, 1, 0, 1)
        textDownColor = Vec4(0.5, 0.9, 1, 1)
        textDisabledColor = Vec4(0.4, 0.8, 0.4, 1)

        self.shardButtons = []
        for shard in base.cr.activeDistricts.values():
            shardName = shard.getDistrictName()
            shardId = shard.doId
            btn = DirectButton(relief=None,
                               text=shardName,
                               text_scale=0.07,
                               text_align=TextNode.ALeft,
                               text1_bg=textDownColor,
                               text2_bg=textRolloverColor,
                               text3_fg=textDisabledColor,
                               textMayChange=0,
                               command=self.__handleShardButton,
                               extraArgs=[shardId],
                               text_pos=(0, 0, 0.0))
            if shardId == base.localAvatar.parentId:
                btn['state'] = DGG.DISABLED
            else:
                btn['state'] = DGG.NORMAL
            self.shardButtons.append(btn)

        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        listXorigin = -0.02
        listFrameSizeX = 0.625
        listZorigin = -0.96
        listFrameSizeZ = 1.04
        arrowButtonScale = 1.3
        itemFrameXorigin = -0.237
        itemFrameZorigin = 0.365
        buttonXstart = itemFrameXorigin + 0.293

        self.districtList = DirectScrolledList(
            relief=None,
            pos=(-0.54, 0, 0.08),
            incButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_scale=(arrowButtonScale, arrowButtonScale,
                             -arrowButtonScale),
            incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999),
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_scale=(arrowButtonScale, arrowButtonScale,
                             arrowButtonScale),
            decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125),
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(listXorigin, listXorigin + listFrameSizeX,
                                 listZorigin, listZorigin + listFrameSizeZ),
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=15,
            forceHeight=0.075,
            items=self.shardButtons)
        base.taskMgr.add(self.__updateDistrictPopTask,
                         "SB.updateDistrictPopTask")

    def __handleShardButton(self, shardId):
        self.finished("switchShard", shardId)

    def __updateDistrictPopTask(self, task):
        population = base.cr.myDistrict.getPopulation()
        self.populationLbl.setText('Population: %d' % population)
        task.delayTime = 5.0
        return task.again

    def exitDistrictPage(self):
        base.taskMgr.remove('SB.updateDistrictPopTask')
        for btn in self.shardButtons:
            btn.destroy()
        del self.shardButtons
        self.districtList.destroy()
        del self.districtList
        self.infoLbl.destroy()
        del self.infoLbl
        self.populationLbl.destroy()
        del self.populationLbl
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterNamePage(self):
        self.namePageStateData = NamePage(self, self.fsm)
        self.namePageStateData.load()
        self.namePageStateData.enter()

    def exitNamePage(self):
        self.namePageStateData.exit()
        self.namePageStateData.unload()
        del self.namePageStateData

    def enterQuestPage(self):
        self.createPageButtons('districtPage', 'inventoryPage')
        self.setTitle("Quests")
        """
        self.notes = base.localAvatar.questManager.makeQuestNotes()
        for note in self.notes:
            note.show()
        """

        self.posters = []
        for quest in base.localAvatar.questManager.getQuests():
            poster = QuestPoster(quest)
            poster.update()
            self.posters.append(poster)

        self.infoText = OnscreenText(
            text=
            "Return completed Quests to an HQ Officer at any Toon HQ building.",
            pos=(0, -0.6),
            scale=0.045)

    def exitQuestPage(self):
        self.infoText.destroy()
        del self.infoText
        for poster in self.posters:
            poster.destroy()
        """
        for note in self.notes:
            note.destroy()
        """
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterInventoryPage(self):
        self.createPageButtons('questPage', 'mapPage')
        self.setTitle('Gags')
        self.gui = BackpackGUI()
        self.gui.createGUI()

    def exitInventoryPage(self):
        self.gui.deleteGUI()
        del self.gui
        self.deletePageButtons(True, True)
        self.clearTitle()

    def enterMapPage(self):
        if base.localAvatar.getAdminToken() > -1:
            self.createPageButtons('inventoryPage', 'adminPage')
        else:
            self.createPageButtons('inventoryPage', None)
        self.setTitle("")

        themap = loader.loadModel('phase_3.5/models/gui/toontown_map.bam')
        self.frame = DirectFrame(parent=aspect2d,
                                 relief=None,
                                 image=themap,
                                 image_scale=(1.8, 1, 1.35),
                                 scale=0.97,
                                 pos=(0, 0, 0.0775))
        cloudpos = [[(-0.61, 0, 0.18), (0.55, 0.25, 0.37), (180, 0, 0)],
                    [(-0.54, 0, 0.34), (0.76, 0.4, 0.55), (180, 0, 0)],
                    [(-0.55, 0, -0.09), (0.72, 0.4, 0.55), (0, 0, 0)],
                    [(-0.67, 0, -0.51), (0.5, 0.29, 0.38), (180, 0, 0)],
                    [(-0.67, 0, 0.51), (0.50, 0.29, 0.38), (0, 0, 0)],
                    [(0.67, 0, 0.51), (0.5, 0.29, 0.38), (0, 0, 0)],
                    [(0.35, 0, -0.46), (0.63, 0.35, 0.45), (0, 0, 0)],
                    [(0.18, 0, -0.45), (0.52, 0.27, 0.32), (0, 0, 0)],
                    [(0.67, 0, -0.44), (0.63, 0.35, 0.48), (180, 0, 0)]]
        hoodclouds = [  #[(0.02, 0, -0.17),  (0.63, 0.35, 0.48), (180, 0, 0), CIGlobals.ToontownCentral],
            [(0.63, 0, -0.13), (0.63, 0.35, 0.40), (0, 0, 0),
             CIGlobals.DonaldsDock],
            [(0.51, 0, 0.25), (0.57, 0.35, 0.40), (0, 0, 0),
             CIGlobals.TheBrrrgh],
            [(0.03, 0, 0.19), (0.63, 0.35, 0.40), (180, 0, 0),
             CIGlobals.MinniesMelodyland],
            [(-0.08, 0, 0.46), (0.54, 0.35, 0.40), (0, 0, 0),
             CIGlobals.DonaldsDreamland],
            [(-0.28, 0, -0.49), (0.60, 0.35, 0.45), (0, 0, 0),
             CIGlobals.DaisyGardens]
        ]
        self.clouds = []
        self.labels = []

        for pos, scale, hpr in cloudpos:
            cloud = loader.loadModel('phase_3.5/models/gui/cloud.bam')
            cloud.reparentTo(self.frame)
            cloud.setPos(pos)
            cloud.setScale(scale)
            cloud.setHpr(hpr)
            self.clouds.append(cloud)

        for pos, scale, hpr, hood in hoodclouds:
            if not base.localAvatar.hasDiscoveredHood(
                    ZoneUtil.getZoneId(hood)):
                cloud = loader.loadModel('phase_3.5/models/gui/cloud.bam')
                cloud.reparentTo(self.frame)
                cloud.setPos(pos)
                cloud.setScale(scale)
                cloud.setHpr(hpr)
                self.clouds.append(cloud)

        labeldata = [[(0, 0, -0.2), CIGlobals.ToontownCentral],
                     [(0.65, 0, -0.125), CIGlobals.DonaldsDock],
                     [(0.07, 0, 0.18), CIGlobals.MinniesMelodyland],
                     [(-0.1, 0, 0.45), CIGlobals.DonaldsDreamland],
                     [(0.5, 0, 0.25), CIGlobals.TheBrrrgh],
                     [(-0.37, 0, -0.525), CIGlobals.DaisyGardens]]

        for pos, name in labeldata:
            if base.localAvatar.hasDiscoveredHood(ZoneUtil.getZoneId(name)):
                text = name
                if base.localAvatar.hasTeleportAccess(
                        ZoneUtil.getZoneId(name)):
                    text = 'Go To\n' + text
                label = DirectButton(parent=self.frame,
                                     relief=None,
                                     pos=pos,
                                     pad=(0.2, 0.16),
                                     text=('', text, text, ''),
                                     text_bg=Vec4(1, 1, 1, 0.4),
                                     text_scale=0.055,
                                     text_wordwrap=8,
                                     rolloverSound=None,
                                     clickSound=None,
                                     pressEffect=0,
                                     sortOrder=1,
                                     text_font=CIGlobals.getToonFont())
                if base.localAvatar.hasTeleportAccess(
                        ZoneUtil.getZoneId(name)):
                    label['command'] = self.finished
                    label['extraArgs'] = [ZoneUtil.getZoneId(name)]
                label.resetFrameSize()
                self.labels.append(label)

        currHoodName = base.cr.playGame.hood.id
        currLocation = ''
        if base.localAvatar.zoneId == CIGlobals.MinigameAreaId or base.localAvatar.getMyBattle(
        ) is not None:
            currLocation = ''
        elif ZoneUtil.getWhereName(base.localAvatar.zoneId) == 'playground':
            currLocation = 'Playground'
        elif ZoneUtil.getWhereName(
                base.localAvatar.zoneId) in ['street', 'interior']:
            currLocation = CIGlobals.BranchZone2StreetName[
                ZoneUtil.getBranchZone(base.localAvatar.zoneId)]
        self.infoLabel = DirectLabel(relief=None,
                                     text='You are in: {0}\n{1}'.format(
                                         currHoodName, currLocation),
                                     scale=0.06,
                                     pos=(-0.4, 0, -0.74),
                                     parent=self.frame,
                                     text_align=TextNode.ACenter)

        if currHoodName in [CIGlobals.MinigameArea, CIGlobals.BattleTTC]:
            currHoodName = base.cr.playGame.lastHood
        btpText = "Back to Playground"
        btpEA = [ZoneUtil.getZoneId(currHoodName)]
        self.BTPButton = DirectButton(relief=None,
                                      text=btpText,
                                      geom=CIGlobals.getDefaultBtnGeom(),
                                      text_pos=(0, -0.018),
                                      geom_scale=(1.3, 1.11, 1.11),
                                      text_scale=0.06,
                                      parent=self.frame,
                                      text_font=CIGlobals.getToonFont(),
                                      pos=(0.25, 0, -0.75),
                                      command=self.finished,
                                      extraArgs=btpEA,
                                      scale=0.7)
        if base.localAvatar.zoneId != CIGlobals.MinigameAreaId:
            self.MGAButton = DirectButton(relief=None,
                                          text="Minigame Area",
                                          geom=CIGlobals.getDefaultBtnGeom(),
                                          text_pos=(0, -0.018),
                                          geom_scale=(1, 1.11, 1.11),
                                          text_scale=0.06,
                                          parent=self.frame,
                                          text_font=CIGlobals.getToonFont(),
                                          pos=(0.625, 0, -0.75),
                                          command=self.finished,
                                          extraArgs=[CIGlobals.MinigameAreaId],
                                          scale=0.7)

    def exitMapPage(self):
        for label in self.labels:
            label.destroy()
        del self.labels
        for cloud in self.clouds:
            cloud.removeNode()
        del self.clouds
        self.frame.destroy()
        del self.frame
        self.infoLabel.destroy()
        del self.infoLabel
        self.BTPButton.destroy()
        del self.BTPButton
        if hasattr(self, 'MGAButton'):
            self.MGAButton.destroy()
            del self.MGAButton
        if base.localAvatar.getAdminToken() > -1:
            self.deletePageButtons(True, True)
        else:
            self.deletePageButtons(True, False)
        self.clearTitle()

    def enterZonePage(self):
        self.createPageButtons('inventoryPage', 'releaseNotesPage')
        self.setTitle("Places")
        #self.home_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
        #									qt_btn.find('**/QuitBtn_DN'),
        #									qt_btn.find('**/QuitBtn_RLVR')), relief=None, scale=1.2, text_scale=0.055, text=CIGlobals.Estate, command=self.setHood, extraArgs=[10], pos=(-0.45, 0.55, 0.55))
        self.ttc_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                          qt_btn.find('**/QuitBtn_DN'),
                                          qt_btn.find('**/QuitBtn_RLVR')),
                                    relief=None,
                                    scale=1.2,
                                    text_scale=0.045,
                                    text=CIGlobals.ToontownCentral,
                                    command=self.finished,
                                    extraArgs=[CIGlobals.ToontownCentralId],
                                    pos=(-0.45, 0.15, 0.5),
                                    text_pos=(0, -0.01))
        self.tbr_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                          qt_btn.find('**/QuitBtn_DN'),
                                          qt_btn.find('**/QuitBtn_RLVR')),
                                    relief=None,
                                    scale=1.2,
                                    text_scale=0.055,
                                    text=CIGlobals.TheBrrrgh,
                                    command=self.finished,
                                    extraArgs=[CIGlobals.TheBrrrghId],
                                    pos=(-0.45, 0.15, 0.38),
                                    text_pos=(0, -0.01))
        self.ddl_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                          qt_btn.find('**/QuitBtn_DN'),
                                          qt_btn.find('**/QuitBtn_RLVR')),
                                    relief=None,
                                    scale=1.2,
                                    text_scale=0.044,
                                    text=CIGlobals.DonaldsDreamland,
                                    command=self.finished,
                                    extraArgs=[CIGlobals.DonaldsDreamlandId],
                                    pos=(-0.45, 0.15, 0.26),
                                    text_pos=(0, -0.01))
        self.mml_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                          qt_btn.find('**/QuitBtn_DN'),
                                          qt_btn.find('**/QuitBtn_RLVR')),
                                    relief=None,
                                    scale=1.2,
                                    text_scale=0.0425,
                                    text=CIGlobals.MinniesMelodyland,
                                    command=self.finished,
                                    extraArgs=[CIGlobals.MinniesMelodylandId],
                                    pos=(-0.45, 0.35, 0.14),
                                    text_pos=(0, -0.01))
        self.dg_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                         qt_btn.find('**/QuitBtn_DN'),
                                         qt_btn.find('**/QuitBtn_RLVR')),
                                   relief=None,
                                   scale=1.2,
                                   text_scale=0.045,
                                   text=CIGlobals.DaisyGardens,
                                   command=self.finished,
                                   extraArgs=[CIGlobals.DaisyGardensId],
                                   pos=(-0.45, 0.35, 0.02),
                                   text_pos=(0, -0.01))
        self.dd_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                         qt_btn.find('**/QuitBtn_DN'),
                                         qt_btn.find('**/QuitBtn_RLVR')),
                                   relief=None,
                                   scale=1.2,
                                   text_scale=0.045,
                                   text=CIGlobals.DonaldsDock,
                                   command=self.finished,
                                   extraArgs=[CIGlobals.DonaldsDockId],
                                   pos=(-0.45, 0.35, -0.1),
                                   text_pos=(0, -0.01))
        self.minigame_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'),
                                               qt_btn.find('**/QuitBtn_DN'),
                                               qt_btn.find('**/QuitBtn_RLVR')),
                                         relief=None,
                                         scale=1.2,
                                         text_scale=0.055,
                                         text=CIGlobals.MinigameArea,
                                         command=self.finished,
                                         extraArgs=[CIGlobals.MinigameAreaId],
                                         pos=(-0.45, 0.35, -0.34),
                                         text_pos=(0, -0.01))
        #self.populationLbl = OnscreenText(text = "", pos = (0.45, 0.1), align = TextNode.ACenter)
        #self.popRecordLbl = OnscreenText(text = "", pos = (0.45, -0.1), align = TextNode.ACenter, scale = 0.05)
        #taskMgr.add(self.__updateGamePopulation, "ShtickerBook-updateGamePopulation")

    def __updateGamePopulation(self, task):
        population = 0
        for district in base.cr.activeDistricts.values():
            population += district.getPopulation()
        self.populationLbl.setText("Game Population:\n" + str(population))
        recordPopulation = base.cr.myDistrict.getPopRecord()
        self.popRecordLbl.setText("Record Population:\n" +
                                  str(recordPopulation))
        task.delayTime = 5.0
        return task.again

    def exitZonePage(self):
        #taskMgr.remove("ShtickerBook-updateGamePopulation")
        #self.popRecordLbl.destroy()
        #del self.popRecordLbl
        #self.populationLbl.destroy()
        #del self.populationLbl
        self.dd_btn.destroy()
        del self.dd_btn
        self.ddl_btn.destroy()
        del self.ddl_btn
        self.ttc_btn.destroy()
        del self.ttc_btn
        self.tbr_btn.destroy()
        del self.tbr_btn
        self.minigame_btn.destroy()
        del self.minigame_btn
        self.mml_btn.destroy()
        del self.mml_btn
        self.dg_btn.destroy()
        del self.dg_btn
        self.deletePageButtons(True, True)
        self.clearTitle()

    def createPageButtons(self, back, fwd):
        if back:
            self.btn_prev = DirectButton(
                geom=(self.book_contents.find('**/arrow_button'),
                      self.book_contents.find('**/arrow_down'),
                      self.book_contents.find('**/arrow_rollover')),
                relief=None,
                pos=(-0.838, 0, -0.661),
                scale=(-0.1, 0.1, 0.1),
                command=self.pageDone,
                extraArgs=[back])
            self.acceptOnce('arrow_left-up', self.pageDone, [back])
        if fwd:
            self.btn_next = DirectButton(
                geom=(self.book_contents.find('**/arrow_button'),
                      self.book_contents.find('**/arrow_down'),
                      self.book_contents.find('**/arrow_rollover')),
                relief=None,
                pos=(0.838, 0, -0.661),
                scale=(0.1, 0.1, 0.1),
                command=self.pageDone,
                extraArgs=[fwd])
            self.acceptOnce('arrow_right-up', self.pageDone, [fwd])

    def deletePageButtons(self, back, fwd):
        if back:
            self.ignore('arrow_left-up')
            self.btn_prev.destroy()
            del self.btn_prev
        if fwd:
            self.ignore('arrow_right-up')
            self.btn_next.destroy()
            del self.btn_next

    def setTitle(self, title):
        self.page_title = OnscreenText(text=title,
                                       pos=(0, 0.62, 0),
                                       scale=0.12)

    def clearTitle(self):
        self.page_title.destroy()
        del self.page_title

    def enterReleaseNotesPage(self):
        if base.localAvatar.getAdminToken() > -1:
            self.createPageButtons('mapPage', 'adminPage')
        else:
            self.createPageButtons('mapPage', None)
        self.setTitle("Release Notes")
        self.frame = DirectScrolledFrame(canvasSize=(-1, 1, -3.5, 1),
                                         frameSize=(-1, 1, -0.6, 0.6))
        self.frame.setPos(0, 0, 0)
        self.frame.setScale(0.8)
        self.release_notes = DirectLabel(text=open("release_notes.txt",
                                                   "r").read(),
                                         text_align=TextNode.ALeft,
                                         pos=(-0.955, 0, 0.93),
                                         relief=None,
                                         text_fg=(0, 0, 0, 1),
                                         text_wordwrap=37.0,
                                         text_scale=0.05,
                                         parent=self.frame.getCanvas())

    def exitReleaseNotesPage(self):
        self.frame.destroy()
        del self.frame
        self.release_notes.destroy()
        del self.release_notes
        self.clearTitle()
        if base.localAvatar.getAdminToken() > -1:
            self.deletePageButtons(True, True)
        else:
            self.deletePageButtons(True, False)

    def enterAdminPage(self):
        self.adminPageStateData = AdminPage(self, self.fsm)
        self.adminPageStateData.load()
        self.adminPageStateData.enter()

    def exitAdminPage(self):
        self.adminPageStateData.exit()
        self.adminPageStateData.unload()
        del self.adminPageStateData

    def pageDone(self, nextPage):
        base.cr.playGame.getPlace().lastBookPage = nextPage
        if hasattr(self, 'fsm'):
            self.fsm.request(nextPage)
        self.book_turn.play()

    def enterOptionPage(self):
        self.optionPageStateData = OptionPage(self, self.fsm)
        #self.acceptOnce(self.optionPageStateData.doneEvent, self.pageDone)
        self.optionPageStateData.load()
        self.optionPageStateData.enter()

    def exitOptionPage(self):
        #self.ignore(self.optionPageStateData.doneEvent)
        self.optionPageStateData.exit()
        self.optionPageStateData.unload()
        del self.optionPageStateData

    def prevPage(self, currentPage):
        self.clearCurrentPage()
        if self.currentPage == 2:
            self.optionPage()
        elif self.currentPage == 3:
            self.zonePage()
        elif self.currentPage == 4:
            self.releaseNotesPage()

    def nextPage(self, currentPage):
        self.clearCurrentPage()
        if self.currentPage == 1:
            self.zonePage()
        elif self.currentPage == 2:
            self.releaseNotesPage()
        elif self.currentPage == 3:
            self.adminPage()

    def clearCurrentPage(self):
        self.book_turn.play()
        for m in base.bookpgnode.getChildren():
            m.removeNode()

    def finished(self, zone, shardId=None):
        if base.localAvatar.getHealth() < 1 and type(zone) == type(1):
            return
        doneStatus = {}
        if zone in [
                CIGlobals.ToontownCentralId, CIGlobals.MinigameAreaId,
                CIGlobals.TheBrrrghId, CIGlobals.DonaldsDreamlandId,
                CIGlobals.MinniesMelodylandId, CIGlobals.DaisyGardensId,
                CIGlobals.DonaldsDockId
        ]:
            doneStatus["mode"] = 'teleport'
            doneStatus["zoneId"] = zone
            doneStatus["hoodId"] = ZoneUtil.getHoodId(zone)
            doneStatus["where"] = ZoneUtil.getWhereName(zone)
            doneStatus["how"] = 'teleportIn'
            doneStatus["avId"] = base.localAvatar.doId
            doneStatus["shardId"] = None
            doneStatus["loader"] = ZoneUtil.getLoaderName(zone)
        else:
            doneStatus["mode"] = zone
            if zone == "switchShard":
                doneStatus["shardId"] = shardId
        self.doneStatus = doneStatus
        messenger.send(self.doneEvent)

    def closeBook(self):
        self.book_close.play()
        base.bookpgnode.removeNode()
        base.booknode.removeNode()
示例#24
0
文件: Char.py 项目: coginvasion/src
class Char(Avatar.Avatar):

    def __init__(self):
        try:
            self.Char_initialized
            return
        except:
            self.Char_initialized = 1

        Avatar.Avatar.__init__(self)
        self.avatarType = CIGlobals.CChar
        self.avatarName = None
        self.currentAnim = None
        self.charType = ''
        self.eyes = loader.loadTexture('phase_3/maps/eyes1.jpg', 'phase_3/maps/eyes1_a.rgb')
        self.closedEyes = loader.loadTexture('phase_3/maps/mickey_eyes_closed.jpg', 'phase_3/maps/mickey_eyes_closed_a.rgb')
        self.animFSM = ClassicFSM('Char', [State('off', self.enterOff, self.exitOff),
         State('neutral', self.enterNeutral, self.exitNeutral),
         State('walk', self.enterWalk, self.exitWalk),
         State('run', self.enterRun, self.exitRun)], 'off', 'off')
        animStateList = self.animFSM.getStates()
        self.animFSM.enterInitialState()
        Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 3.5, 1)
        return

    def stopAnimations(self):
        if hasattr(self, 'animFSM'):
            if not self.animFSM.isInternalStateInFlux():
                self.animFSM.request('off')
            else:
                notify.warning('animFSM in flux, state=%s, not requesting off' % self.animFSM.getCurrentState().getName())
        else:
            notify.warning('animFSM has been deleted')

    def disable(self):
        self.stopBlink()
        self.stopAnimations()
        Avatar.Avatar.disable(self)

    def delete(self):
        try:
            self.Char_deleted
        except:
            self.Char_deleted = 1
            del self.animFSM
            Avatar.Avatar.delete(self)

    def setChat(self, chatString):
        if self.charType == CIGlobals.Mickey:
            self.dial = base.audio3d.loadSfx('phase_3/audio/dial/mickey.wav')
        elif self.charType == CIGlobals.Minnie:
            self.dial = base.audio3d.loadSfx('phase_3/audio/dial/minnie.wav')
        elif self.charType == CIGlobals.Goofy:
            self.dial = base.audio3d.loadSfx('phase_6/audio/dial/goofy.wav')
        base.audio3d.attachSoundToObject(self.dial, self)
        self.dial.play()
        Avatar.Avatar.setChat(self, chatString)

    def setName(self, nameString, charName = None):
        self.avatarName = nameString
        Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType, charName=charName)

    def generateChar(self, charType):
        self.charType = charType
        if charType == CIGlobals.Mickey or charType == CIGlobals.Minnie:
            self.loadModel('phase_3/models/char/' + charType.lower() + '-' + str(CIGlobals.ModelDetail(self.avatarType)) + '.bam')
            self.loadAnims({'neutral': 'phase_3/models/char/' + charType.lower() + '-wait.bam',
             'walk': 'phase_3/models/char/' + charType.lower() + '-walk.bam',
             'run': 'phase_3/models/char/' + charType.lower() + '-run.bam',
             'left-start': 'phase_3.5/models/char/' + charType.lower() + '-left-start.bam',
             'left': 'phase_3.5/models/char/' + charType.lower() + '-left.bam',
             'right-start': 'phase_3.5/models/char/' + charType.lower() + '-right-start.bam',
             'right': 'phase_3.5/models/char/' + charType.lower() + '-right.bam'})
            if charType == CIGlobals.Mickey:
                self.mickeyEye = self.controlJoint(None, 'modelRoot', 'joint_pupilR')
                self.mickeyEye.setY(0.025)
            for bundle in self.getPartBundleDict().values():
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                earNull.clearNetTransforms()

            for bundle in self.getPartBundleDict().values():
                charNodepath = bundle['modelRoot'].partBundleNP
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                ears = charNodepath.find('**/sphere3')
                if ears.isEmpty():
                    ears = charNodepath.find('**/*sphere3')
                ears.clearEffect(CharacterJointEffect.getClassType())
                earRoot = charNodepath.attachNewNode('earRoot')
                earPitch = earRoot.attachNewNode('earPitch')
                earPitch.setP(40.0)
                ears.reparentTo(earPitch)
                earNull.addNetTransform(earRoot.node())
                ears.clearMat()
                ears.node().setPreserveTransform(ModelNode.PTNone)
                ears.setP(-40.0)
                ears.flattenMedium()
                ears.setBillboardAxis()
                self.startBlink()

        elif charType == CIGlobals.Pluto:
            self.loadModel('phase_6/models/char/pluto-1000.bam')
            self.loadAnims({'walk': 'phase_6/models/char/pluto-walk.bam',
             'neutral': 'phase_6/models/char/pluto-neutral.bam',
             'sit': 'phase_6/models/char/pluto-sit.bam',
             'stand': 'phase_6/models/char/pluto-stand.bam'})
        elif charType == CIGlobals.Goofy:
            self.loadModel('phase_6/models/char/TT_G-1500.bam')
            self.loadAnims({'neutral': 'phase_6/models/char/TT_GWait.bam',
             'walk': 'phase_6/models/char/TT_GWalk.bam'})
        else:
            raise StandardError('unknown char %s!' % charType)
        Avatar.Avatar.initShadow(self)
        return

    def initializeLocalCollisions(self, name, radius):
        Avatar.Avatar.initializeLocalCollisions(self, radius, 2, name)

    def startBlink(self):
        randomStart = random.uniform(0.5, 5)
        taskMgr.add(self.blinkTask, 'blinkTask')

    def stopBlink(self):
        taskMgr.remove('blinkTask')
        taskMgr.remove('doBlink')
        taskMgr.remove('openEyes')

    def blinkTask(self, task):
        taskMgr.add(self.doBlink, 'doBlink')
        delay = random.uniform(0.5, 7)
        task.delayTime = delay
        return task.again

    def doBlink(self, task):
        self.closeEyes()
        taskMgr.doMethodLater(0.2, self.openEyes, 'openEyes')
        return task.done

    def closeEyes(self):
        self.find('**/joint_pupilR').hide()
        self.find('**/joint_pupilL').hide()
        if self.charType == CIGlobals.Mickey:
            self.mickeyEye.setY(-0.025)
            self.mickeyEye.hide()
        self.find('**/eyes').setTexture(self.closedEyes, 1)

    def openEyes(self, task):
        self.find('**/joint_pupilR').show()
        self.find('**/joint_pupilL').show()
        if self.charType == CIGlobals.Mickey:
            self.mickeyEye.setY(0.025)
            self.mickeyEye.show()
        self.find('**/eyes').setTexture(self.eyes, 1)
        return task.done

    def enterOff(self):
        self.currentAnim = None
        return

    def exitOff(self):
        pass

    def enterNeutral(self):
        self.loop('neutral')

    def exitNeutral(self):
        self.stop()

    def enterWalk(self):
        self.loop('walk')

    def exitWalk(self):
        self.stop()

    def enterRun(self):
        self.loop('run')

    def exitRun(self):
        self.stop()
示例#25
0
class QuietZoneState(StateData):
    def __init__(self, doneEvent, moveOn=1):
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('quietZone', [
            State('off', self.enterOff, self.exitOff,
                  ['waitForQuietZoneResponse']),
            State(
                'waitForQuietZoneResponse', self.enterWaitForQuietZoneResponse,
                self.exitWaitForQuietZoneResponse, ['waitForSetZoneResponse']),
            State('waitForSetZoneResponse', self.enterWaitForSetZoneResponse,
                  self.exitWaitForSetZoneResponse, ['waitForSetZoneComplete']),
            State('waitForSetZoneComplete', self.enterWaitForSetZoneComplete,
                  self.exitWaitForSetZoneComplete, ['off'])
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.moveOn = moveOn

    def getSetZoneCompleteEvent(self):
        return 'setZoneComplete-%s' % id(self)

    def getQuietZoneResponseEvent(self):
        return 'quietZoneResponse-%s' % id(self)

    def getEnterWaitForSetZoneResponseMsg(self):
        return 'enterWaitForSetZoneResponse-%s' % id(self)

    def unload(self):
        StateData.unload(self)
        del self.fsm

    def enter(self, requestStatus):
        StateData.enter(self)
        self._requestStatus = requestStatus
        base.localAvatar.b_setAnimState('off')
        self.fsm.request('waitForQuietZoneResponse')

    def exit(self):
        StateData.exit(self)
        if self._requestStatus.get('how', None) != 'doorOut':
            base.transitions.noTransitions()
        del self._requestStatus
        self.fsm.request('off')
        return

    def getDoneStatus(self):
        return self._requestStatus

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def handleWaitForQuietZoneResponse(self, msgType, di):
        if msgType == CLIENT_ENTER_OBJECT_REQUIRED:
            base.cr.handleQuietZoneGenerateWithRequired(di)
        else:
            if msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER:
                base.cr.handleQuietZoneGenerateWithRequiredOther(di)
            else:
                if msgType == CLIENT_OBJECT_SET_FIELD:
                    base.cr.handleQuietZoneUpdateField(di)
                else:
                    base.cr.astronHandle(di)

    def enterWaitForQuietZoneResponse(self):
        self.setZoneDoneEvent = base.cr.getNextSetZoneDoneEvent()
        self.acceptOnce(self.setZoneDoneEvent, self._handleQuietZoneResponse)
        base.cr.sendQuietZoneRequest()

    def _handleQuietZoneResponse(self):
        if self.moveOn:
            self.fsm.request('waitForSetZoneResponse')
        else:
            messenger.send('enteredQuietZone')

    def exitWaitForQuietZoneResponse(self):
        self.ignore(self.setZoneDoneEvent)
        del self.setZoneDoneEvent

    def enterWaitForZoneRedirect(self):
        self.fsm.request('waitForSetZoneResponse')

    def exitWaitForZoneRedirect(self):
        pass

    def enterWaitForSetZoneResponse(self):
        zoneId = self._requestStatus['zoneId']
        base.cr.sendSetZoneMsg(zoneId)
        self.fsm.request('waitForSetZoneComplete')

    def exitWaitForSetZoneResponse(self):
        pass

    def enterWaitForSetZoneComplete(self):
        self.setZoneDoneEvent = base.cr.getLastSetZoneDoneEvent()
        self.acceptOnce(self.setZoneDoneEvent, self._announceDone)

    def exitWaitForSetZoneComplete(self):
        self.ignore(self.setZoneDoneEvent)
        del self.setZoneDoneEvent

    def _announceDone(self):
        doneEvent = self.doneEvent
        requestStatus = self._requestStatus
        messenger.send(self.getSetZoneCompleteEvent(), [requestStatus])
        messenger.send(doneEvent)

    def getRequestStatus(self):
        return self._requestStatus
示例#26
0
class AvChooser(StateData):
    notify = directNotify.newCategory('AvChooser')

    def __init__(self, parentFSM):
        StateData.__init__(self, 'avChooseDone')
        self.avChooseFSM = ClassicFSM('avChoose', [State('getToonData', self.enterGetToonData, self.exitGetToonData),
         State('avChoose', self.enterAvChoose, self.exitAvChoose),
         State('waitForToonDelResponse', self.enterWaitForToonDelResponse, self.exitWaitForToonDelResponse),
         State('off', self.enterOff, self.exitOff)], 'off', 'off')
        self.avChooseFSM.enterInitialState()
        self.parentFSM = parentFSM
        self.parentFSM.getStateNamed('avChoose').addChild(self.avChooseFSM)
        self.pickAToon = None
        self.setAvatarsNone()
        return

    def enter(self):
        StateData.enter(self)
        base.transitions.noTransitions()
        self.avChooseFSM.request('getToonData')

    def exit(self):
        StateData.exit(self)
        self.setAvatarsNone()
        self.avChooseFSM.requestFinalState()

    def setAvatarsNone(self):
        self.avChoices = []

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterGetToonData(self):
        self.acceptOnce(base.cr.csm.getSetAvatarsEvent(), self.handleToonData)
        base.cr.csm.d_requestAvatars()

    def handleToonData(self, avatarList):
        for av in avatarList:
            avId = av[0]
            dna = av[1]
            name = av[2]
            slot = av[3]
            choice = AvChoice(dna, name, slot, avId)
            self.avChoices.append(choice)

        self.avChooseFSM.request('avChoose')

    def exitGetToonData(self):
        self.ignore(base.cr.csm.getSetAvatarsEvent())

    def enterAvChoose(self):
        self.pickAToon = CharSelection(self)
        self.pickAToon.load()

    def enterWaitForToonDelResponse(self, avId):
        self.acceptOnce(base.cr.csm.getToonDeletedEvent(), self.handleDeleteToonResp)
        base.cr.csm.sendDeleteToon(avId)

    def exitWaitForToonDelResponse(self):
        self.ignore(base.cr.csm.getToonDeletedEvent())

    def hasToonInSlot(self, slot):
        if self.getAvChoiceBySlot(slot) != None:
            return True
        else:
            return False
            return

    def getNameInSlot(self, slot):
        return self.getAvChoiceBySlot(slot).getName()

    def getAvChoiceBySlot(self, slot):
        for avChoice in self.avChoices:
            if avChoice.getSlot() == slot:
                return avChoice

        return None

    def getHeadInfo(self, slot):
        dna = self.getAvChoiceBySlot(slot).getDNA()
        self.pickAToon.dna.setDNAStrand(dna)
        return [self.pickAToon.dna.getGender(),
         self.pickAToon.dna.getAnimal(),
         self.pickAToon.dna.getHead(),
         self.pickAToon.dna.getHeadColor()]

    def handleDeleteToonResp(self):
        base.cr.loginFSM.request('avChoose')

    def exitAvChoose(self):
        self.pickAToon.unload()
        self.pickAToon = None
        return
class DistributedDisneyChar(DistributedAvatar, DistributedSmoothNode):
    notify = directNotify.newCategory('DistributedDisneyChar')

    def __init__(self, cr):
        DistributedAvatar.__init__(self, cr)
        DistributedSmoothNode.__init__(self, cr)

        self.fsm = ClassicFSM('DDisneyChar', [
            State('off', self.enterOff, self.exitOff),
            State('walking', self.enterWalking, self.exitWalking),
            State('neutral', self.enterNeutral, self.exitNeutral)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.neutralFSM = ClassicFSM('DDisneyChar-neutral', [
            State('off', self.enterOff, self.exitOff),
            State('turn2target', self.enterTurn2Target, self.exitTurn2Target),
            State('talk2target', self.enterTalk2Target, self.exitTalk2Target)
        ], 'off', 'off')
        self.neutralFSM.enterInitialState()

        self.charId = 0
        self.geoEyes = 0
        self.avatarType = CIGlobals.CChar
        self.isInRange = False
        self.currentPointLetter = "a"
        self.walkIval = None
        self.currentChat = ""
        self.talkEnabled = True
        self.speechSound = None

        self.chatsSinceLastNoise = 0
        self.chatsWithoutNoise = 5

        self.eyes = None
        self.lpupil = None
        self.rpupil = None
        self.eyesOpen = None
        self.eyesClosed = None

    def setCharId(self, charId):
        self.charId = charId

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def doNeutral(self, pointLetter):
        self.fsm.request('neutral', [pointLetter])

    def doWalking(self, pointLetter, startPointLetter, timestamp):
        ts = globalClockDelta.localElapsedTime(timestamp)
        self.fsm.request('walking', [pointLetter, startPointLetter, ts])

    def enterWalking(self, pointLetter, startPointLetter, ts):

        if self.walkIval:
            self.walkIval.finish()
            self.walkIval = None

        self.nametag.clearChatText()

        self.loop('walk')

        point = WALK_POINTS[self.charId][pointLetter][0]
        lastPoint = WALK_POINTS[self.charId][startPointLetter][0]

        seq = Sequence(name=self.uniqueName('DCharWalkIval'))
        if self.charId == PLUTO:
            seq.append(ActorInterval(self, 'stand'))
        elif self.charId == SLEEP_DONALD:
            seq.append(ActorInterval(self, 'neutral2walk'))
        seq.append(Func(self.loop, 'walk'))
        ival = NPCWalkInterval(self, point, startPos=lastPoint, fluid=1)
        seq.append(ival)
        seq.append(Func(self.loop, 'neutral'))
        seq.start(ts)

        self.currentPointLetter = pointLetter

        self.walkIval = ival

    def exitWalking(self):
        if self.walkIval:
            self.walkIval.finish()
            self.walkIval = None

    def enterNeutral(self, pointLetter):
        point = WALK_POINTS[self.charId][pointLetter][0]
        self.setPos(point)
        if self.charId == PLUTO:
            seq = Sequence(ActorInterval(self, 'sit'),
                           Func(self.loop, 'neutral'))
            seq.start()
        elif self.charId == SLEEP_DONALD:
            seq = Sequence(ActorInterval(self, 'walk2neutral'),
                           Func(self.loop, 'neutral'))
            seq.start()
        else:
            self.loop('neutral')

    def talk2Toon(self, chatType, chatIndex, avId):
        toon = self.cr.doId2do.get(avId)
        if not toon:
            return

        if chatType in [SHARED_GREETINGS, SHARED_COMMENTS, SHARED_GOODBYES]:
            self.currentChat = CHATTER[chatType][chatIndex]
        elif chatType in [CHAR_GREETINGS, CHAR_COMMENTS, CHAR_GOODBYES]:
            self.currentChat = CHATTER[chatType][self.charId][chatIndex]

        if '%s' in self.currentChat:
            self.currentChat = self.currentChat % toon.getName()

        self.neutralFSM.request('turn2target', [toon])

    def enterTurn2Target(self, toon):
        self.turnIval = NPCLookInterval(self,
                                        toon,
                                        fluid=1,
                                        name=self.uniqueName('turnIval'))
        if self.turnIval.distance > 30:
            self.loop('walk')
        elif self.turnIval.distance < 10.0:
            self.headsUp(toon)
            self.neutralFSM.request('talk2target')
            return
        self.turnIval.setDoneEvent(self.turnIval.getName())
        self.acceptOnce(self.turnIval.getDoneEvent(), self.__handleTurningDone)
        self.turnIval.start()

    def __handleTurningDone(self):
        self.neutralFSM.request('talk2target')

    def exitTurn2Target(self):
        self.ignore(self.turnIval.getDoneEvent())
        self.turnIval.finish()
        del self.turnIval

    def enterTalk2Target(self):
        self.setChat(self.currentChat)
        if self.getCurrentAnim() != 'neutral':
            if self.charId == SLEEP_DONALD:
                seq = Sequence(ActorInterval(self, 'walk2neutral'),
                               Func(self.loop, 'neutral'))
                seq.start()
            else:
                self.loop('neutral')

    def exitTalk2Target(self):
        pass

    def exitNeutral(self):
        self.neutralFSM.request('off')
        self.stop()

    def setChat(self, chat):
        if self.charId == SLEEP_DONALD:
            chat = "." + chat
        DistributedAvatar.setChat(self, chat)
        if self.chatsSinceLastNoise >= self.chatsWithoutNoise or self.chatsSinceLastNoise == 0:
            base.playSfx(self.speechSound, node=self)
            self.chatsSinceLastNoise = 0
            self.chatsWithoutNoise = random.randint(1, 5)
        self.chatsSinceLastNoise += 1

    def loadChar(self):
        data = CHAR_DATA[self.charId]
        self.loadModel(data[0], 'modelRoot')
        self.loadAnims(data[1], 'modelRoot')
        if self.charId == SLEEP_DONALD:
            self.setPlayRate(0.5, 'neutral')
        self.setHeight(data[2])
        self.setName(data[3])
        self.talkEnabled = data[4]
        if self.talkEnabled:
            self.speechSound = data[5]
            if self.speechSound is not None:
                base.audio3d.attachSoundToObject(self.speechSound, self)
        self.setupNameTag()

        self.ears = []

        if self.charId in [MINNIE, MICKEY]:
            for bundle in self.getPartBundleDict().values():
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                earNull.clearNetTransforms()

            for bundle in self.getPartBundleDict().values():
                charNodepath = bundle['modelRoot'].partBundleNP
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                ears = charNodepath.find('**/sphere3')
                if ears.isEmpty():
                    ears = charNodepath.find('**/*sphere3')
                ears.clearEffect(CharacterJointEffect.getClassType())
                earRoot = charNodepath.attachNewNode('earRoot')
                earPitch = earRoot.attachNewNode('earPitch')
                earPitch.setP(40.0)
                ears.reparentTo(earPitch)
                earNull.addNetTransform(earRoot.node())
                ears.clearMat()
                ears.node().setPreserveTransform(ModelNode.PTNone)
                ears.setP(-40.0)
                ears.flattenMedium()
                self.ears.append(ears)
                ears.setBillboardAxis()

            self.eyesOpen = loader.loadTexture('phase_3/maps/eyes1.jpg',
                                               'phase_3/maps/eyes1_a.rgb')
            self.eyesClosed = loader.loadTexture(
                'phase_3/maps/mickey_eyes_closed.jpg',
                'phase_3/maps/mickey_eyes_closed_a.rgb')
            self.eyes = self.find('**/eyes')
            self.eyes.setBin('transparent', 0)
            self.lpupil = self.find('**/joint_pupilL')
            self.rpupil = self.find('**/joint_pupilR')
            self.drawInFront('joint_pupil?', 'eyes*', -3)
        elif self.charId == PLUTO:
            self.eyesOpen = loader.loadTexture(
                'phase_6/maps/plutoEyesOpen.jpg',
                'phase_6/maps/plutoEyesOpen_a.rgb')
            self.eyesClosed = loader.loadTexture(
                'phase_6/maps/plutoEyesClosed.jpg',
                'phase_6/maps/plutoEyesClosed_a.rgb')
            self.eyes = self.find('**/eyes')
            self.lpupil = self.find('**/joint_pupilL')
            self.rpupil = self.find('**/joint_pupilR')
            self.drawInFront('joint_pupil?', 'eyes*', -3)
        elif self.charId == DAISY:
            self.geoEyes = 1
            self.eyeOpenList = []
            self.eyeCloseList = []
            self.eyeCloseList.append(self.find('**/eyesclose'))
            self.eyeOpenList.append(self.find('**/eyesclose'))
            self.eyeOpenList.append(self.find('**/eyespupil'))
            self.eyeOpenList.append(self.find('**/eyesopen'))
            for part in self.eyeOpenList:
                part.show()

            for part in self.eyeCloseList:
                part.hide()
        elif self.charId == SAILOR_DONALD:
            self.eyes = self.find('**/eyes')
            self.lpupil = self.find('**/joint_pupilL')
            self.rpupil = self.find('**/joint_pupilR')
            self.drawInFront('joint_pupil?', 'eyes*', -3)

        if self.lpupil is not None:
            self.lpupil.adjustAllPriorities(1)
            self.rpupil.adjustAllPriorities(1)
        if self.eyesOpen:
            self.eyesOpen.setMinfilter(Texture.FTLinear)
            self.eyesOpen.setMagfilter(Texture.FTLinear)
        if self.eyesClosed:
            self.eyesClosed.setMinfilter(Texture.FTLinear)
            self.eyesClosed.setMagfilter(Texture.FTLinear)

        if self.charId == MICKEY:
            pupilParent = self.rpupil.getParent()
            pupilOffsetNode = pupilParent.attachNewNode('pupilOffsetNode')
            pupilOffsetNode.setPos(0, 0.025, 0)
            self.rpupil.reparentTo(pupilOffsetNode)

        self.initShadow()
        self.shadow.setScale(0.6)
        self.initializeBodyCollisions(self.avatarType, self.getHeight(), 1.0)
        self.initializeRay(self.avatarType, 1)
        self.disableShadowRay()

        self.__blinkName = 'blink-' + data[3]

    def setupNameTag(self):
        DistributedAvatar.setupNameTag(self)
        self.nametag.setNametagColor(
            NametagGlobals.NametagColors[NametagGlobals.CCNPC])
        self.nametag.setActive(0)
        self.nametag.updateAll()

    def __monitorRange(self, task):
        if base.localAvatar.getDistance(self) <= MAX_RANGE:
            if self.isInRange is False:
                self.sendUpdate('avatarEnter')
                self.isInRange = True
        else:
            if self.isInRange is True:
                self.sendUpdate('avatarExit')
                self.isInRange = False

        return task.cont

    def __blinkOpenEyes(self, task):
        self.openEyes()
        r = random.random()
        if r < 0.1:
            t = 0.2
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self.__blinkCloseEyes, self.__blinkName)
        return task.done

    def __blinkCloseEyes(self, task):
        self.closeEyes()
        taskMgr.doMethodLater(0.125, self.__blinkOpenEyes, self.__blinkName)
        return task.done

    def openEyes(self):
        if self.geoEyes:
            for part in self.eyeOpenList:
                part.show()

            for part in self.eyeCloseList:
                part.hide()

        else:
            if self.eyes:
                self.eyes.setTexture(self.eyesOpen, 1)
            self.lpupil.show()
            self.rpupil.show()

    def closeEyes(self):
        if self.geoEyes:
            for part in self.eyeOpenList:
                part.hide()

            for part in self.eyeCloseList:
                part.show()

        else:
            if self.eyes:
                self.eyes.setTexture(self.eyesClosed, 1)
            self.lpupil.hide()
            self.rpupil.hide()

    def startBlink(self):
        if self.eyesOpen or self.geoEyes:
            taskMgr.remove(self.__blinkName)
            taskMgr.doMethodLater(random.random() * 4 + 1,
                                  self.__blinkCloseEyes, self.__blinkName)

    def stopBlink(self):
        if self.eyesOpen or self.geoEyes:
            taskMgr.remove(self.__blinkName)
            self.openEyes()

    def getNametagJoints(self):
        return []

    def generate(self):
        DistributedAvatar.generate(self)
        DistributedSmoothNode.generate(self)

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        DistributedSmoothNode.announceGenerate(self)
        self.loadChar()
        self.startBlink()
        base.taskMgr.add(self.__monitorRange, self.uniqueName('monitorRange'))
        self.sendUpdate('requestStateData')
        if self.charId == SAILOR_DONALD:
            self.disableRay()
            self.stashBodyCollisions()
            boat = self.cr.playGame.hood.loader.geom.find('**/*donalds_boat*')
            boat.find('**/wheel').hide()
            self.setPos(0, -1, 3.95)
            self.reparentTo(boat)
            self.loop('wheel')
        else:
            self.reparentTo(render)

    def disable(self):
        base.taskMgr.remove(self.uniqueName('monitorRange'))
        self.stopBlink()
        self.fsm.requestFinalState()
        self.fsm = None
        self.neutralFSM.requestFinalState()
        self.neutralFSM = None
        self.charId = None
        self.geoEyes = None
        self.avatarType = None
        self.isInRange = None
        self.currentPointLetter = None
        self.walkIval = None
        self.currentChat = None
        self.talkEnabled = None
        self.speechSound = None
        self.chatsSinceLastNoise = None

        self.eyes = None
        self.lpupil = None
        self.rpupil = None
        self.eyesOpen = None
        self.eyesClosed = None
        DistributedAvatar.disable(self)
        Avatar.disable(self)
        DistributedSmoothNode.disable(self)
示例#28
0
class ToonHead(Actor.Actor):

    notify = DirectNotifyGlobal.directNotify.newCategory('ToonHead')
    EyesOpen = loader.loadTexture('phase_3/maps/eyes.jpg', 'phase_3/maps/eyes_a.rgb')
    EyesOpen.setMinfilter(Texture.FTLinear)
    EyesOpen.setMagfilter(Texture.FTLinear)
    EyesClosed = loader.loadTexture('phase_3/maps/eyesClosed.jpg', 'phase_3/maps/eyesClosed_a.rgb')
    EyesClosed.setMinfilter(Texture.FTLinear)
    EyesClosed.setMagfilter(Texture.FTLinear)
    EyesSadOpen = loader.loadTexture('phase_3/maps/eyesSad.jpg', 'phase_3/maps/eyesSad_a.rgb')
    EyesSadOpen.setMinfilter(Texture.FTLinear)
    EyesSadOpen.setMagfilter(Texture.FTLinear)
    EyesSadClosed = loader.loadTexture('phase_3/maps/eyesSadClosed.jpg', 'phase_3/maps/eyesSadClosed_a.rgb')
    EyesSadClosed.setMinfilter(Texture.FTLinear)
    EyesSadClosed.setMagfilter(Texture.FTLinear)
    EyesAngryOpen = loader.loadTexture('phase_3/maps/eyesAngry.jpg', 'phase_3/maps/eyesAngry_a.rgb')
    EyesAngryOpen.setMinfilter(Texture.FTLinear)
    EyesAngryOpen.setMagfilter(Texture.FTLinear)
    EyesAngryClosed = loader.loadTexture('phase_3/maps/eyesAngryClosed.jpg', 'phase_3/maps/eyesAngryClosed_a.rgb')
    EyesAngryClosed.setMinfilter(Texture.FTLinear)
    EyesAngryClosed.setMagfilter(Texture.FTLinear)
    EyesSurprised = loader.loadTexture('phase_3/maps/eyesSurprised.jpg', 'phase_3/maps/eyesSurprised_a.rgb')
    EyesSurprised.setMinfilter(Texture.FTLinear)
    EyesSurprised.setMagfilter(Texture.FTLinear)
    Muzzle = loader.loadTexture('phase_3/maps/muzzleShrtGeneric.jpg')
    Muzzle.setMinfilter(Texture.FTLinear)
    Muzzle.setMagfilter(Texture.FTLinear)
    MuzzleSurprised = loader.loadTexture('phase_3/maps/muzzleShortSurprised.jpg')
    MuzzleSurprised.setMinfilter(Texture.FTLinear)
    MuzzleSurprised.setMagfilter(Texture.FTLinear)
    LeftA = Point3(0.06, 0.0, 0.14)
    LeftB = Point3(-0.13, 0.0, 0.1)
    LeftC = Point3(-0.05, 0.0, 0.0)
    LeftD = Point3(0.06, 0.0, 0.0)
    RightA = Point3(0.13, 0.0, 0.1)
    RightB = Point3(-0.06, 0.0, 0.14)
    RightC = Point3(-0.06, 0.0, 0.0)
    RightD = Point3(0.05, 0.0, 0.0)
    LeftAD = Point3(LeftA[0] - LeftA[2] * (LeftD[0] - LeftA[0]) / (LeftD[2] - LeftA[2]), 0.0, 0.0)
    LeftBC = Point3(LeftB[0] - LeftB[2] * (LeftC[0] - LeftB[0]) / (LeftC[2] - LeftB[2]), 0.0, 0.0)
    RightAD = Point3(RightA[0] - RightA[2] * (RightD[0] - RightA[0]) / (RightD[2] - RightA[2]), 0.0, 0.0)
    RightBC = Point3(RightB[0] - RightB[2] * (RightC[0] - RightB[0]) / (RightC[2] - RightB[2]), 0.0, 0.0)

    def __init__(self):
        try:
            self.ToonHead_initialized
        except:
            self.ToonHead_initialized = 1
            Actor.Actor.__init__(self)
            self.toonName = 'ToonHead-' + str(self.this)
            self.__blinkName = 'blink-' + self.toonName
            self.__stareAtName = 'stareAt-' + self.toonName
            self.__lookName = 'look-' + self.toonName
            self.lookAtTrack = None
            self.__eyes = None
            self.__eyelashOpen = None
            self.__eyelashClosed = None
            self.__lod500Eyes = None
            self.__lod250Eyes = None
            self.__lpupil = None
            self.__lod500lPupil = None
            self.__lod250lPupil = None
            self.__rpupil = None
            self.__lod500rPupil = None
            self.__lod250rPupil = None
            self.__muzzle = None
            self.__eyesOpen = ToonHead.EyesOpen
            self.__eyesClosed = ToonHead.EyesClosed
            self.__height = 0.0
            self.__eyelashesHiddenByGlasses = False
            self.randGen = random.Random()
            self.randGen.seed(random.random())
            self.eyelids = ClassicFSM('eyelids', [
             State('off', self.enterEyelidsOff, self.exitEyelidsOff, ['open', 'closed', 'surprised']),
             State('open', self.enterEyelidsOpen, self.exitEyelidsOpen, ['closed', 'surprised', 'off']),
             State('surprised', self.enterEyelidsSurprised, self.exitEyelidsSurprised, ['open', 'closed', 'off']),
             State('closed', self.enterEyelidsClosed, self.exitEyelidsClosed, ['open', 'surprised', 'off'])
            ], 'off', 'off')
            self.eyelids.enterInitialState()
            self.emote = None
            self.__stareAtNode = NodePath()
            self.__defaultStarePoint = Point3(0, 0, 0)
            self.__stareAtPoint = self.__defaultStarePoint
            self.__stareAtTime = 0
            self.lookAtPositionCallbackArgs = None

    def delete(self):
        try:
            self.ToonHead_deleted
        except:
            self.ToonHead_deleted = 1
            taskMgr.remove(self.__blinkName)
            taskMgr.remove(self.__lookName)
            taskMgr.remove(self.__stareAtName)
            if self.lookAtTrack:
                self.lookAtTrack.finish()
                self.lookAtTrack = None
            del self.eyelids
            del self.__stareAtNode
            del self.__stareAtPoint
            if self.__eyes:
                del self.__eyes
            if self.__lpupil:
                del self.__lpupil
            if self.__rpupil:
                del self.__rpupil
            if self.__eyelashOpen:
                del self.__eyelashOpen
            if self.__eyelashClosed:
                del self.__eyelashClosed
            self.lookAtPositionCallbackArgs = None
            Actor.Actor.delete(self)

    def setupHead(self, dna, forGui = 0):
        self.__height = self.generateToonHead(1, dna, ('1000',), forGui)
        self.generateToonColor(dna)
        animalStyle = dna.getAnimal()
        bodyScale = ToontownGlobals.toonBodyScales[animalStyle]
        headScale = ToontownGlobals.toonHeadScales[animalStyle]
        self.getGeomNode().setScale(headScale[0] * bodyScale * 1.3, headScale[1] * bodyScale * 1.3, headScale[2] * bodyScale * 1.3)
        if forGui:
            self.getGeomNode().setDepthWrite(1)
            self.getGeomNode().setDepthTest(1)
        if dna.getAnimal() == 'dog':
            self.loop('neutral')

    def fitAndCenterHead(self, maxDim, forGui = 0):
        p1 = Point3()
        p2 = Point3()
        self.calcTightBounds(p1, p2)
        if forGui:
            h = 180
            t = p1[0]
            p1.setX(-p2[0])
            p2.setX(-t)
        else:
            h = 0
        d = p2 - p1
        biggest = max(d[0], d[2])
        s = maxDim / biggest
        mid = (p1 + d / 2.0) * s
        self.setPosHprScale(-mid[0], -mid[1] + 1, -mid[2], h, 0, 0, s, s, s)

    def setLookAtPositionCallbackArgs(self, argTuple):
        self.lookAtPositionCallbackArgs = argTuple

    def getHeight(self):
        return self.__height

    def getRandomForwardLookAtPoint(self):
        x = self.randGen.choice((-0.8, -0.5, 0, 0.5, 0.8))
        z = self.randGen.choice((-0.5, 0, 0.5, 0.8))
        return Point3(x, 1.5, z)

    def findSomethingToLookAt(self):
        if self.lookAtPositionCallbackArgs != None:
            pnt = self.lookAtPositionCallbackArgs[0].getLookAtPosition(self.lookAtPositionCallbackArgs[1], self.lookAtPositionCallbackArgs[2])
            self.startStareAt(self, pnt)
            return
        if self.randGen.random() < 0.33:
            lookAtPnt = self.getRandomForwardLookAtPoint()
        else:
            lookAtPnt = self.__defaultStarePoint
        self.lerpLookAt(lookAtPnt, blink=1)

    def generateToonHead(self, copy, style, lods, forGui=0):
        headStyle = style.head
        fix = None
        if headStyle == 'dls':
            filePrefix = HeadDict['dls']
            headHeight = 0.75
        elif headStyle == 'dss':
            filePrefix = HeadDict['dss']
            headHeight = 0.5
        elif headStyle == 'dsl':
            filePrefix = HeadDict['dsl']
            headHeight = 0.5
        elif headStyle == 'dll':
            filePrefix = HeadDict['dll']
            headHeight = 0.75
        elif headStyle == 'cls':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'css':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'csl':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'cll':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'hls':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'hss':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'hsl':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'hll':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'mls':
            filePrefix = HeadDict['m']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'mss':
            filePrefix = HeadDict['m']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'rls':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'rss':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'rsl':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'rll':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'fls':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'fss':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'fsl':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'fll':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'pls':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'pss':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'psl':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'pll':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'bls':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'bss':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'bsl':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'bll':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'sls':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'sss':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'ssl':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'sll':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        else:
            ToonHead.notify.error('unknown head style: %s' % headStyle)
        if len(lods) == 1:
            self.loadModel('phase_3' + filePrefix + lods[0], 'head', 'lodRoot', copy)
            if not copy:
                self.showAllParts('head')
            if fix != None:
                fix(style, None, copy)
            if not forGui:
                self.__lods = lods
                self.__style = style
                self.__headStyle = headStyle
                self.__copy = copy
        else:
            for lod in lods:
                self.loadModel('phase_3' + filePrefix + lod, 'head', lod, copy)
                if not copy:
                    self.showAllParts('head', lod)
                if fix != None:
                    fix(style, lod, copy)
                if not forGui:
                    self.__lods = lods
                    self.__style = style
                    self.__headStyle = headStyle
                    self.__copy = copy
        self.__fixEyes(style, forGui)
        self.setupEyelashes(style)
        self.eyelids.request('closed')
        self.eyelids.request('open')
        self.setupMuzzles(style)
        return headHeight

    def hideEars(self):
        self.findAllMatches('**/ears*;+s').stash()

    def showEars(self):
        self.findAllMatches('**/ears*;+s').unstash()

    def hideEyelashes(self):
        if self.__eyelashOpen:
            self.__eyelashOpen.stash()
        if self.__eyelashClosed:
            self.__eyelashClosed.stash()
        self.__eyelashesHiddenByGlasses = True

    def showEyelashes(self):
        if self.__eyelashOpen:
            self.__eyelashOpen.unstash()
        if self.__eyelashClosed:
            self.__eyelashClosed.unstash()
        self.__eyelashesHiddenByGlasses = False

    def generateToonColor(self, style):
        parts = self.findAllMatches('**/head*')
        parts.setColor(style.getHeadColor())
        animalType = style.getAnimal()
        if animalType == 'cat' or animalType == 'rabbit' or animalType == 'bear' or animalType == 'mouse' or animalType == 'pig':
            parts = self.findAllMatches('**/ear?-*')
            parts.setColor(style.getHeadColor())

    def __fixEyes(self, style, forGui = 0):
        mode = -3
        if forGui:
            mode = -2
        if self.hasLOD():
            for lodName in self.getLODNames():
                self.drawInFront('eyes*', 'head-front*', mode, lodName=lodName)
                if base.config.GetBool('want-new-anims', 1):
                    if not self.find('**/joint_pupil*').isEmpty():
                        self.drawInFront('joint_pupil*', 'eyes*', -1, lodName=lodName)
                    else:
                        self.drawInFront('def_*_pupil', 'eyes*', -1, lodName=lodName)
                else:
                    self.drawInFront('joint_pupil*', 'eyes*', -1, lodName=lodName)

            self.__eyes = self.getLOD(1000).find('**/eyes*')
            self.__lod500Eyes = self.getLOD(500).find('**/eyes*')
            self.__lod250Eyes = self.getLOD(250).find('**/eyes*')
            if self.__lod500Eyes.isEmpty():
                self.__lod500Eyes = None
            else:
                self.__lod500Eyes.setColorOff()
                if base.config.GetBool('want-new-anims', 1):
                    if not self.find('**/joint_pupilL*').isEmpty():
                        self.__lod500lPupil = self.__lod500Eyes.find('**/joint_pupilL*')
                        self.__lod500rPupil = self.__lod500Eyes.find('**/joint_pupilR*')
                    else:
                        self.__lod500lPupil = self.__lod500Eyes.find('**/def_left_pupil*')
                        self.__lod500rPupil = self.__lod500Eyes.find('**/def_right_pupil*')
                else:
                    self.__lod500lPupil = self.__lod500Eyes.find('**/joint_pupilL*')
                    self.__lod500rPupil = self.__lod500Eyes.find('**/joint_pupilR*')
            if self.__lod250Eyes.isEmpty():
                self.__lod250Eyes = None
            else:
                self.__lod250Eyes.setColorOff()
                if base.config.GetBool('want-new-anims', 1):
                    if not self.find('**/joint_pupilL*').isEmpty():
                        self.__lod250lPupil = self.__lod250Eyes.find('**/joint_pupilL*')
                        self.__lod250rPupil = self.__lod250Eyes.find('**/joint_pupilR*')
                    else:
                        self.__lod250lPupil = self.__lod250Eyes.find('**/def_left_pupil*')
                        self.__lod250rPupil = self.__lod250Eyes.find('**/def_right_pupil*')
                else:
                    self.__lod250lPupil = self.__lod250Eyes.find('**/joint_pupilL*')
                    self.__lod250rPupil = self.__lod250Eyes.find('**/joint_pupilR*')
        else:
            self.drawInFront('eyes*', 'head-front*', mode)
            if base.config.GetBool('want-new-anims', 1):
                if not self.find('joint_pupil*').isEmpty():
                    self.drawInFront('joint_pupil*', 'eyes*', -1)
                else:
                    self.drawInFront('def_*_pupil', 'eyes*', -1)
            else:
                self.drawInFront('joint_pupil*', 'eyes*', -1)
            self.__eyes = self.find('**/eyes*')
        if not self.__eyes.isEmpty():
            self.__eyes.setColorOff()
            self.__lpupil = None
            self.__rpupil = None
            if base.config.GetBool('want-new-anims', 1):
                if not self.find('**/joint_pupilL*').isEmpty():
                    if self.getLOD(1000):
                        lp = self.getLOD(1000).find('**/joint_pupilL*')
                        rp = self.getLOD(1000).find('**/joint_pupilR*')
                    else:
                        lp = self.find('**/joint_pupilL*')
                        rp = self.find('**/joint_pupilR*')
                elif not self.getLOD(1000):
                    lp = self.find('**/def_left_pupil*')
                    rp = self.find('**/def_right_pupil*')
                else:
                    lp = self.getLOD(1000).find('**/def_left_pupil*')
                    rp = self.getLOD(1000).find('**/def_right_pupil*')
            else:
                lp = self.__eyes.find('**/joint_pupilL*')
                rp = self.__eyes.find('**/joint_pupilR*')
            if lp.isEmpty() or rp.isEmpty():
                print 'Unable to locate pupils.'
            else:
                leye = self.__eyes.attachNewNode('leye')
                reye = self.__eyes.attachNewNode('reye')
                lmat = Mat4(0.802174, 0.59709, 0, 0, -0.586191, 0.787531, 0.190197, 0, 0.113565, -0.152571, 0.981746, 0, -0.233634, 0.418062, 0.0196875, 1)
                leye.setMat(lmat)
                rmat = Mat4(0.786788, -0.617224, 0, 0, 0.602836, 0.768447, 0.214658, 0, -0.132492, -0.16889, 0.976689, 0, 0.233634, 0.418062, 0.0196875, 1)
                reye.setMat(rmat)
                self.__lpupil = leye.attachNewNode('lpupil')
                self.__rpupil = reye.attachNewNode('rpupil')
                lpt = self.__eyes.attachNewNode('')
                rpt = self.__eyes.attachNewNode('')
                lpt.wrtReparentTo(self.__lpupil)
                rpt.wrtReparentTo(self.__rpupil)
                lp.reparentTo(lpt)
                rp.reparentTo(rpt)
                self.__lpupil.adjustAllPriorities(1)
                self.__rpupil.adjustAllPriorities(1)
                if self.__lod500Eyes:
                    self.__lod500lPupil.adjustAllPriorities(1)
                    self.__lod500rPupil.adjustAllPriorities(1)
                if self.__lod250Eyes:
                    self.__lod250lPupil.adjustAllPriorities(1)
                    self.__lod250rPupil.adjustAllPriorities(1)
                animalType = style.getAnimal()
                if animalType != 'dog':
                    self.__lpupil.flattenStrong()
                    self.__rpupil.flattenStrong()
        return

    def __setPupilDirection(self, x, y):
        if y < 0.0:
            y2 = -y
            left1 = self.LeftAD + (self.LeftD - self.LeftAD) * y2
            left2 = self.LeftBC + (self.LeftC - self.LeftBC) * y2
            right1 = self.RightAD + (self.RightD - self.RightAD) * y2
            right2 = self.RightBC + (self.RightC - self.RightBC) * y2
        else:
            y2 = y
            left1 = self.LeftAD + (self.LeftA - self.LeftAD) * y2
            left2 = self.LeftBC + (self.LeftB - self.LeftBC) * y2
            right1 = self.RightAD + (self.RightA - self.RightAD) * y2
            right2 = self.RightBC + (self.RightB - self.RightBC) * y2
        left0 = Point3(0.0, 0.0, left1[2] - left1[0] * (left2[2] - left1[2]) / (left2[0] - left1[0]))
        right0 = Point3(0.0, 0.0, right1[2] - right1[0] * (right2[2] - right1[2]) / (right2[0] - right1[0]))
        if x < 0.0:
            x2 = -x
            left = left0 + (left2 - left0) * x2
            right = right0 + (right2 - right0) * x2
        else:
            x2 = x
            left = left0 + (left1 - left0) * x2
            right = right0 + (right1 - right0) * x2
        self.__lpupil.setPos(left)
        self.__rpupil.setPos(right)

    def __lookPupilsAt(self, node, point):
        if node != None:
            mat = node.getMat(self.__eyes)
            point = mat.xformPoint(point)
        distance = 1.0
        recip_z = 1.0 / max(0.1, point[1])
        x = distance * point[0] * recip_z
        y = distance * point[2] * recip_z
        x = min(max(x, -1), 1)
        y = min(max(y, -1), 1)
        self.__setPupilDirection(x, y)
        return

    def __lookHeadAt(self, node, point, frac = 1.0, lod = None):
        reachedTarget = 1
        if lod == None:
            head = self.getPart('head', self.getLODNames()[0])
        else:
            head = self.getPart('head', lod)
        if node != None:
            headParent = head.getParent()
            mat = node.getMat(headParent)
            point = mat.xformPoint(point)
        rot = Mat3(0, 0, 0, 0, 0, 0, 0, 0, 0)
        lookAt(rot, Vec3(point), Vec3(0, 0, 1), CSDefault)
        scale = VBase3(0, 0, 0)
        hpr = VBase3(0, 0, 0)
        if decomposeMatrix(rot, scale, hpr, CSDefault):
            hpr = VBase3(min(max(hpr[0], -60), 60), min(max(hpr[1], -20), 30), 0)
            if frac != 1:
                currentHpr = head.getHpr()
                reachedTarget = abs(hpr[0] - currentHpr[0]) < 1.0 and abs(hpr[1] - currentHpr[1]) < 1.0
                hpr = currentHpr + (hpr - currentHpr) * frac
            if lod == None:
                for lodName in self.getLODNames():
                    head = self.getPart('head', lodName)
                    head.setHpr(hpr)

            else:
                head.setHpr(hpr)
        return reachedTarget

    def setupEyelashes(self, style):
        if style.getGender() == 'm':
            if self.__eyelashOpen:
                self.__eyelashOpen.removeNode()
                self.__eyelashOpen = None
            if self.__eyelashClosed:
                self.__eyelashClosed.removeNode()
                self.__eyelashClosed = None
        else:
            if self.__eyelashOpen:
                self.__eyelashOpen.removeNode()
            if self.__eyelashClosed:
                self.__eyelashClosed.removeNode()
            animal = style.head[0]
            model = loader.loadModel('phase_3' + EyelashDict[animal])
            if self.hasLOD():
                head = self.getPart('head', '1000')
            else:
                head = self.getPart('head', 'lodRoot')
            length = style.head[1]
            if length == 'l':
                openString = 'open-long'
                closedString = 'closed-long'
            else:
                openString = 'open-short'
                closedString = 'closed-short'
            self.__eyelashOpen = model.find('**/' + openString).copyTo(head)
            self.__eyelashClosed = model.find('**/' + closedString).copyTo(head)
            model.removeNode()
        return

    def __fixHeadLongLong(self, style, lodName=None, copy=1):
        if lodName == None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        otherParts = searchRoot.findAllMatches('**/*short*')
        for partNum in range(0, otherParts.getNumPaths()):
            if copy:
                otherParts.getPath(partNum).removeNode()
            else:
                otherParts.getPath(partNum).stash()

    def __fixHeadLongShort(self, style, lodName=None, copy=1):
        animalType = style.getAnimal()
        headStyle = style.head
        if lodName == None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        if animalType != 'duck' and animalType != 'horse':
            if animalType == 'rabbit':
                if copy:
                    searchRoot.find('**/ears-long').removeNode()
                else:
                    searchRoot.find('**/ears-long').hide()
            elif copy:
                searchRoot.find('**/ears-short').removeNode()
            else:
                searchRoot.find('**/ears-short').hide()
        if animalType != 'rabbit':
            if copy:
                searchRoot.find('**/eyes-short').removeNode()
            else:
                searchRoot.find('**/eyes-short').hide()
        if animalType != 'dog':
            if copy:
                searchRoot.find('**/joint_pupilL_short').removeNode()
                searchRoot.find('**/joint_pupilR_short').removeNode()
            else:
                searchRoot.find('**/joint_pupilL_short').stash()
                searchRoot.find('**/joint_pupilR_short').stash()
        if copy:
            self.find('**/head-short').removeNode()
            self.find('**/head-front-short').removeNode()
        else:
            self.find('**/head-short').hide()
            self.find('**/head-front-short').hide()
        if animalType != 'rabbit':
            muzzleParts = searchRoot.findAllMatches('**/muzzle-long*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()
        else:
            muzzleParts = searchRoot.findAllMatches('**/muzzle-short*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

    def __fixHeadShortLong(self, style, lodName=None, copy=1):
        animalType = style.getAnimal()
        headStyle = style.head
        if lodName == None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        if animalType != 'duck' and animalType != 'horse':
            if animalType == 'rabbit':
                if copy:
                    searchRoot.find('**/ears-short').removeNode()
                else:
                    searchRoot.find('**/ears-short').hide()
            elif copy:
                searchRoot.find('**/ears-long').removeNode()
            else:
                searchRoot.find('**/ears-long').hide()
        if animalType != 'rabbit':
            if copy:
                searchRoot.find('**/eyes-long').removeNode()
            else:
                searchRoot.find('**/eyes-long').hide()
        if animalType != 'dog':
            if copy:
                searchRoot.find('**/joint_pupilL_long').removeNode()
                searchRoot.find('**/joint_pupilR_long').removeNode()
            else:
                searchRoot.find('**/joint_pupilL_long').stash()
                searchRoot.find('**/joint_pupilR_long').stash()
        if copy:
            searchRoot.find('**/head-long').removeNode()
            searchRoot.find('**/head-front-long').removeNode()
        else:
            searchRoot.find('**/head-long').hide()
            searchRoot.find('**/head-front-long').hide()
        if animalType != 'rabbit':
            muzzleParts = searchRoot.findAllMatches('**/muzzle-short*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()
        else:
            muzzleParts = searchRoot.findAllMatches('**/muzzle-long*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

    def __fixHeadShortShort(self, style, lodName=None, copy=1):
        if lodName == None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        otherParts = searchRoot.findAllMatches('**/*long*')
        for partNum in range(0, otherParts.getNumPaths()):
            if copy:
                otherParts.getPath(partNum).removeNode()
            else:
                otherParts.getPath(partNum).stash()

    def __blinkOpenEyes(self, task):
        if self.eyelids.getCurrentState().getName() == 'closed':
            self.eyelids.request('open')
        r = self.randGen.random()
        if r < 0.1:
            t = 0.2
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self.__blinkCloseEyes, self.__blinkName)
        return Task.done

    def __blinkCloseEyes(self, task):
        if self.eyelids.getCurrentState().getName() != 'open':
            taskMgr.doMethodLater(4.0, self.__blinkCloseEyes, self.__blinkName)
        else:
            self.eyelids.request('closed')
            taskMgr.doMethodLater(0.125, self.__blinkOpenEyes, self.__blinkName)
        return Task.done

    def startBlink(self):
        taskMgr.remove(self.__blinkName)
        if self.__eyes:
            self.openEyes()
        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1, self.__blinkCloseEyes, self.__blinkName)

    def stopBlink(self):
        taskMgr.remove(self.__blinkName)
        if self.__eyes:
            self.eyelids.request('open')

    def closeEyes(self):
        self.eyelids.request('closed')

    def openEyes(self):
        self.eyelids.request('open')

    def surpriseEyes(self):
        self.eyelids.request('surprised')

    def sadEyes(self):
        self.__eyesOpen = ToonHead.EyesSadOpen
        self.__eyesClosed = ToonHead.EyesSadClosed

    def angryEyes(self):
        self.__eyesOpen = ToonHead.EyesAngryOpen
        self.__eyesClosed = ToonHead.EyesAngryClosed

    def normalEyes(self):
        self.__eyesOpen = ToonHead.EyesOpen
        self.__eyesClosed = ToonHead.EyesClosed

    def blinkEyes(self):
        taskMgr.remove(self.__blinkName)
        self.eyelids.request('closed')
        taskMgr.doMethodLater(0.1, self.__blinkOpenEyes, self.__blinkName)

    def __stareAt(self, task):
        frac = 2 * globalClock.getDt()
        reachedTarget = self.__lookHeadAt(self.__stareAtNode, self.__stareAtPoint, frac)
        self.__lookPupilsAt(self.__stareAtNode, self.__stareAtPoint)
        if reachedTarget and self.__stareAtNode == None:
            return Task.done
        else:
            return Task.cont
        return

    def doLookAroundToStareAt(self, node, point):
        self.startStareAt(node, point)
        self.startLookAround()

    def startStareAtHeadPoint(self, point):
        self.startStareAt(self, point)

    def startStareAt(self, node, point):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        self.__stareAtNode = node
        if point != None:
            self.__stareAtPoint = point
        else:
            self.__stareAtPoint = self.__defaultStarePoint
        self.__stareAtTime = globalClock.getFrameTime()
        taskMgr.add(self.__stareAt, self.__stareAtName)
        return

    def lerpLookAt(self, point, time = 1.0, blink = 0):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        lodNames = self.getLODNames()
        if lodNames:
            lodName = lodNames[0]
        else:
            return 0
        head = self.getPart('head', lodName)
        startHpr = head.getHpr()
        startLpupil = self.__lpupil.getPos()
        startRpupil = self.__rpupil.getPos()
        self.__lookHeadAt(None, point, lod=lodName)
        self.__lookPupilsAt(None, point)
        endHpr = head.getHpr()
        endLpupil = self.__lpupil.getPos() * 0.5
        endRpupil = self.__rpupil.getPos() * 0.5
        head.setHpr(startHpr)
        self.__lpupil.setPos(startLpupil)
        self.__rpupil.setPos(startRpupil)
        if startHpr.almostEqual(endHpr, 10):
            return 0
        if blink:
            self.blinkEyes()
        lookToTgt_TimeFraction = 0.2
        lookToTgtTime = time * lookToTgt_TimeFraction
        returnToEyeCenterTime = time - lookToTgtTime - 0.5
        origin = Point3(0, 0, 0)
        blendType = 'easeOut'
        self.lookAtTrack = Parallel(Sequence(LerpPosInterval(self.__lpupil, lookToTgtTime, endLpupil, blendType=blendType), Wait(0.5), LerpPosInterval(self.__lpupil, returnToEyeCenterTime, origin, blendType=blendType)), Sequence(LerpPosInterval(self.__rpupil, lookToTgtTime, endRpupil, blendType=blendType), Wait(0.5), LerpPosInterval(self.__rpupil, returnToEyeCenterTime, origin, blendType=blendType)), name=self.__stareAtName)
        for lodName in self.getLODNames():
            head = self.getPart('head', lodName)
            self.lookAtTrack.append(LerpHprInterval(head, time, endHpr, blendType='easeInOut'))
        self.lookAtTrack.start()
        return 1

    def stopStareAt(self):
        self.lerpLookAt(Vec3.forward())

    def stopStareAtNow(self):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        if self.__lpupil and self.__rpupil:
            self.__setPupilDirection(0, 0)
        for lodName in self.getLODNames():
            head = self.getPart('head', lodName)
            head.setHpr(0, 0, 0)

    def __lookAround(self, task):
        self.findSomethingToLookAt()
        t = self.randGen.random() * 4.0 + 3.0
        taskMgr.doMethodLater(t, self.__lookAround, self.__lookName)
        return Task.done

    def startLookAround(self):
        taskMgr.remove(self.__lookName)
        t = self.randGen.random() * 5.0 + 2.0
        taskMgr.doMethodLater(t, self.__lookAround, self.__lookName)

    def stopLookAround(self):
        taskMgr.remove(self.__lookName)
        self.stopStareAt()

    def stopLookAroundNow(self):
        taskMgr.remove(self.__lookName)
        self.stopStareAtNow()

    def enterEyelidsOff(self):
        return None

    def exitEyelidsOff(self):
        return None

    def enterEyelidsOpen(self):
        if not self.__eyes.isEmpty():
            self.__eyes.setTexture(self.__eyesOpen, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.show()
            if self.__eyelashClosed:
                self.__eyelashClosed.hide()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(self.__eyesOpen, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(self.__eyesOpen, 1)
            if self.__lpupil:
                self.__lpupil.show()
                self.__rpupil.show()
            if self.__lod500lPupil:
                self.__lod500lPupil.show()
                self.__lod500rPupil.show()
            if self.__lod250lPupil:
                self.__lod250lPupil.show()
                self.__lod250rPupil.show()

    def exitEyelidsOpen(self):
        return None

    def enterEyelidsClosed(self):
        if not self.__eyes.isEmpty() and self.__eyesClosed:
            self.__eyes.setTexture(self.__eyesClosed, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.hide()
            if self.__eyelashClosed:
                self.__eyelashClosed.show()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(self.__eyesClosed, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(self.__eyesClosed, 1)
            if self.__lpupil:
                self.__lpupil.hide()
                self.__rpupil.hide()
            if self.__lod500lPupil:
                self.__lod500lPupil.hide()
                self.__lod500rPupil.hide()
            if self.__lod250lPupil:
                self.__lod250lPupil.hide()
                self.__lod250rPupil.hide()

    def exitEyelidsClosed(self):
        return None

    def enterEyelidsSurprised(self):
        if not self.__eyes.isEmpty() and ToonHead.EyesSurprised:
            self.__eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.hide()
            if self.__eyelashClosed:
                self.__eyelashClosed.hide()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__muzzle:
                self.__muzzle.setTexture(ToonHead.MuzzleSurprised, 1)
            if self.__lpupil:
                self.__lpupil.show()
                self.__rpupil.show()
            if self.__lod500lPupil:
                self.__lod500lPupil.show()
                self.__lod500rPupil.show()
            if self.__lod250lPupil:
                self.__lod250lPupil.show()
                self.__lod250rPupil.show()

    def exitEyelidsSurprised(self):
        if self.__muzzle:
            self.__muzzle.setTexture(ToonHead.Muzzle, 1)

    def setupMuzzles(self, style):
        self.__muzzles = []
        self.__surpriseMuzzles = []
        self.__angryMuzzles = []
        self.__sadMuzzles = []
        self.__smileMuzzles = []
        self.__laughMuzzles = []
        def hideAddNonEmptyItemToList(item, list):
            if not item.isEmpty():
                item.hide()
                list.append(item)

        def hideNonEmptyItem(item):
            if not item.isEmpty():
                item.hide()

        if self.hasLOD():
            for lodName in self.getLODNames():
                animal = style.getAnimal()
                if animal != 'dog':
                    muzzle = self.find('**/' + lodName + '/**/muzzle*neutral')
                else:
                    muzzle = self.find('**/' + lodName + '/**/muzzle*')
                    if lodName == '1000' or lodName == '500':
                        filePrefix = DogMuzzleDict[style.head]
                        muzzles = loader.loadModel('phase_3' + filePrefix + lodName)
                        if base.config.GetBool('want-new-anims', 1):
                            if not self.find('**/' + lodName + '/**/__Actor_head/def_head').isEmpty():
                                muzzles.reparentTo(self.find('**/' + lodName + '/**/__Actor_head/def_head'))
                            else:
                                muzzles.reparentTo(self.find('**/' + lodName + '/**/joint_toHead'))
                        elif self.find('**/' + lodName + '/**/joint_toHead'):
                            muzzles.reparentTo(self.find('**/' + lodName + '/**/joint_toHead'))
                surpriseMuzzle = self.find('**/' + lodName + '/**/muzzle*surprise')
                angryMuzzle = self.find('**/' + lodName + '/**/muzzle*angry')
                sadMuzzle = self.find('**/' + lodName + '/**/muzzle*sad')
                smileMuzzle = self.find('**/' + lodName + '/**/muzzle*smile')
                laughMuzzle = self.find('**/' + lodName + '/**/muzzle*laugh')
                self.__muzzles.append(muzzle)
                hideAddNonEmptyItemToList(surpriseMuzzle, self.__surpriseMuzzles)
                hideAddNonEmptyItemToList(angryMuzzle, self.__angryMuzzles)
                hideAddNonEmptyItemToList(sadMuzzle, self.__sadMuzzles)
                hideAddNonEmptyItemToList(smileMuzzle, self.__smileMuzzles)
                hideAddNonEmptyItemToList(laughMuzzle, self.__laughMuzzles)
        else:
            if style.getAnimal() != 'dog':
                muzzle = self.find('**/muzzle*neutral')
            else:
                muzzle = self.find('**/muzzle*')
                filePrefix = DogMuzzleDict[style.head]
                muzzles = loader.loadModel('phase_3' + filePrefix + '1000')
                if base.config.GetBool('want-new-anims', 1):
                    if not self.find('**/def_head').isEmpty():
                        muzzles.reparentTo(self.find('**/def_head'))
                    else:
                        muzzles.reparentTo(self.find('**/joint_toHead'))
                else:
                    muzzles.reparentTo(self.find('**/joint_toHead'))
            surpriseMuzzle = self.find('**/muzzle*surprise')
            angryMuzzle = self.find('**/muzzle*angry')
            sadMuzzle = self.find('**/muzzle*sad')
            smileMuzzle = self.find('**/muzzle*smile')
            laughMuzzle = self.find('**/muzzle*laugh')
            self.__muzzles.append(muzzle)
            hideAddNonEmptyItemToList(surpriseMuzzle, self.__surpriseMuzzles)
            hideAddNonEmptyItemToList(angryMuzzle, self.__angryMuzzles)
            hideAddNonEmptyItemToList(sadMuzzle, self.__sadMuzzles)
            hideAddNonEmptyItemToList(smileMuzzle, self.__smileMuzzles)
            hideAddNonEmptyItemToList(laughMuzzle, self.__laughMuzzles)

    def getMuzzles(self):
        return self.__muzzles

    def getSurpriseMuzzles(self):
        return self.__surpriseMuzzles

    def getAngryMuzzles(self):
        return self.__angryMuzzles

    def getSadMuzzles(self):
        return self.__sadMuzzles

    def getSmileMuzzles(self):
        return self.__smileMuzzles

    def getLaughMuzzles(self):
        return self.__laughMuzzles

    def showNormalMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__muzzles)):
            self.__muzzles[muzzleNum].show()

    def hideNormalMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__muzzles)):
            self.__muzzles[muzzleNum].hide()

    def showAngryMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__angryMuzzles)):
            self.__angryMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideAngryMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__angryMuzzles)):
            self.__angryMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSadMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__sadMuzzles)):
            self.__sadMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSadMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__sadMuzzles)):
            self.__sadMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSmileMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__smileMuzzles)):
            self.__smileMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSmileMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__smileMuzzles)):
            self.__smileMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showLaughMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__laughMuzzles)):
            self.__laughMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideLaughMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__laughMuzzles)):
            self.__laughMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSurpriseMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__surpriseMuzzles)):
            self.__surpriseMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSurpriseMuzzle(self):
        if self.isIgnoreCheesyEffect():
            return
        for muzzleNum in range(len(self.__surpriseMuzzles)):
            self.__surpriseMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def isIgnoreCheesyEffect(self):
        if hasattr(self, 'savedCheesyEffect'):
            if self.savedCheesyEffect == 10 or self.savedCheesyEffect == 11 or self.savedCheesyEffect == 12 or self.savedCheesyEffect == 13 or self.savedCheesyEffect == 14:
                return True
        return False
示例#29
0
class Walk(StateData):
    notify = directNotify.newCategory("Walk")

    def __init__(self, doneEvent):
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('Walk', [
            State('off', self.enterOff, self.exitOff, ['walking', 'deadWalking']),
            State('walking', self.enterWalking, self.exitWalking),
            State('deadWalking', self.enterDeadWalking, self.exitDeadWalking)],
            'off', 'off')
        self.fsm.enterInitialState()

    def load(self):
        pass

    def unload(self):
        del self.fsm

    def enter(self):
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()
        base.localAvatar.startBlink()
        base.localAvatar.attachCamera()
        base.localAvatar.startSmartCamera()
        base.localAvatar.collisionsOn()
        base.localAvatar.enableAvatarControls()

    def exit(self):
        base.localAvatar.lastState = None
        self.fsm.request('off')
        base.localAvatar.disableAvatarControls()
        base.localAvatar.detachCamera()
        base.localAvatar.stopSmartCamera()
        base.localAvatar.stopPosHprBroadcast()
        base.localAvatar.stopBlink()
        base.localAvatar.collisionsOff()
        base.localAvatar.controlManager.placeOnFloor()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterWalking(self):
        if base.localAvatar.getHealth() > 0:
            base.localAvatar.startTrackAnimToSpeed()
            base.localAvatar.setWalkSpeedNormal()
        else:
            self.fsm.request('deadWalking')

    def exitWalking(self):
        base.localAvatar.stopTrackAnimToSpeed()

    def enterDeadWalking(self):
        base.localAvatar.startTrackAnimToSpeed()
        base.localAvatar.setWalkSpeedSlow()
        base.taskMgr.add(self.__watchForPositiveHP, base.localAvatar.uniqueName('watchforPositiveHP'))

    def __watchForPositiveHP(self, task):
        if base.localAvatar.getHealth() > 0:
            self.fsm.request('walking')
            return task.done
        return task.cont

    def exitDeadWalking(self):
        base.taskMgr.remove(base.localAvatar.uniqueName('watchforPositiveHP'))
        base.localAvatar.stopTrackAnimToSpeed()
示例#30
0
class DynamicHuman(HumanBase.HumanBase, Biped.Biped):
    notify = DirectNotifyGlobal.directNotify.newCategory('Human')

    def __init__(self, other = None):
        Biped.Biped.__init__(self, other, HumanAnimationMixer)
        self.model = None
        self.zombie = False
        self.crazyColorSkin = False
        self.crazyColorSkinIndex = 0
        self.flattenPending = None
        if __dev__:
            self.optimizeLOD = base.config.GetBool('optimize-avatar-lod', 1)
        else:
            self.optimizeLOD = 0
        self.master = 0
        self.loaded = 0
        self.playingRate = None
        self.shadowFileName = 'models/misc/drop_shadow'
        self.setFont(PiratesGlobals.getInterfaceFont())
        self._DynamicHuman__blinkName = 'blink-' + str(self.this)
        self.eyeLids = None
        self.eyeBalls = None
        self.eyeIris = None
        self.reducedAnimList = None
        self.headNode = None
        self.extraNode = None
        self.scaleNode = None
        self.rootNode = None
        self.floorOffsetZ = 0.0
        self.headFudgeHpr = Vec3(0, 0, 0)
        self.randGen = random.Random()
        self.randGen.seed(random.random())
        self.eyeFSM = ClassicFSM('eyeFSM', [
            State('off', self.enterEyeFSMOff, self.exitEyeFSMOff, [
                'open',
                'closed']),
            State('open', self.enterEyeFSMOpen, self.exitEyeFSMOpen, [
                'closed',
                'off']),
            State('closed', self.enterEyeFSMClosed, self.exitEyeFSMClosed, [
                'open',
                'off'])], 'off', 'off')
        self.eyeFSM.enterInitialState()
        self.isPaid = True
        if other != None:
            self.copyHuman(other)



    def removeCopiedNodes(self):
        self.dropShadow = self.find('**/drop_shadow*')
        if not self.dropShadow.isEmpty():
            self.deleteDropShadow()



    def flattenHuman(self):
        self.deleteNametag3d()
        self.getWeaponJoints()


    def _DynamicHuman__doneFlattenHuman(self, models):
        self.flattenPending = None
        self.getWeaponJoints()


    def copyHuman(self, other):
        self.gender = other.gender
        self.loaded = other.loaded
        self.type = other.type
        self.loadAnimatedHead = other.loadAnimatedHead
        self.flattenHuman()
        self.model = None


    def delete(self):
        self.Human_deleted = 1
        taskMgr.remove(self._DynamicHuman__blinkName)
        if self.dropShadow and not self.dropShadow.isEmpty():
            self.deleteDropShadow()

        del self.eyeFSM
        self.controlShapes = None
        self.sliderNames = None
        if self.model:
            self.model.delete()
            del self.model

        Biped.Biped.delete(self)



    def isDeleted(self):

        try:
            if self.Human_deleted == 1:
                return True
        except:
            return False



    def setupExtraNodes(self):
        idx = 0
        if self.gender == 'f':
            idx = 1

        jointName = 'def_head01'
        jointNameExtra = 'def_extra_jt'
        jointNameScale = 'def_scale_jt'
        lods = self.getLODNames()
        self.headNode = self.controlJoint(None, 'legs', jointName, lods[0])
        self.extraNode = self.controlJoint(None, 'legs', jointNameExtra, lods[0])
        self.scaleNode = self.controlJoint(None, 'legs', jointNameScale, lods[0])
        self.rootNode = self.getLOD('2000').find('**/dx_root')
        self.floorOffsetZ = self.rootNode.getZ()
        for lod in lods[1:]:
            self.controlJoint(self.headNode, 'legs', jointName, lod)
            self.controlJoint(self.extraNode, 'legs', jointNameExtra, lod)
            self.controlJoint(self.scaleNode, 'legs', jointNameScale, lod)
            exposedHeadJoint = self.getLOD(lod).find('**/def_head01')
            if not exposedHeadJoint.isEmpty():
                exposedHeadJoint.removeNode()
                continue

        self.headNode.setScale(HeadScales[idx][self.style.getBodyShape()])
        self.setGlobalScale(self.calcBodyScale())


    def undoExtraNodes(self):
        jointNameExtra = 'def_extra_jt'
        jointNameScale = 'def_scale_jt'
        joints = self.findAllMatches('**/*' + jointNameExtra)
        if not joints.isEmpty():
            joints.detach()
            joints.clear()

        if self.headNode:
            self.headNode.removeNode()
            self.headNode = None
            self.extraNode.removeNode()
            self.extraNode = None

        joints = self.findAllMatches('**/*' + jointNameScale)
        if not joints.isEmpty():
            joints.detach()
            joints.clear()

        if self.scaleNode:
            self.scaleNode.removeNode()
            self.scaleNode = None
            self.rootNode = None



    def fixEyes(self):
        self.eyeLids = { }
        self.eyeBalls = { }
        self.eyeIris = { }
        for lodName in self.getLODNames():
            geom = self.getPart('head', lodName)
            self.eyeLids[lodName] = geom.findAllMatches('**/*eyelid*')
            self.eyeBalls[lodName] = geom.findAllMatches('**/eye_ball*')
            self.eyeIris[lodName] = geom.findAllMatches('**/eye_iris*')
            self.eyeLids[lodName].stash()
            self.eyeBalls[lodName].unstash()
            self.eyeIris[lodName].unstash()



    def generateFaceTexture(self):
        faceTextureIdx = self.style.head.texture
        if self.gender == 'f':
            face_textures = PirateFemale.face_textures
        else:
            face_textures = PirateMale.face_textures
        tex_name = self.getTrySafe(face_textures, faceTextureIdx)
        if tex_name != None:
            tex = self.model.faceTextures.findTexture(tex_name)
            if tex == None:
                return None

        else:
            return None
        for lodName in self.getLODNames():
            self.findAllMatches('**/body_master_face').setTexture(tex, 1)



    def generateSkinColor(self):
        skinColor = self.style.getSkinColor()
        self.model.faces[0].setColorScale(skinColor)
        if self.model.newAvatars:
            self.model.currentBody.setColorScale(skinColor)
        else:
            numPaths = self.model.body.getNumPaths()
            if self.zombie:
                self.model.body.setColorScale(Vec4(1, 1, 1, 1))
            else:
                self.model.body.setColorScale(skinColor)


    def generateSkinTexture(self):
        bodyTextureIdx = self.style.body.skin
        if self.zombie:
            if self.gender == 'f':
                bodyTextureIdx = PirateFemale.ZOMB_BODY_TEXTURE
            else:
                bodyTextureIdx = PirateMale.ZOMB_BODY_TEXTURE

        if self.gender == 'f':
            body_textures = PirateFemale.body_textures[self.style.body.shape]
        else:
            body_textures = PirateMale.body_textures[self.style.body.shape]
        tex_name = self.getTrySafe(body_textures, bodyTextureIdx)
        if tex_name != None:
            tex = self.model.bodyTextures.findTexture(tex_name)
        else:
            return None
        for parts in self.model.bodys:
            parts.setTexture(tex, 1)



    def generateHairColor(self, colorName = None, colorModel = None):
        self.model.setHairBaseColor()


    def getTrySafe(self, list, idx):

        try:
            if type(idx) == str:
                lookup = idx.split('_cut')[0]
            else:
                lookup = idx
            return list[lookup]
        except:
            return None



    def generateEyesTexture(self):
        eyesTextureIdx = self.style.head.eyes.color
        if self.gender == 'f':
            eye_iris_textures = PirateFemale.eye_iris_textures
        else:
            eye_iris_textures = PirateMale.eye_iris_textures
        tex_name = self.getTrySafe(eye_iris_textures, eyesTextureIdx)
        if tex_name != None:
            tex = self.eyeIrisTextures.findTexture(tex_name)
        else:
            return None
        self.model.irises.setTexture(tex, 1)


    def generateHatColor(self):
        style = self.style
        if self.zombie:
            style = self.model.dnaZomb

        hatColor = style.lookupHatColor()
        geom = self.getGeomNode()
        geom.findAllMatches('**/hat_band*').setColorScale(hatColor)


    def generateClothesColor(self):
        style = self.style
        if self.zombie:
            style = self.model.dnaZomb

        clothesTopColor = style.lookupClothesTopColor()
        clothesBotColor = style.lookupClothesBotColor()
        geom = self.getGeomNode()
        geom.findAllMatches('**/clothing_layer1_shirt*').setColorScale(clothesTopColor[0])
        geom.findAllMatches('**/clothing_layer2_vest*').setColorScale(clothesTopColor[1])
        geom.findAllMatches('**/clothing_layer3_coat*').setColorScale(clothesTopColor[2])
        geom.findAllMatches('**/clothing_layer1_pant*').setColorScale(clothesBotColor[0])
        geom.findAllMatches('**/clothing_layer2_belt*').setColorScale(clothesBotColor[1])
        geom.findAllMatches('**/clothing_layer1_shoe*').setColorScale(clothesBotColor[2])


    def generateColor(self):
        self.generateSkinColor()
        self.generateHairColor()
        self.generateHatColor()


    def makeAnimDict(self, gender, animNames):
        self.animDict = []
        for currAnim in animNames:
            anim = animNames.get(currAnim)
            for currAnimName in anim:
                self.animTable.append([
                    currAnimName,
                    currAnimName])


        self.reducedAnimList = self.animDict


    def forceLoadAnimDict(self):
        for anim in self.animDict:
            self.getAnimControls(anim[0])



    def createAnimDict(self, customList = None):
        if self.gender == 'f':
            filePrefix = 'models/char/f'
            genderPrefix = 'f'
        else:
            filePrefix = 'models/char/m'
            genderPrefix = 'm'
        filePrefix += 'p'
        animList = self.reducedAnimList
        if animList is None:
            animList = AnimListDict[self.type]

        AnimDict.clear()
        for anim in animList:
            animSuffix = ''
            for customAnim in CustomAnimDict[genderPrefix + self.type]:
                if anim[0] == customAnim:
                    animSuffix = '_' + genderPrefix + NewModelDict.get(self.type)
                    break
                    continue

            AnimDict[anim[0]] = filePrefix + '_' + anim[1] + animSuffix

        if self.reducedAnimList is None:
            AnimDict.pop('intro')

        return filePrefix


    def generateBody(self, copy = 1):
        filePrefix = self.createAnimDict()
        lodString = '2000'
        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '2000', copy)
        self.loadAnims(AnimDict, 'modelRoot', 'all')
        if loader.loadModel(filePrefix + '_' + '1000', allowInstance = True) != None:
            lodString = '1000'

        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '1000', copy)
        if loader.loadModel(filePrefix + '_' + '500', allowInstance = True) != None:
            lodString = '500'

        self.loadModel(filePrefix + '_' + lodString, 'modelRoot', '500', copy)
        self.makeSubpart('head', [
            'zz_head01'], [])
        self.makeSubpart('torso', [
            'zz_spine01'], [
            'zz_head01'])
        self.makeSubpart('legs', [
            'dx_root'], [
            'zz_spine01'])
        self.setSubpartsComplete(True)
        self.getWeaponJoints()
        self.eyeIrisTextures = loader.loadModel('models/misc/eye_iris.bam')


    def refreshBody(self):
        if self.style.getGender() == 'f':
            gender = 1
            cjs = FemaleBodyShapeControlJoints
            matrix = FemaleBodyShapeControlJointMatrix
        else:
            gender = 0
            cjs = MaleBodyShapeControlJoints
            matrix = MaleBodyShapeControlJointMatrix
        type = self.style.getBodyShape()
        filePrefix = self.createAnimDict()
        self.loadAnims(AnimDict, 'modelRoot', 'all')
        for jointName in cjs:
            joint = self.find('**/*' + jointName)
            vector = matrix[jointName][type]
            if jointName.find('def') != -1:
                joint.setScale(vector)
                continue
            joint.setPos(vector)

        self.headNode.setScale(HeadScales[gender][self.style.getBodyShape()])
        self.setGlobalScale(self.calcBodyScale())
        self.createAnimDict()
        self.stop(self.getCurrentAnim())
        self.loop(self.getCurrentAnim())


    def setLODs(self):
        self.setLODNode()
        avatarDetail = base.config.GetString('avatar-detail', 'high')
        if avatarDetail == 'high':
            dist = [
                0,
                20,
                80,
                280]
        elif avatarDetail == 'med':
            dist = [
                0,
                10,
                40,
                280]
        elif avatarDetail == 'low':
            dist = [
                0,
                5,
                20,
                280]
        else:
            raise StandardError, 'Invalid avatar-detail: %s' % avatarDetail
        self.addLOD(2000, dist[1], dist[0])
        self.addLOD(1000, dist[2], dist[1])
        self.addLOD(500, dist[3], dist[2])
        if self.optimizeLOD:
            lowLOD = self.getLOD('500')
            lowLOD.setTextureOff(1000)
            lowLOD.setTransparency(0, 1000)

        self.getLODNode().setCenter(Point3(0, 0, 5))


    def showLOD(self, lodName):
        if not self.model.loaded:
            self.model.setupHead(lodName)
            self.model.setupBody(lodName)
            self.model.setupClothing(lodName)
            if self.master:
                self.model.setupSelectionChoices('NPC')

            self.model.loaded = 1

        self.model.setFromDNA()
        self.generateEyesTexture()
        if self.optimizeLOD:
            self.optimizeLowLOD()

        self.generateColor()


    def loadHuman(self, gender = 'm', other = None):
        if other:
            pirate = other
            pirate.style = self.style
        else:
            pirate = self
        pirate.gender = gender
        if self.loaded:
            return None

        if pirate.gender == 'f':
            pirate.type = BodyDefs.femaleFrames[pirate.style.getBodyShape()]
            controlShapes = PirateFemale.ControlShapes
            sliderNames = PirateFemale.SliderNames
        else:
            pirate.type = BodyDefs.maleFrames[pirate.style.getBodyShape()]
            controlShapes = PirateMale.ControlShapes
            sliderNames = PirateMale.SliderNames
        if not pirate.loaded:
            pirate.setLODs()
            pirate.loadAnimatedHead = True
            pirate.generateBody()
            if pirate.gender == 'f':
                pirate.model = PirateFemale.PirateFemale(pirate, pirate.style)
                self.pirateFemale = PirateFemale.PirateFemale(pirate, pirate.style)
            else:
                pirate.model = PirateMale.PirateMale(pirate, pirate.style)
                self.pirateMale = PirateMale.PirateMale(pirate, pirate.style)
            if base.config.GetBool('debug-dynamic-human', 0):
                pirate.model.newAvatars = True
            else:
                pirate.model.newAvatars = False
            pirate.faceAwayFromViewer()
            pirate.fixEyes()
        else:
            pirate.model.dna = pirate.style
            pirate.reducedAnimList = self.reducedAnimList
            pirate.createAnimDict()
            pirate.loadAnims(AnimDict, 'modelRoot', 'all')
        self.lods = pirate.getLODNames()
        if pirate.gender == 'f':
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 1
        else:
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 0
        pirate.zombie = self.zombie
        pirate.showLOD(2000)
        pirate.loaded = 1
        self.model = pirate.model
        if pirate.zombie:
            pirate.showZombie()
        else:
            pirate.showNormal()
        if hasattr(self, 'motionFSM'):
            self.motionFSM.setAvatar(self)

        self.controlShapes = controlShapes
        self.sliderNames = sliderNames
        if other:
            self.copyActor(other)
            self.fixEyes()
            self.copyHuman(other)
            self.undoExtraNodes()

        self.setupExtraNodes()
        self.applyBodyShaper()
        self.applyHeadShaper()
        if other:
            pirate.zombie = 0
            pirate.showNormal()
            pirate.unloadAnims(AnimDict, None, None)
            pirate.removeAnimControlDict()
            pirate.reducedAnimList = None

        self.initializeMiscNodes()
        self.startBlink()


    def initializeMiscNodes(self):
        self.initializeNametag3d()
        self.initializeDropShadow()
        if self.getLOD('2000') == None:
            return None

        exposedHeadJoint = self.getLOD('2000').find('**/def_head01')
        if not exposedHeadJoint.isEmpty():
            idx = 0
            if self.gender == 'f':
                idx = 1

            exposedHeadJoint.setScale(1)
            self.headNode.reparentTo(exposedHeadJoint)
            self.headNode.setScale(HeadScales[idx][self.style.getBodyShape()])



    def undoControlJoints(self):
        self.getGeomNode().getParent().findAllMatches('def_*').detach()
        self.getGeomNode().getParent().findAllMatches('trs_*').detach()
        self.findAllMatches('def_*').detach()
        self.findAllMatches('trs_*').detach()


    def cleanupHuman(self, gender = 'm'):
        self.eyeFSM.request('off')
        self.undoExtraNodes()
        self.undoControlJoints()
        self.eyeLids = { }
        self.eyeBalls = { }
        self.eyeIris = { }
        self.flush()
        self.loaded = 0
        self.master = 0


    def generateHuman(self, gender = 'm', others = None):
        other = None
        if others:
            if gender == 'f':
                other = others[1]
            else:
                other = others[0]

        if other and not (other.master) and other.loaded:
            other.cleanupHuman()
        elif self.loaded:
            self.cleanupHuman()

        self.loadHuman(self.style.gender, other)
        if self.isLocal():
            self.renderReflection = True

        self.setRenderReflection()
        self.disableMixing()
        self.enableMixing()

    generateHuman = quickProfile('loadHuman')(generateHuman)

    def getShadowJoint(self):
        return self


    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('legs', lodName)
            joint = bundle.findChild('name_tag')
            if joint:
                joints.append(joint)
                continue

        return joints


    def _DynamicHuman__blinkOpenEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() == 'closed':
            self.eyeFSM.request('open')

        r = self.randGen.random()
        if r < 0.10000000000000001:
            t = 0.20000000000000001
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self._DynamicHuman__blinkCloseEyes, self._DynamicHuman__blinkName)
        return Task.done


    def _DynamicHuman__blinkCloseEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() != 'open':
            taskMgr.doMethodLater(4.0, self._DynamicHuman__blinkCloseEyes, self._DynamicHuman__blinkName)
        else:
            self.eyeFSM.request('closed')
            taskMgr.doMethodLater(0.125, self._DynamicHuman__blinkOpenEyes, self._DynamicHuman__blinkName)
        return Task.done


    def startBlink(self):
        taskMgr.remove(self._DynamicHuman__blinkName)
        if self.eyeLids:
            self.openEyes()

        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1, self._DynamicHuman__blinkCloseEyes, self._DynamicHuman__blinkName)


    def stopBlink(self):
        taskMgr.remove(self._DynamicHuman__blinkName)
        if self.eyeLids:
            self.eyeFSM.request('open')



    def closeEyes(self):
        self.eyeFSM.request('closed')


    def openEyes(self):
        self.eyeFSM.request('open')


    def enterEyeFSMOff(self):
        pass


    def exitEyeFSMOff(self):
        pass


    def enterEyeFSMOpen(self):
        for lodName in self.getLODNames():
            if not self.eyeLids[lodName].isEmpty():
                self.eyeLids[lodName].hide()
                self.eyeBalls[lodName].show()
                self.eyeIris[lodName].show()
                continue



    def exitEyeFSMOpen(self):
        pass


    def enterEyeFSMClosed(self):
        return None
        for lodName in self.getLODNames():
            if not self.eyeLids[lodName].isEmpty():
                self.eyeLids[lodName].show()
                self.eyeBalls[lodName].hide()
                self.eyeIris[lodName].hide()
                continue



    def exitEyeFSMClosed(self):
        pass


    def setControlValue(self, r, name):
        if self.style.getGender() == 'f':
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixI = FemaleHeadShapeInitialControlJointMatrix
        else:
            matrixF = MaleHeadShapeControlJointMatrix
            matrixI = MaleHeadShapeInitialControlJointMatrix
        shapes = self.controlShapes
        ctl = shapes[name]
        slider = ctl[0]
        if r < 0.0:
            if len(ctl) > 1:
                slider = ctl[1]


        for i in range(0, len(slider)):
            jointName = slider[i][0]
            jointCtls = self.findAllMatches(jointName)
            posI = matrixI[jointName][0]
            hprI = matrixI[jointName][1]
            sclI = matrixI[jointName][2]
            posF = VBase3(posI[0], posI[1], posI[2])
            hprF = VBase3(hprI[0], hprI[1], hprI[2])
            sclF = VBase3(sclI[0], sclI[1], sclI[2])
            self.notify.debug('scv: %s initial %s' % (jointName, posI))
            dr = slider[i][4] * r
            ctl[0][i][5] = dr
            posDelta = VBase3(0, 0, 0)
            hprDelta = VBase3(0, 0, 0)
            sclDelta = VBase3(0, 0, 0)
            for sliderIdx in xrange(0, len(matrixF[jointName])):
                sliderName = matrixF[jointName][sliderIdx]
                jointSet = shapes[sliderName][0]
                for jointIdx in xrange(0, len(jointSet)):
                    if jointSet[jointIdx][0] == jointName:
                        if jointSet[jointIdx][1] == TX:
                            posDelta.setX(posDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == TY:
                            posDelta.setY(posDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == TZ:
                            posDelta.setZ(posDelta.getZ() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RX:
                            hprDelta.setX(hprDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RY:
                            hprDelta.setY(hprDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == RZ:
                            hprDelta.setZ(hprDelta.getZ() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SX:
                            if r < 0.0:
                                sclDelta.setX(sclDelta.getX() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setX(sclDelta.getX() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SY:
                            if r < 0.0:
                                sclDelta.setY(sclDelta.getY() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setY(sclDelta.getY() + jointSet[jointIdx][5])
                        elif jointSet[jointIdx][1] == SZ:
                            if r < 0.0:
                                sclDelta.setZ(sclDelta.getZ() + jointSet[jointIdx][5] / jointSet[jointIdx][2])
                            else:
                                sclDelta.setZ(sclDelta.getZ() + jointSet[jointIdx][5])
                        else:
                            self.notify.warning('scv:wrong element = %s' % jointSet[jointIdx][1])
                    jointSet[jointIdx][1] == TX


            self.notify.debug('scv: %s composite posDelta = %s' % (jointName, posDelta))
            posF.setX(posI[0] + posDelta[0])
            posF.setY(posI[1] + posDelta[1])
            posF.setZ(posI[2] + posDelta[2])
            self.notify.debug('scv: %s final posDelta%s' % (jointName, posF))
            self.notify.debug('scv: %s composite hprDelta = %s' % (jointName, hprDelta))
            hprF.setX(hprI[0] + hprDelta[0])
            hprF.setY(hprI[1] + hprDelta[1])
            hprF.setZ(hprI[2] + hprDelta[2])
            self.notify.debug('scv: %s final hprDelta%s' % (jointName, hprF))
            self.notify.debug('scv: %s composite sclDelta = %s' % (jointName, sclDelta))
            sclF.setX(sclI[0] + sclDelta[0])
            sclF.setY(sclI[1] + sclDelta[1])
            sclF.setZ(sclI[2] + sclDelta[2])
            self.notify.debug('scv: %s final sclDelta%s' % (jointName, sclF))
            for j in range(0, jointCtls.getNumPaths()):
                jointCtl = jointCtls[j]
                jointCtl.setPosHprScale(posF, hprF, sclF)




    def applyBodyShaper(self):
        if self.style.getGender() == 'f':
            cjs = FemaleBodyShapeControlJoints
            matrix = FemaleBodyShapeControlJointMatrix
        else:
            cjs = MaleBodyShapeControlJoints
            matrix = MaleBodyShapeControlJointMatrix
        type = self.style.getBodyShape()
        for jointName in cjs:
            for lodName in self.getLODNames():
                if lodName == '2000':
                    joint = self.controlJoint(None, 'legs', jointName, lodName)
                    continue
                joint = self.controlJoint(joint, 'legs', jointName, lodName)

            joint = self.find('**/*' + jointName)
            vector = matrix[jointName][type]
            if jointName.find('def') != -1:
                joint.setScale(vector)
                continue
            joint.setPos(vector)



    def undoBodyShaper(self):
        if self.style.getGender() == 'f':
            cjs = FemaleBodyShapeControlJoints
        else:
            cjs = MaleBodyShapeControlJoints


    def applyHeadShaper(self):
        self.createControlJoints()
        self.initHeadControlShapes()
        self.setHeadControlShapeValues()


    def undoHeadShaper(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
        else:
            cjs = MaleHeadShapeControlJoints


    def createControlJoints(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
        else:
            cjs = MaleHeadShapeControlJoints
        for jointName in cjs:
            for lodName in self.getLODNames():
                if lodName == '2000':
                    joint = self.controlJoint(None, 'legs', jointName, lodName)
                    continue
                if lodName == '1000':
                    continue
                    continue
                if lodName == '500':
                    continue
                    continue




    def initHeadControlShapes(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixI = FemaleHeadShapeInitialControlJointMatrix
        else:
            cjs = MaleHeadShapeControlJoints
            matrixF = MaleHeadShapeControlJointMatrix
            matrixI = MaleHeadShapeInitialControlJointMatrix
        if len(matrixF['initialized']) > 0:
            return None

        initializedMatrixI = len(matrixI['initialized'])
        initializedMatrixF = len(matrixF['initialized'])
        for jointName in cjs:
            transform = TransformState.makeMat(self.getJointTransform('legs', jointName, '2000'))
            pos = Vec3(transform.getPos())
            hpr = Vec3(transform.getHpr())
            scale = Vec3(transform.getScale())
            matrixI[jointName].append(pos)
            matrixI[jointName].append(hpr)
            matrixI[jointName].append(scale)

        matrixI['initialized'].append('initialized')
        shapes = self.controlShapes
        names = self.sliderNames
        for i in xrange(0, len(shapes)):
            slider = shapes[names[i]]
            for k in xrange(0, len(slider[0])):
                slider[0][k][4] = slider[0][k][2]
                if len(slider) > 1:
                    slider[1][k][4] = slider[1][k][2]
                    continue


        for i in xrange(0, len(shapes)):
            slider = shapes[names[i]]
            for k in xrange(0, len(slider[0])):
                jointCtl = slider[0][k]
                jointName = jointCtl[0]
                matrixF[jointName].append(names[i])
                pos = matrixI[jointName][0]
                hpr = matrixI[jointName][1]
                scl = matrixI[jointName][2]

                if jointCtl[1] < 3:
                    posDelta = jointCtl[4] - pos[jointCtl[1]]
                    jointCtl[4] = posDelta
                    if len(slider) > 1:
                        jointCtl = slider[1][k]
                        jointCtl[4] = posDelta

                if len(slider) > 1:
                    if jointCtl[1] > 2 and jointCtl[1] < 6:
                        hprDelta = jointCtl[4] - hpr[jointCtl[1] - 3]
                        jointCtl[4] = hprDelta
                        if len(slider) > 1:
                            jointCtl = slider[1][k]
                            jointCtl[4] = hprDelta

                #if len(slider) > 1:
                    #sclDelta = jointCtl[4] - scl[jointCtl[1] - 6]
                    #jointCtl[4] = sclDelta

                #if len(slider) > 1:
                #    jointCtl = slider[1][k]
                #    jointCtl[4] = sclDelta


        matrixF['initialized'].append('initialized')


    def setHeadControlShapeValues_old(self):
        value = self.style.getHeadSize()
        mappedValue = 0.90000000000000002 + (1 + value) * 0.10000000000000001
        self.extraNode.setScale(2 - mappedValue, mappedValue, 1)
        self.setControlValue(self.style.getHeadWidth(), 'headWidth')
        self.setControlValue(self.style.getHeadHeight(), 'headHeight')
        self.setControlValue(self.style.getHeadRoundness(), 'headRoundness')
        self.setControlValue(self.style.getJawWidth(), 'jawWidth')
        self.setControlValue(self.style.getJawAngle(), 'jawChinAngle')
        self.setControlValue(self.style.getJawChinSize(), 'jawChinSize')
        self.setControlValue(self.style.getJawLength(), 'jawLength')
        self.setControlValue(self.style.getMouthWidth(), 'mouthWidth')
        self.setControlValue(self.style.getMouthLipThickness(), 'mouthLipThickness')
        self.setControlValue(self.style.getCheekFat(), 'cheekFat')
        self.setControlValue(self.style.getBrowProtruding(), 'browProtruding')
        self.setControlValue(self.style.getEyeCorner(), 'eyeCorner')
        self.setControlValue(self.style.getEyeOpeningSize(), 'eyeOpeningSize')
        self.setControlValue(self.style.getEyeBulge(), 'eyeSpacing')
        self.setControlValue(self.style.getNoseBridgeWidth(), 'noseBridgeWidth')
        self.setControlValue(self.style.getNoseNostrilWidth(), 'noseNostrilWidth')
        self.setControlValue(self.style.getNoseLength(), 'noseLength')
        self.setControlValue(self.style.getNoseBump(), 'noseBump')
        self.setControlValue(self.style.getNoseNostrilHeight(), 'noseNostrilHeight')
        self.setControlValue(self.style.getNoseNostrilAngle(), 'noseNostrilAngle')
        self.setControlValue(self.style.getNoseBridgeBroke(), 'noseBridgeBroke')
        self.setControlValue(self.style.getNoseNostrilBroke(), 'noseNostrilBroke')
        self.setControlValue(self.style.getEarScale(), 'earScale')
        self.setControlValue(self.style.getEarFlapAngle(), 'earFlap')
        self.setControlValue(self.style.getEarPosition(), 'earPosition')


    def getGlobalScale(self):
        return self.scaleNode.getScale()


    def setGlobalScale(self, scale):
        self.scaleNode.setScale(scale)
        self.scaleNode.setZ(-(self.floorOffsetZ * (1 - scale)))


    def calcBodyScale(self):
        idx = 0
        if self.gender == 'f':
            idx = 1

        mappedValue = (0.80000000000000004 + (1 + self.style.getBodyHeight()) * 0.20000000000000001) * BodyScales[idx][self.style.getBodyShape()]
        return mappedValue


    def showZombie(self):
        self.model.irises.stash()
        self.model.faces[0].stash()
        self.model.faceZomb.unstash()
        self.generateSkinTexture()


    def showNormal(self):
        self.model.irises.unstash()
        self.model.faces[0].unstash()
        self.model.faceZomb.stash()
        self.generateSkinTexture()


    def takeAwayTexture(self, geoms, omitFace = False):
        emptyRenderState = RenderState.makeEmpty()
        eyeIrisColor = VBase4(0, 0, 0, 1)
        for i in range(0, geoms.getNumPaths()):
            element = geoms[i]
            if 'eye_iris' in element.getName():
                element.setColorScale(eyeIrisColor)
            elif omitFace and 'master_face' in element.getName():
                continue

            element.setTextureOff()
            geom = element.node()
            for j in range(0, geom.getNumGeoms()):
                geom.setGeomState(j, emptyRenderState)




    def optimizeMedLOD(self):
        medLOD = self.getLOD('1000')
        geoms = medLOD.findAllMatches('**/teeth*')
        geoms.stash()
        self.medSkinGone = False
        geoms = medLOD.find('**/body_forearm*')
        if geoms.isEmpty():
            self.medSkinGone = True
            geoms = medLOD.findAllMatches('**/body_*')
            self.takeAwayTexture(geoms, True)

        geoms = medLOD.findAllMatches('**/hair_*')
        self.takeAwayTexture(geoms)
        if self.gender != 'f':
            geoms = medLOD.findAllMatches('**/beard_*')
            self.takeAwayTexture(geoms)
            geoms = medLOD.findAllMatches('**/mustache_*')
            self.takeAwayTexture(geoms)

        geoms = medLOD.findAllMatches('**/eye_*')
        self.takeAwayTexture(geoms)
        geoms = medLOD.findAllMatches('**/clothing_layer2_belt_*')
        self.takeAwayTexture(geoms)
        geoms = medLOD.findAllMatches('**/clothing_layer1_shoe_*')
        self.takeAwayTexture(geoms)


    def optimizeLowLOD(self):
        lowLOD = self.getLOD('500')
        geoms = lowLOD.findAllMatches('**/teeth*')
        geoms.stash()
        geoms = lowLOD.findAllMatches('**/+GeomNode')
        self.takeAwayTexture(geoms)


    def setHeadControlShapeValues(self):
        value = self.style.getHeadSize()
        mappedValue = 0.90000000000000002 + (1 + value) * 0.10000000000000001
        self.extraNode.setScale(2 - mappedValue, mappedValue, 1)
        self.setControlValue_new(self.style.getHeadWidth(), 'headWidth')
        self.setControlValue_new(self.style.getHeadHeight(), 'headHeight')
        self.setControlValue_new(self.style.getHeadRoundness(), 'headRoundness')
        self.setControlValue_new(self.style.getJawWidth(), 'jawWidth')
        self.setControlValue_new(self.style.getJawAngle(), 'jawChinAngle')
        self.setControlValue_new(self.style.getJawChinSize(), 'jawChinSize')
        self.setControlValue_new(self.style.getJawLength(), 'jawLength')
        self.setControlValue_new(self.style.getMouthWidth(), 'mouthWidth')
        self.setControlValue_new(self.style.getMouthLipThickness(), 'mouthLipThickness')
        self.setControlValue_new(self.style.getCheekFat(), 'cheekFat')
        self.setControlValue_new(self.style.getBrowProtruding(), 'browProtruding')
        self.setControlValue_new(self.style.getEyeCorner(), 'eyeCorner')
        self.setControlValue_new(self.style.getEyeOpeningSize(), 'eyeOpeningSize')
        self.setControlValue_new(self.style.getEyeBulge(), 'eyeSpacing')
        self.setControlValue_new(self.style.getNoseBridgeWidth(), 'noseBridgeWidth')
        self.setControlValue_new(self.style.getNoseNostrilWidth(), 'noseNostrilWidth')
        self.setControlValue_new(self.style.getNoseLength(), 'noseLength')
        self.setControlValue_new(self.style.getNoseBump(), 'noseBump')
        self.setControlValue_new(self.style.getNoseNostrilHeight(), 'noseNostrilHeight')
        self.setControlValue_new(self.style.getNoseNostrilAngle(), 'noseNostrilAngle')
        self.setControlValue_new(self.style.getNoseBridgeBroke(), 'noseBridgeBroke')
        self.setControlValue_new(self.style.getNoseNostrilBroke(), 'noseNostrilBroke')
        self.setControlValue_new(self.style.getEarScale(), 'earScale')
        self.setControlValue_new(self.style.getEarFlapAngle(), 'earFlap')
        self.setControlValue_new(self.style.getEarPosition(), 'earPosition')
        self.postProcess_setHeadControlShapeValues()


    def setControlValue_new(self, r, name):
        ctl = self.controlShapes[name]
        zeroindex = ctl[0]
        sliders = zeroindex
        if r < 0.0:
            if len(ctl) > 1:
                sliders = ctl[1]


        for i in range(0, len(sliders)):
            zeroindex[i][5] = sliders[i][4] * r



    def postProcess_setHeadControlShapeValues(self):
        if self.style.getGender() == 'f':
            cjs = FemaleHeadShapeControlJoints
            matrixF = FemaleHeadShapeControlJointMatrix
            matrixI = FemaleHeadShapeInitialControlJointMatrix
        else:
            cjs = MaleHeadShapeControlJoints
            matrixF = MaleHeadShapeControlJointMatrix
            matrixI = MaleHeadShapeInitialControlJointMatrix
        posDelta = VBase3()
        hprDelta = VBase3()
        sclDelta = VBase3()
        fdict2 = {
            0: posDelta.addX,
            1: posDelta.addY,
            2: posDelta.addZ,
            3: hprDelta.addX,
            4: hprDelta.addY,
            5: hprDelta.addZ,
            6: sclDelta.addX,
            7: sclDelta.addY,
            8: sclDelta.addZ }
        for jointName in cjs:
            posDelta.assign(matrixI[jointName][0])
            hprDelta.assign(matrixI[jointName][1])
            sclDelta.assign(matrixI[jointName][2])
            for sliderIdx in xrange(0, len(matrixF[jointName])):
                sliderName = matrixF[jointName][sliderIdx]
                jointSet = self.controlShapes[sliderName][0]
                for sliderJoint in jointSet:
                    if sliderJoint[0] == jointName:
                        fdict2[sliderJoint[1]](sliderJoint[5])
                        continue


            self.find(jointName).setPosHprScale(posDelta, hprDelta, sclDelta)
示例#31
0
class DistributedMinigame(DistributedObject.DistributedObject, Timer.Timer):

    def __init__(self, cr):
        try:
            self.DistributedMinigame_initialized
            return
        except:
            self.DistributedMinigame_initialized = 1

        DistributedObject.DistributedObject.__init__(self, cr)
        Timer.Timer.__init__(self)
        self.headPanels = HeadPanels()
        self.finalScoreUI = FinalScoreGUI()
        self.fsm = ClassicFSM('DistributedMinigame', [State('start', self.enterStart, self.exitStart, ['waitForOthers']),
         State('waitForOthers', self.enterWaitForOthers, self.exitWaitForOthers, ['play']),
         State('play', self.enterPlay, self.exitPlay, ['gameOver']),
         State('gameOver', self.enterGameOver, self.exitGameOver, ['off']),
         State('off', self.enterOff, self.exitOff)], 'off', 'off')
        self.fsm.enterInitialState()
        self.cr = cr
        self.localAv = base.localAvatar
        self.localAvId = self.localAv.doId
        self.musicPath = 'phase_4/audio/bgm/trolley_song.mid'
        self.winSfx = base.loadSfx('phase_4/audio/sfx/MG_win.mp3')
        self.loseSfx = base.loadSfx('phase_4/audio/sfx/MG_lose.mp3')
        self.prizeHigh = base.loadSfx('phase_6/audio/sfx/KART_Applause_1.mp3')
        self.prizeLow = base.loadSfx('phase_6/audio/sfx/KART_Applause_4.mp3')
        self.music = None
        self.description = ''
        self.descDialog = None
        self.winnerPrize = 0
        self.loserPrize = 0
        self.winnerMsg = 'Winner!\nYou have earned: %s'
        self.loserMsg = 'Loser!\nYou have earned: %s'
        self.allWinnerMsgs = ['Nice try!\nYou have earned: %s',
         'Good job!\nYou have earned: %s',
         'Way to go!\nYou have earned: %s',
         'Awesome!\nYou have earned: %s']
        self.timer = None
        self.timeLbl = None
        return

    def enterFinalScores(self):
        self.finalScoreUI.load()
        self.finalScoreUI.showFinalScores()

    def exitFinalScores(self):
        self.finalScoreUI.hideFinalScores()
        self.finalScoreUI.unload()

    def finalScores(self, avIdList, scoreList):
        self.finalScoreUI.handleFinalScores(avIdList, scoreList)

    def generateHeadPanel(self, gender, head, headtype, color, doId, name):
        self.headPanels.generate(gender, head, headtype, color, doId, name)

    def updateHeadPanelValue(self, doId, direction):
        self.headPanels.updateValue(doId, direction)

    def setTimerTime(self, time):
        self.setTime(time)

    def createTimer(self):
        Timer.Timer.load(self)

    def deleteTimer(self):
        Timer.Timer.unload(self)

    def setDescription(self, desc):
        self.description = desc

    def getDescription(self):
        return self.description

    def enterStart(self):
        self.descDialog = GlobalDialog(style=3, message=self.getDescription(), doneEvent='gameDescAck')
        self.acceptOnce('gameDescAck', self.handleDescAck)

    def handleDescAck(self):
        self.d_ready()
        self.fsm.request('waitForOthers')

    def exitStart(self):
        self.ignore('gameDescAck')
        self.descDialog.cleanup()
        del self.descDialog

    def enterWaitForOthers(self):
        self.waitLbl = DirectLabel(text='Waiting for other players...', relief=None, text_fg=(1, 1, 1, 1), text_scale=0.08, text_shadow=(0, 0, 0, 1))
        return

    def exitWaitForOthers(self):
        self.waitLbl.destroy()
        del self.waitLbl

    def setLoserPrize(self, prize):
        self.loserPrize = prize

    def setWinnerPrize(self, prize):
        self.winnerPrize = prize

    def getLoserPrize(self):
        return self.loserPrize

    def getWinnerPrize(self):
        return self.winnerPrize

    def winner(self):
        self.winSfx.play()
        self.localAv.b_setAnimState('happy')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'winner')).start()

    def showPrize(self, amt):
        self.winSfx.play()
        self.localAv.b_setAnimState('happy')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'showPrize', amt)).start()

    def loser(self):
        self.loseSfx.play()
        self.localAv.b_setAnimState('neutral')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'loser')).start()

    def displayGameOver(self, scenario, amt = None):
        if scenario == 'winner':
            msg = self.winnerMsg % self.winnerPrize
            self.prizeHigh.play()
        elif scenario == 'loser':
            msg = self.loserMsg % self.loserPrize
            self.prizeLow.play()
        elif scenario == 'showPrize':
            msg = random.choice(self.allWinnerMsgs) % amt
            self.prizeHigh.play()
        self.gameOverDialog = GlobalDialog(message=msg, style=3, doneEvent='gameOverAck')
        self.acceptOnce('gameOverAck', self.__handleGameOverAck)
        self.gameOverDialog.show()

    def deleteGameOverDialog(self):
        self.ignore('gameOverAck')
        if hasattr(self, 'gameOverDialog'):
            self.gameOverDialog.cleanup()
            del self.gameOverDialog

    def __handleGameOverAck(self):
        self.fsm.requestFinalState()
        Sequence(Func(base.transitions.irisOut, 1.0), Wait(1.2), Func(self.d_leaving), Func(self.headBackToMinigameArea)).start()

    def headBackToMinigameArea(self):
        whereName = ZoneUtil.getWhereName(CIGlobals.MinigameAreaId)
        loaderName = ZoneUtil.getLoaderName(CIGlobals.MinigameAreaId)
        requestStatus = {'zoneId': CIGlobals.MinigameAreaId,
         'hoodId': CIGlobals.MinigameArea,
         'where': whereName,
         'how': 'teleportIn',
         'avId': base.localAvatar.doId,
         'shardId': None,
         'loader': loaderName}
        self.cr.playGame.hood.fsm.request('quietZone', [requestStatus])
        return

    def abort(self):
        self.headBackToMinigameArea()

    def load(self):
        self.fsm.request('start')
        base.transitions.irisIn()

    def d_leaving(self):
        """ Tell the AI that we are leaving. """
        self.sendUpdate('leaving', [])

    def allPlayersReady(self):
        self.fsm.request('play')

    def enterPlay(self):
        self.playMinigameMusic()

    def exitPlay(self):
        self.stopMinigameMusic()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterGameOver(self, winner, winnerDoId, allPrize):
        if winner:
            if self.localAvId in winnerDoId:
                self.winner()
            else:
                self.loser()
        else:
            self.showPrize(allPrize)

    def exitGameOver(self):
        self.deleteGameOverDialog()

    def gameOver(self, winner = 0, winnerDoId = [], allPrize = 0):
        self.fsm.request('gameOver', [winner, winnerDoId, allPrize])

    def setMinigameMusic(self, path):
        self.musicPath = path

    def getMinigameMusic(self):
        return self.musicPath

    def playMinigameMusic(self):
        self.stopMinigameMusic()
        self.music = base.loadMusic(self.musicPath)
        self.music.setLoop(True)
        self.music.setVolume(0.7)
        self.music.play()

    def stopMinigameMusic(self):
        if self.music:
            self.music.stop()
            self.music = None
        return

    def d_ready(self):
        self.sendUpdate('ready', [])

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)

    def disable(self):
        DistributedObject.DistributedObject.disable(self)
        base.localAvatar.setPosHpr(0, 0, 0, 0, 0, 0)
        self.fsm.requestFinalState()
        del self.fsm
        self.winSfx = None
        self.loseSfx = None
        self.prizeHigh = None
        self.prizeLow = None
        self.headPanels.delete()
        self.headPanels = None
        self.finalScoreUI.unload()
        self.finalScoreUI = None
        return
示例#32
0
class ToonHood(Hood.Hood):

    def __init__(self, parentFSM, doneEvent, dnaStore, hoodId):
        Hood.Hood.__init__(self, parentFSM, doneEvent, dnaStore, hoodId)
        self.safeZoneLoader = None
        self.townLoader = None
        self.fsm = ClassicFSM('Hood', [State('off', self.enterOff, self.exitOff),
         State('safeZoneLoader', self.enterSafeZoneLoader, self.exitSafeZoneLoader, ['quietZone', 'townLoader']),
         State('townLoader', self.enterTownLoader, self.exitTownLoader, ['quietZone', 'safeZoneLoader']),
         State('quietZone', self.enterQuietZone, self.exitQuietZone, ['safeZoneLoader', 'townLoader'])], 'off', 'off')
        self.fsm.enterInitialState()
        return

    def loadLoader(self, requestStatus):
        loader = requestStatus['loader']
        if loader == 'safeZoneLoader':
            if self.safeZoneLoader:
                self.loader = self.safeZoneLoader(self, self.fsm.getStateNamed('safeZoneLoader'), self.loaderDoneEvent)
                self.loader.load()
            else:
                self.notify.error('ToonHood.ToonHood.safeZoneLoader cannot be None!' % loader)
        elif loader == 'townLoader':
            if self.townLoader:
                self.loader = self.townLoader(self, self.fsm.getStateNamed('townLoader'), self.loaderDoneEvent)
                self.loader.load(requestStatus['zoneId'])
        else:
            self.notify.error('Unknown loader %s!' % loader)

    def enterTownLoader(self, requestStatus):
        self.acceptOnce(self.loaderDoneEvent, self.handleTownLoaderDone)
        self.loader.enter(requestStatus)
        self.spawnTitleText(requestStatus['zoneId'])

    def exitTownLoader(self):
        taskMgr.remove('titleText')
        self.hideTitleText()
        self.ignore(self.loaderDoneEvent)
        self.loader.exit()
        self.loader.unload()
        del self.loader

    def handleTownLoaderDone(self):
        doneStatus = self.loader.getDoneStatus()
        if self.isSameHood(doneStatus):
            self.fsm.request('quietZone', [doneStatus])
        else:
            self.doneStatus = doneStatus
            messenger.send(self.doneEvent)

    def load(self):
        Hood.Hood.load(self)
        self.whiteFogColor = Vec4(0.8, 0.8, 0.8, 1)
        self.underwaterFogColor = Vec4(0.0, 0.0, 0.6, 1.0)

    def unload(self):
        del self.safeZoneLoader
        Hood.Hood.unload(self)

    def enter(self, requestStatus):
        self.loadLoader(requestStatus)
        Hood.Hood.enter(self, requestStatus)

    def exit(self):
        Hood.Hood.exit(self)

    def setUnderwaterFog(self):
        if base.wantFog:
            self.fog.setColor(self.underwaterColor)
            self.fog.setLinearRange(0.1, 100.0)
            render.setFog(self.fog)
            self.sky.setFog(self.fog)

    def setWhiteFog(self):
        if base.wantFog:
            self.fog.setColor(self.whiteFogColor)
            self.fog.setLinearRange(0.0, 400.0)
            render.clearFog()
            render.setFog(self.fog)
            self.sky.clearFog()
            self.sky.setFog(self.fog)

    def setNoFog(self):
        if base.wantFog:
            render.clearFog()
            self.sky.clearFog()
示例#33
0
class DistributedWeatherCycleAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedWeatherCycleAI')

    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)

        self.fsm = ClassicFSM(self.__class__.__name__, [
            State('off', self.enterOff, self.exitOff, ['morning']),
            State('morning', self.enterMorning, self.exitMorning,
                  ['afternoon']),
            State('afternoon', self.enterAfternoon, self.exitAfternoon,
                  ['evening']),
            State('evening', self.enterEvening, self.exitEvening,
                  ['midnight']),
            State('midnight', self.enterMidnight, self.exitMidnight,
                  ['morning'])
        ], 'off', 'off')

        self.fsm.enterInitialState()
        self.duration = 0

    def generate(self):
        DistributedObjectAI.generate(self)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)

        taskMgr.doMethodLater(self.getDuration(), self.update, 'update-time')

    def delete(self):
        DistributedObjectAI.delete(self)

        taskMgr.remove('update-time')

    def update(self, task):
        self.b_setState(self.fsm.getCurrentState()._State__transitions[0])
        return task.again

    def setState(self, state):
        self.fsm.request(state)

    def d_setState(self, state):
        self.sendUpdate('setState', [state])

    def b_setState(self, state):
        self.setState(state)
        self.d_setState(state)

    def getState(self):
        return self.fsm.getCurrentState()._State__name

    def setDuration(self, duration):
        self.duration = duration

    def d_setDuration(self, duration):
        self.sendUpdate('setDuration', [duration])

    def b_setDuration(self, duration):
        self.setDuration(duration)
        self.d_setDuration(duration)

    def getDuration(self):
        return self.duration

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterMorning(self):
        pass

    def exitMorning(self):
        pass

    def enterAfternoon(self):
        pass

    def exitAfternoon(self):
        pass

    def enterEvening(self):
        pass

    def exitEvening(self):
        pass

    def enterMidnight(self):
        pass

    def exitMidnight(self):
        pass
示例#34
0
class Playground(Place.Place):
    notify = directNotify.newCategory('Playground')

    def __init__(self, loader, parentFSM, doneEvent):
        Place.Place.__init__(self, loader, doneEvent)
        self.fsm = ClassicFSM('Playground', [State('start', self.enterStart, self.exitStart, ['walk',
          'teleportIn',
          'tunnelOut',
          'doorOut']),
         State('teleportIn', self.enterTeleportIn, self.exitTeleportIn, ['walk', 'acknowledgeDeath']),
         State('walk', self.enterWalk, self.exitWalk, ['teleportOut',
          'stop',
          'shtickerBook',
          'died',
          'tunnelIn']),
         State('teleportOut', self.enterTeleportOut, self.exitTeleportOut, ['teleportIn', 'stop']),
         State('stop', self.enterStop, self.exitStop, ['walk',
          'died',
          'station',
          'teleportOut',
          'doorIn']),
         State('shtickerBook', self.enterShtickerBook, self.exitShtickerBook, ['teleportOut', 'walk']),
         State('tunnelOut', self.enterTunnelOut, self.exitTeleportOut, ['walk']),
         State('final', self.enterFinal, self.exitFinal, ['start']),
         State('died', self.enterDied, self.exitDied, ['final']),
         State('station', self.enterStation, self.exitStation, ['teleportOut', 'walk']),
         State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
         State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
         State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
         State('acknowledgeDeath', self.enterAcknowledgeDeath, self.exitAcknowledgeDeath, ['walk'])], 'start', 'final')
        self.parentFSM = parentFSM

    def enter(self, requestStatus):
        Place.Place.enter(self)
        self.fsm.enterInitialState()
        messenger.send('enterPlayground')
        if self.loader.music:
            if self.__class__.__name__ == 'CTPlayground':
                volume = 2.0
            else:
                volume = 0.8
            base.playMusic(self.loader.music, looping=1, volume=volume)
        self.loader.geom.reparentTo(render)
        self.loader.hood.startSky()
        self.zoneId = requestStatus['zoneId']
        if base.cr.playGame.suitManager:
            base.cr.playGame.suitManager.d_requestSuitInfo()
        how = requestStatus['how']
        self.fsm.request(how, [requestStatus])

    def exit(self):
        self.ignoreAll()
        messenger.send('exitPlayground')
        self.loader.geom.reparentTo(hidden)
        self.loader.hood.stopSky()
        if self.loader.music:
            self.loader.music.stop()
        if self.loader.bossBattleMusic:
            self.loader.bossBattleMusic.stop()
        if self.loader.battleMusic:
            self.loader.battleMusic.stop()
        if self.loader.invasionMusic:
            self.loader.invasionMusic.stop()
        if self.loader.tournamentMusic:
            self.loader.tournamentMusic.stop()
        Place.Place.exit(self)

    def load(self):
        Place.Place.load(self)
        self.parentFSM.getStateNamed('playground').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('playground').removeChild(self.fsm)
        del self.parentFSM
        del self.fsm
        self.ignoreAll()
        Place.Place.unload(self)

    def enterStation(self):
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()

    def exitStation(self):
        base.localAvatar.stopPosHprBroadcast()

    def enterWalk(self, teleportIn = 0):
        Place.Place.enterWalk(self, teleportIn)
        if base.localAvatar.zoneId != CIGlobals.RecoverAreaId:
            base.localAvatar.startMonitoringHP()

    def exitWalk(self):
        if base.localAvatar.zoneId != CIGlobals.RecoverAreaId:
            base.localAvatar.stopMonitoringHP()
        Place.Place.exitWalk(self)

    def enterTeleportIn(self, requestStatus):
        if base.localAvatar.getHealth() < 1:
            requestStatus['nextState'] = 'acknowledgeDeath'
        else:
            requestStatus['nextState'] = 'walk'
        x, y, z, h, p, r = base.cr.hoodMgr.getPlaygroundCenterFromId(self.loader.hood.id)
        base.localAvatar.detachNode()
        base.localAvatar.setPosHpr(render, x, y, z, h, p, r)
        Place.Place.enterTeleportIn(self, requestStatus)
示例#35
0
class Toon(Avatar.Avatar, ToonHead, ToonDNA.ToonDNA):
    notify = directNotify.newCategory("Toon")

    def __init__(self, cr, mat=0):
        self.cr = cr
        try:
            self.Toon_initialized
            return
        except:
            self.Toon_initialized = 1
        Avatar.Avatar.__init__(self, mat)
        ToonDNA.ToonDNA.__init__(self)
        ToonHead.__init__(self, cr)
        self.collsSetup = False
        self.forwardSpeed = 0.0
        self.rotateSpeed = 0.0
        self.strafeSpeed = 0.0
        self.avatarType = CIGlobals.Toon
        self.track = None
        self.standWalkRunReverse = None
        self.playingAnim = None
        self.playingRate = None
        self.tag = None
        self.money = 0
        self.lookAtTrack = None
        self.portal1 = None
        self.portal2 = None
        self.spineA = NodePath()
        self.tokenIcon = None
        self.tokenIconIval = None
        self.fallSfx = base.audio3d.loadSfx(
            "phase_4/audio/sfx/MG_cannon_hit_dirt.ogg")
        base.audio3d.attachSoundToObject(self.fallSfx, self)
        self.eyes = loader.loadTexture("phase_3/maps/eyes.jpg",
                                       "phase_3/maps/eyes_a.rgb")
        self.myTaskId = random.uniform(0, 1231231232132131231232)
        self.closedEyes = loader.loadTexture("phase_3/maps/eyesClosed.jpg",
                                             "phase_3/maps/eyesClosed_a.rgb")
        self.soundChatBubble = loader.loadSfx(
            "phase_3/audio/sfx/GUI_balloon_popup.ogg")
        self.shadowCaster = None
        self.accessories = []
        self.chatSoundDict = {}
        self.backpack = None
        self.forceRunSpeed = False
        self.animFSM = ClassicFSM('Toon', [
            State('off', self.enterOff, self.exitOff),
            State('neutral', self.enterNeutral, self.exitNeutral),
            State('swim', self.enterSwim, self.exitSwim),
            State('walk', self.enterWalk, self.exitWalk),
            State('run', self.enterRun, self.exitRun),
            State('bow', self.enterBow, self.exitBow),
            State('openBook', self.enterOpenBook, self.exitOpenBook),
            State('readBook', self.enterReadBook, self.exitReadBook),
            State('closeBook', self.enterCloseBook, self.exitCloseBook),
            State('teleportOut', self.enterTeleportOut, self.exitTeleportOut),
            State('teleportIn', self.enterTeleportIn, self.exitTeleportIn),
            State('died', self.enterDied, self.exitDied),
            State('fallFWD', self.enterFallFWD, self.exitFallFWD),
            State('fallBCK', self.enterFallBCK, self.exitFallBCK),
            State('jump', self.enterJump, self.exitJump),
            State('leap', self.enterLeap, self.exitLeap),
            State('laugh', self.enterLaugh, self.exitLaugh),
            State('happy', self.enterHappyJump, self.exitHappyJump),
            State('shrug', self.enterShrug, self.exitShrug),
            State('hdance', self.enterHDance, self.exitHDance),
            State('wave', self.enterWave, self.exitWave),
            State('scientistEmcee', self.enterScientistEmcee,
                  self.exitScientistEmcee),
            State('scientistWork', self.enterScientistWork,
                  self.exitScientistWork),
            State('scientistGame', self.enterScientistGame,
                  self.exitScientistGame),
            State('scientistJealous', self.enterScientistJealous,
                  self.exitScientistJealous),
            State('cringe', self.enterCringe, self.exitCringe),
            State('conked', self.enterConked, self.exitConked),
            State('win', self.enterWin, self.exitWin),
            State('walkBack', self.enterWalkBack, self.exitWalkBack),
            State('deadNeutral', self.enterDeadNeutral, self.exitDeadNeutral),
            State('deadWalk', self.enterDeadWalk, self.exitDeadWalk),
            State('squish', self.enterSquish, self.exitSquish),
            State('Happy', self.enterHappy, self.exitHappy),
            State('Sad', self.enterSad, self.exitSad),
            State('Swim', self.enterSwim, self.exitSwim)
        ], 'off', 'off')
        animStateList = self.animFSM.getStates()
        self.animFSM.enterInitialState()

        if not hasattr(self, 'uniqueName'):
            self.uniqueName = types.MethodType(uniqueName, self)

        self.activities = {
            ACT_DIE: Die(self),
            ACT_VICTORY_DANCE: VictoryDance(self),
            ACT_TOON_BOW: Bow(self),
            ACT_JUMP: Jump(self)
        }

    def setActivity(self, act, timestamp=0):
        Avatar.Avatar.setActivity(self, act, timestamp)
        if act == ACT_NONE:
            self.animFSM.request("Happy")

    def getUpperBodySubpart(self):
        if self.getAnimal() == "dog":
            return ["torso-top", "head"]

        return ["torso-top"]

    def getLowerBodySubpart(self):
        return ["legs", "torso-pants"]

    def getRightHandNode(self):
        return self.find("**/def_joint_right_hold")

    def getLeftHandNode(self):
        return self.find("**/def_joint_left_hold")

    def getHeadNode(self):
        return self.getPart('head')

    def getEyePoint(self):
        # middle of the head
        return Point3(0, 0, self.getHeight() - (self.getHeadHeight() / 2.0))

    def setForceRunSpeed(self, flag):
        self.forceRunSpeed = flag

    def resetTorsoRotation(self):
        if not self.isEmpty():
            spine = self.find("**/def_spineB")
            if not spine.isEmpty():
                spine.setH(0)
                spine.detachNode()
                self.getPart("legs").setH(0)
                self.releaseJoint("torso", "def_spineB")

    def showAvId(self):
        pass

    def showName(self):
        pass

    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('legs', lodName)
            joint = bundle.findChild('joint_nameTag')
            if joint:
                joints.append(joint)

        return joints

    def enterHappy(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = None
        self.standWalkRunReverse = (('neutral', 1.0), ('walk', 1.0),
                                    ('run', 1.0), ('walk', -1.0),
                                    ('strafe', 1.0), ('strafe', -1.0))
        self.setSpeed(self.forwardSpeed, self.rotateSpeed)

    def exitHappy(self):
        self.standWalkRunReverse = None
        self.stop()

    def enterSad(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'sad'
        self.standWalkRunReverse = (('dneutral', 1.0), ('dwalk', 1.2),
                                    ('dwalk', 1.2), ('dwalk', -1.0))
        self.setSpeed(0, 0)

    def exitSad(self):
        self.standWalkRunReverse = None
        self.stop()
        #if hasattr(self, 'doId'):
        #    if hasattr(base, 'localAvatar'):
        #        if base.localAvatar.doId == self.doId:
        #            self.controlManager.enableAvatarJump()

    def setSpeed(self, forwardSpeed, rotateSpeed, strafeSpeed=0.0):
        if self.forceRunSpeed:
            forwardSpeed = CIGlobals.RunCutOff
        self.forwardSpeed = forwardSpeed
        self.rotateSpeed = rotateSpeed
        self.strafeSpeed = strafeSpeed
        action = None
        if self.standWalkRunReverse != None:

            rotateCutOff = CIGlobals.RotateCutOff if not self.isLocalAvatar(
            ) else CIGlobals.WalkCutOff

            if strafeSpeed < CIGlobals.StrafeCutOff and strafeSpeed > -CIGlobals.StrafeCutOff:
                self.resetTorsoRotation()

            if forwardSpeed >= CIGlobals.RunCutOff:
                action = CIGlobals.RUN_INDEX
            elif forwardSpeed > CIGlobals.WalkCutOff:
                action = CIGlobals.WALK_INDEX
            elif forwardSpeed < -CIGlobals.WalkCutOff:
                action = CIGlobals.REVERSE_INDEX
            elif abs(rotateSpeed) > rotateCutOff:
                action = CIGlobals.WALK_INDEX
            elif abs(strafeSpeed) > CIGlobals.RunCutOff:
                action = CIGlobals.RUN_INDEX
            elif abs(strafeSpeed) > CIGlobals.WalkCutOff:
                action = CIGlobals.WALK_INDEX
            else:
                action = CIGlobals.STAND_INDEX

            if abs(strafeSpeed) > CIGlobals.WalkCutOff:
                spine = self.find("**/def_spineB")

                if spine.isEmpty():
                    spine = self.controlJoint(None, "torso", "def_spineB")

                movementVec = Vec3(strafeSpeed, forwardSpeed, 0)
                movementVec.normalize()
                movementAngle = rad2Deg(
                    math.atan2(movementVec[1], movementVec[0])) - 90.0

                if action == CIGlobals.REVERSE_INDEX:
                    movementAngle -= 180

                spine.setH(-movementAngle)
                self.getPart('legs').setH(movementAngle)

            anim, rate = self.standWalkRunReverse[action]
            if anim != self.playingAnim or rate != self.playingRate or self.forcedTorsoAnim != self.lastForcedTorsoAnim:
                self.playingAnim = anim
                self.playingRate = rate
                self.lastForcedTorsoAnim = self.forcedTorsoAnim

                if self.forcedTorsoAnim is None:
                    self.loop(anim)
                else:

                    # Whatever happens to the legs should also happen on the pants.
                    self.loop(anim, partName='torso-pants')
                    self.loop(anim, partName='legs')
                self.setPlayRate(rate, anim)
        return action

    def enterSquish(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'squish'
        sound = loader.loadSfx('phase_9/audio/sfx/toon_decompress.ogg')
        lerpTime = 0.1
        node = self.getGeomNode().getChild(0)
        origScale = node.getScale()
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('getSquished')
        else:
            name = 'getSquished'
        self.track = Sequence(LerpScaleInterval(node,
                                                lerpTime,
                                                VBase3(2, 2, 0.025),
                                                blendType='easeInOut'),
                              Wait(1.0),
                              Parallel(
                                  Sequence(
                                      Wait(0.4),
                                      LerpScaleInterval(node,
                                                        lerpTime,
                                                        VBase3(1.4, 1.4, 1.4),
                                                        blendType='easeInOut'),
                                      LerpScaleInterval(node,
                                                        lerpTime / 2.0,
                                                        VBase3(0.8, 0.8, 0.8),
                                                        blendType='easeInOut'),
                                      LerpScaleInterval(
                                          node,
                                          lerpTime / 3.0,
                                          origScale,
                                          blendType='easeInOut')),
                                  ActorInterval(self, 'happy', startTime=0.2),
                                  SoundInterval(sound)),
                              name=name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.squishDone,
                        [callback, extraArgs])
        self.track.delayDelete = DelayDelete.DelayDelete(self, name)
        self.track.start(ts)

    def squishDone(self, callback=None, extraArgs=[]):
        self.__doCallback(callback, extraArgs)

    def exitSquish(self):
        if self.track:
            self.ignore(self.track.getName())
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track.finish()
            self.track = None
        self.playingAnim = 'neutral'

    def enterDeadNeutral(self, ts=0, callback=None, extraArgs=[]):
        self.loop('dneutral')

    def exitDeadNeutral(self):
        self.stop()

    def enterDeadWalk(self, ts=0, callback=None, extraArgs=[]):
        self.loop('dwalk')

    def exitDeadWalk(self):
        self.stop()

    def setBackpack(self, pack):
        self.backpack = pack

    def getGhost(self):
        return 0

    def updateChatSoundDict(self):
        self.chatSoundDict['exclaim'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('exclaim'))
        self.chatSoundDict['question'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('question'))
        self.chatSoundDict['short'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('short'))
        self.chatSoundDict['medium'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('med'))
        self.chatSoundDict['long'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('long'))
        self.chatSoundDict['howl'] = base.audio3d.loadSfx(
            self.getToonAnimalNoise('howl'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['exclaim'],
                                         self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['question'],
                                         self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['short'],
                                         self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['medium'],
                                         self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['long'],
                                         self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['howl'],
                                         self.getPart('head'))

    def __actAsGone(self):
        if self.nametag3d:
            self.nametag3d.hide()
        if self.getShadow():
            self.getShadow().hide()
        if self.tokenIcon:
            self.tokenIcon.hide()
        #self.stashBodyCollisions()

    def __restoreHide(self):
        if self.tokenIcon:
            self.tokenIcon.show()
        if self.getShadow():
            self.getShadow().show()
        if self.nametag3d:
            self.nametag3d.show()
        if self.getGeomNode():
            self.getGeomNode().setTransparency(False)
            self.getGeomNode().setAlphaScale(1.0)
            self.getGeomNode().show()
        #self.unstashBodyCollisions()

    def handleGhost(self, flag):
        alpha = 1.0 if not flag else 0.25
        local = self == base.localAvatar
        if flag:
            if self.getAccessLevel() >= base.localAvatar.getAccessLevel():
                # Other staff members at this access level or higher should
                # be able to see this avatar still.
                alpha = 0.25
                #self.stashBodyCollisions()
            elif not local:
                self.getGeomNode().setTransparency(True)
                self.getGeomNode().setColorScale(1.0, 1.0, 1.0, 0.0)
                self.__actAsGone()
        else:
            self.__restoreHide()
        if local:
            self.getGeomNode().setTransparency(flag)
            self.getGeomNode().setColorScale(1.0, 1.0, 1.0, alpha)

    def stopAnimations(self):
        if hasattr(self, 'animFSM'):
            if not self.animFSM.isInternalStateInFlux():
                self.animFSM.request('off')
            else:
                self.notify.warning(
                    "animFSM in flux, state=%s, not requesting off" %
                    self.animFSM.getCurrentState().getName())
        else:
            self.notify.warning("animFSM has been deleted")
        if self.track != None:
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        return

    def disable(self):
        try:
            self.Toon_disabled
        except:
            self.Toon_disabled = 1
            self.ignoreAll()
            self.backpack = None
            self.collsSetup = False
            self.stopAnimations()
            self.removeAdminToken()
            ToonHead.delete(self)
            self.deleteCurrentToon()
            self.chatSoundDict = {}
            Avatar.Avatar.disable(self)

    def delete(self):
        try:
            self.Toon_deleted
        except:
            self.Toon_deleted = 1
            del self.animFSM
            self.forwardSpeed = None
            self.chatSoundDict = None
            self.rotateSpeed = None
            self.avatarType = None
            self.track = None
            self.standWalkRunReverse = None
            self.currentAnim = None
            self.toon_head = None
            self.forcedTorsoAnim = None
            self.lastForcedTorsoAnim = None
            self.toon_torso = None
            self.toon_legs = None
            self.gender = None
            self.headtype = None
            self.head = None
            self.legtype = None
            self.torsotype = None
            self.hr = None
            self.hg = None
            self.hb = None
            self.tr = None
            self.tg = None
            self.tb = None
            self.lr = None
            self.lg = None
            self.lb = None
            self.shir = None
            self.shig = None
            self.shib = None
            self.shor = None
            self.shog = None
            self.shob = None
            self.shirt = None
            self.sleeve = None
            self.short = None
            self.tag = None
            self.money = None
            self.lookAtTrack = None
            self.portal1 = None
            self.portal2 = None
            self.backpack = None
            self.fallSfx = None
            self.eyes = None
            self.myTaskId = None
            self.closedEyes = None
            self.soundChatBubble = None
            self.lastAction = None
            self.lastState = None
            self.playingAnim = None
            self.playingRate = None
            self.accessories = None
            Avatar.Avatar.delete(self)
        return

    def initCollisions(self):
        self.collNodePath.setCollideMask(BitMask32(0))
        self.collNodePath.node().setFromCollideMask(CIGlobals.WallBitmask)

        pusher = CollisionHandlerPusher()
        pusher.setInPattern("%in")
        pusher.addCollider(self.collNodePath, self)
        base.cTrav.addCollider(self.collNodePath, pusher)

    def deleteCurrentToon(self):
        if self.shadowCaster:
            self.shadowCaster.clear()
            self.shadowCaster = None

        for accessory in self.accessories:
            accessory.removeNode()
        self.accessories = []

        self.pupils = []

        if 'head' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['head']
        if 'torso' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['torso']
        if 'legs' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['legs']

        self.deleteShadow()
        self.removePart('head')
        self.removePart('torso')
        self.removePart('legs')

        self.clearPythonData()
        self.flush()

    def setAdminToken(self, tokenInstance):

        if tokenInstance:
            matPath = tokenInstance.getMaterialPath()
            self.tokenIcon = loader.loadModel(
                "phase_3/models/props/staffIcon.bam")
            self.tokenIcon.reparentTo(self)
            self.tokenIcon.setScale(0.75)
            self.tokenIcon.setShaderAuto()

            # Let's update the material.
            self.tokenIcon.setBSPMaterial(matPath, 1)

            # Let's position the icon above the nametag.
            x, y, z = self.nametag3d.getPos()
            self.tokenIcon.setPos(Vec3(x, y, z + self.tokenIcon.getSz()))

            r, g, b, _ = tokenInstance.getColor()

            # Let's add the glow.
            glow = loader.loadModel(
                'phase_4/models/minigames/particleGlow.bam')
            glow.reparentTo(self.tokenIcon)
            glow.setScale(2.50)
            glow.setColorScale((r, g, b, 0.50), 1)
            glow.setBSPMaterial('phase_4/maps/particleGlow.mat', 1)
            glow.setDepthWrite(False, 1)
            glow.setShaderAuto()
            glow.setTwoSided(1)

            self.tokenIconIval = Sequence(
                LerpHprInterval(self.tokenIcon,
                                duration=3.0,
                                hpr=Vec3(360, 0, 0),
                                startHpr=Vec3(0, 0, 0)))
            self.tokenIconIval.loop()
        else:
            self.removeAdminToken()

    def removeAdminToken(self):
        if self.tokenIcon != None and self.tokenIconIval != None:
            self.tokenIconIval.finish()
            self.tokenIcon.removeNode()
            self.tokenIconIval = None
            self.tokenIcon = None

    def playChatSfx(self, chatString):
        if not self.getGhost() or self.doId == base.localAvatar.doId:
            if "ooo" in chatString.lower():
                sfx = self.chatSoundDict['howl']
            elif "!" in chatString.lower():
                sfx = self.chatSoundDict['exclaim']
            elif "?" in chatString.lower():
                sfx = self.chatSoundDict['question']
            elif len(chatString) <= 9:
                sfx = self.chatSoundDict['short']
            elif 10 <= len(chatString) <= 19:
                sfx = self.chatSoundDict['medium']
            elif len(chatString) >= 20:
                sfx = self.chatSoundDict['long']
            base.playSfx(sfx, node=self)

    def chatStompComplete(self, chatString):
        if not self.thoughtInProg and CIGlobals.getSettingsMgr().getSetting(
                "chs").getValue():
            self.playChatSfx(chatString)

    def setName(self, nameString):
        Avatar.Avatar.setName(self, nameString)

    def setDNAStrand(self, dnaStrand, makeTag=1):
        ToonDNA.ToonDNA.setDNAStrand(self, dnaStrand)
        self.deleteCurrentToon()
        self.generateToon(makeTag)

    def generateMask(self):
        # No accessories yet.

        if self.shirt == self.maleTopDNA2maleTop['135'][
                0] or self.shirt == self.maleTopDNA2maleTop['136'][0]:
            # This toon is wearing the tsa suit, give them some sweet shades.
            name = 'tsaGlasses'
            glasses = loader.loadModel(
                AccessoryGlobals.AccessoryName2Model[name])
            glassesNode = self.getPart('head').attachNewNode('glassesNode')
            glasses.reparentTo(glassesNode)
            data = AccessoryGlobals.MaskTransExtended[name].get(self.animal)
            if not data:
                data = AccessoryGlobals.MaskTrans.get(self.animal)
                posHprScale = AccessoryGlobals.MaskTrans[self.animal][
                    self.headLength]
            else:
                posHprScale = AccessoryGlobals.MaskTransExtended[name][
                    self.animal].get(self.headLength)
                if not posHprScale:
                    posHprScale = AccessoryGlobals.MaskTrans[self.animal][
                        self.headLength]

            glasses.setPos(posHprScale[0])
            glasses.setHpr(posHprScale[1])
            glasses.setScale(posHprScale[2])

            self.accessories.append(glassesNode)

    def generateToon(self, makeTag=1):
        self.generateLegs()
        self.generateTorso()
        self.generateHead()
        self.setToonColor()
        self.setClothes()
        self.setGloves()
        self.parentToonParts()
        self.rescaleToon()
        self.generateMask()

        # Make torso subparts so we can play a run animation on the pants but another animation on the spine and arms.
        if self.gender == 'boy':
            self.makeSubpart("torso-pants", [
                "def_left_pant_bottom", "def_left_pant_top",
                "def_right_pant_bottom", "def_right_pant_top"
            ],
                             parent="torso")
        elif self.gender == 'girl':
            if self.torso == 'dgs_skirt':
                self.makeSubpart("torso-pants", [
                    "def_left_skirt_backA", "def_left_skirt_frontA",
                    "def_left_skirt_topA", "def_right_skirt_backA",
                    "def_right_skirt_frontA", "def_right_skirt_topA"
                ],
                                 parent="torso")
            elif self.torso == 'dgl_skirt':
                self.makeSubpart("torso-pants", [
                    "def_left_skirt_bottomA", "def_left_skirt_topA",
                    "def_right_hip"
                ],
                                 parent="torso")
            else:
                self.makeSubpart("torso-pants", [
                    "def_left_skirt_bottomA", "def_left_skirt_topA",
                    "def_right_skirt_bottomA", "def_right_skirt_topA"
                ],
                                 parent="torso")
        self.makeSubpart("torso-top", ["def_spineB"], parent="torso")

        Avatar.Avatar.initShadow(self)

        self.updateChatSoundDict()
        self.setBlend(frameBlend=True)

        bodyMat = CIGlobals.getCharacterMaterial(shininess=5,
                                                 specular=(0.5, 0.5, 0.5, 1))
        self.setMaterial(bodyMat, 1)

        if not hasattr(base, 'localAvatar') or base.localAvatar != self:
            self.setupPhysics(1.0, self.getHeight())

        # We can safely optimize the scene graph and combine nodes since we're done manipulating
        # the separate pieces. After this point, the separate pieces of the toon are no
        # longer manipulatable, such as arms, sleeves, shirt, etc. If this needs to be done,
        # the toon will have to be regenerated.

        # Don't do it in Make-A-Toon though, as we have to be constantly modifying the pieces.
        if not self.mat:
            self.optimize()

        if makeTag:
            self.setupNameTag()
        if self.cr.isShowingPlayerIds:
            self.showAvId()

        self.loop('neutral')

    def optimize(self):
        self.getPart('legs').flattenStrong()
        self.postFlatten()

    def attachTNT(self):
        self.pies.attachTNT()
        self.holdTNTAnim()

    def detachTNT(self):
        self.pies.detachTNT()
        self.animFSM.request(self.animFSM.getCurrentState().getName())

    def holdTNTAnim(self):
        self.pose("toss", 22, partName="torso")

    def parentToonParts(self):
        self.attach('head', 'torso', 'def_head')
        self.attach('torso', 'legs', 'joint_hips')

    def unparentToonParts(self):
        self.getPart('head').reparentTo(self.getGeomNode())
        self.getPart('torso').reparentTo(self.getGeomNode())
        self.getPart('legs').reparentTo(self.getGeomNode())

    def getHeadHeight(self):
        animal = self.getAnimal()
        headScale = ToonGlobals.HeadScales[animal][2]
        headHeight = ToonGlobals.HeadHeightDict[self.head] * headScale
        return headHeight

    def rescaleToon(self):
        if not self.getHead():
            return

        animal = self.getAnimal()
        bodyScale = ToonGlobals.BodyScales[animal]
        headScale = ToonGlobals.HeadScales[animal][2]
        shoulderHeight = ToonGlobals.LegHeightDict[
            self.getLegs()] * bodyScale + ToonGlobals.TorsoHeightDict[
                self.getTorso()] * bodyScale
        height = shoulderHeight + ToonGlobals.HeadHeightDict[
            self.getHead()] * headScale
        bodyScale = ToonGlobals.BodyScales[animal]
        self.setAvatarScale(bodyScale)
        self.getPart('head').setScale(headScale)
        self.setHeight(height)

    def setGloves(self):
        color = self.getGloveColor()
        gloves = self.find('**/hands')
        gloves.setColor(color)

    def setClothes(self):
        shirt, shirtcolor = self.getShirtStyle()
        short, shortcolor = self.getShortStyle()
        sleeve, sleevecolor = self.getSleeveStyle()
        torsot = self.findAllMatches('**/torso-top')
        torsob = self.findAllMatches('**/torso-bot')
        sleeves = self.findAllMatches('**/sleeves')
        torsot.setBSPMaterial(shirt, 1)
        torsob.setBSPMaterial(short, 1)
        sleeves.setBSPMaterial(sleeve, 1)
        torsot.setColor(shirtcolor)
        sleeves.setColor(sleevecolor)
        torsob.setColor(shortcolor)

    def generateLegs(self):
        ToonGlobals.generateBodyPart(self, 'legs', self.getLegs(), 3, 'shorts')
        self.find('**/boots_long').stash()
        self.find('**/boots_short').stash()
        self.find('**/shoes').stash()

    def generateTorso(self):
        ToonGlobals.generateBodyPart(self, 'torso', self.getTorso(), 3, '')

    def generateHead(self, pat=0):
        gender = self.getGender()
        head = self.getAnimal()
        headtype = self.getHead()
        ToonHead.generateHead(self, gender, head, headtype)

    def setToonColor(self):
        self.setHeadColor()
        self.setTorsoColor()
        self.setLegColor()

    def setLegColor(self):
        legcolor = self.getLegColor()
        self.findAllMatches('**/legs').setColor(legcolor)
        self.findAllMatches('**/feet').setColor(legcolor)

    def setTorsoColor(self):
        torsocolor = self.getTorsoColor()
        self.findAllMatches('**/arms').setColor(torsocolor)
        self.findAllMatches('**/neck').setColor(torsocolor)
        self.findAllMatches('**/hands').setColor(1, 1, 1, 1)

    def enterOff(self, ts=0, callback=None, extraArgs=[]):
        self.currentAnim = None
        return

    def exitOff(self):
        pass

    def enterWin(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'win'
        self.sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_Win.ogg")
        self.sfx.setLoop(True)
        base.audio3d.attachSoundToObject(self.sfx, self)
        base.playSfx(self.sfx, node=self, looping=1)
        self.loop("win")

    def exitWin(self):
        self.stop()
        self.sfx.stop()
        del self.sfx
        self.playingAnim = 'neutral'

    def enterShrug(self, ts=0, callback=None, extraArgs=[]):
        self.play("shrug")

    def exitShrug(self):
        self.exitGeneral()

    def enterHDance(self, ts=0, callback=None, extraArgs=[]):
        self.play("hdance")

    def exitHDance(self):
        self.exitGeneral()

    def enterScientistWork(self, ts=0, callback=None, extraArgs=[]):
        self.loop("scwork")

    def exitScientistWork(self):
        self.exitGeneral()

    def enterScientistEmcee(self, ts=0, callback=None, extraArgs=[]):
        self.loop("scemcee")

    def exitScientistEmcee(self):
        self.exitGeneral()

    def enterScientistGame(self, ts=0, callback=None, extraArgs=[]):
        self.loop("scgame")

    def exitScientistGame(self):
        self.exitGeneral()

    def enterScientistJealous(self, ts=0, callback=None, extraArgs=[]):
        self.loop("scjealous")

    def exitScientistJealous(self):
        self.exitGeneral()

    def enterWave(self, ts=0, callback=None, extraArgs=[]):
        self.play("wave")

    def exitWave(self):
        self.exitGeneral()

    def enterLaugh(self, ts=0, callback=None, extraArgs=[]):
        self.setPlayRate(5.0, "neutral")
        self.loop("neutral")

    def exitLaugh(self):
        self.setPlayRate(1.0, "neutral")
        self.stop()

    def enterNeutral(self, ts=0, callback=None, extraArgs=[]):
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop("neutral", partName="legs")
            return
        self.loop("neutral")
        self.playingAnim = 'neutral'

    def exitNeutral(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def exitGeneral(self):
        self.stop()

    def enterRun(self, ts=0, callback=None, extraArgs=[]):
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop('run', partName='legs')
            return
        self.loop("run")

    def exitRun(self):
        self.exitGeneral()

    def enterWalk(self, ts=0, callback=None, extraArgs=[]):
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop('walk', partName='legs')
            return
        self.loop('walk')

    def exitWalk(self):
        self.exitGeneral()

    def enterWalkBack(self, ts=0, callback=None, extraArgs=[]):
        self.setPlayRate(-1.0, "walk")
        self.enterWalk()

    def exitWalkBack(self):
        self.exitWalk()
        self.setPlayRate(1.0, "walk")

    def enterOpenBook(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'book'
        self.book1 = Actor("phase_3.5/models/props/book-mod.bam",
                           {"chan": "phase_3.5/models/props/book-chan.bam"})
        self.book1.reparentTo(
            self.getPart('torso').find('**/def_joint_right_hold'))
        self.track = ActorInterval(self,
                                   "book",
                                   startFrame=CIGlobals.OpenBookFromFrame,
                                   endFrame=CIGlobals.OpenBookToFrame,
                                   name=self.uniqueName('enterOpenBook'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.__doCallback,
                        [callback, extraArgs])
        self.track.start(ts)
        self.book1.play("chan",
                        fromFrame=CIGlobals.OpenBookFromFrame,
                        toFrame=CIGlobals.OpenBookToFrame)

    def exitOpenBook(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        if self.book1:
            self.book1.cleanup()
            self.book1 = None
        self.playingAnim = 'neutral'

    def enterReadBook(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'book'
        self.book2 = Actor("phase_3.5/models/props/book-mod.bam",
                           {"chan": "phase_3.5/models/props/book-chan.bam"})
        self.book2.reparentTo(
            self.getPart('torso').find('**/def_joint_right_hold'))

        self.pingpong("book",
                      fromFrame=CIGlobals.ReadBookFromFrame,
                      toFrame=CIGlobals.ReadBookToFrame)
        self.book2.pingpong("chan",
                            fromFrame=CIGlobals.ReadBookFromFrame,
                            toFrame=CIGlobals.ReadBookToFrame)

    def exitReadBook(self):
        if self.book2:
            self.book2.cleanup()
            self.book2 = None
        self.playingAnim = 'neutral'

    def enterCloseBook(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'book'
        self.book3 = Actor("phase_3.5/models/props/book-mod.bam",
                           {"chan": "phase_3.5/models/props/book-chan.bam"})
        self.book3.reparentTo(
            self.getPart('torso').find('**/def_joint_right_hold'))
        self.track = ActorInterval(self,
                                   "book",
                                   startFrame=CIGlobals.CloseBookFromFrame,
                                   endFrame=CIGlobals.CloseBookToFrame,
                                   name=self.uniqueName('enterCloseBook'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.__doCallback,
                        [callback, extraArgs])
        self.track.start(ts)
        self.book3.play("chan",
                        fromFrame=CIGlobals.CloseBookFromFrame,
                        toFrame=CIGlobals.CloseBookToFrame)
        self.lerpLookAt(self.getPart('head'), (0, 0, 0))

    def exitCloseBook(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        if self.book3:
            self.book3.cleanup()
            self.book3 = None
        self.playingAnim = 'neutral'

    def enterTeleportOut(self, ts=0, callback=None, extraArgs=[]):
        self.notify.info(
            str(self.doId) + "-" + str(self.zoneId) + ": enterTeleportOut")
        self.playingAnim = 'tele'
        self.portal1 = Actor(
            "phase_3.5/models/props/portal-mod.bam",
            {"chan": "phase_3.5/models/props/portal-chan.bam"})
        self.portal1.play("chan")
        self.portal1.reparentTo(
            self.getPart('legs').find('**/def_joint_right_hold'))
        self.play("tele")
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('enterTeleportOut')
        else:
            name = 'enterTeleportOut'

        self.track = Sequence(Wait(0.4),
                              Func(self.teleportOutSfx),
                              Wait(1.3),
                              Func(self.throwPortal),
                              Wait(1.1),
                              Func(self.__actAsGone),
                              Wait(1.5),
                              name=name)

        self.track.delayDelete = DelayDelete.DelayDelete(self, name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getName(), self.teleportOutDone,
                        [callback, extraArgs])
        self.track.start(ts)

    def doPortalBins(self, portal):
        portal.setBin('portal', 19)
        portal.setDepthWrite(0)
        portal.setDepthTest(0)

    def teleportOutDone(self, callback, requestStatus):
        self.notify.info(
            str(self.doId) + "-" + str(self.zoneId) + ": teleportOutDone")
        self.__doCallback(callback, requestStatus)
        self.exitTeleportOut()

    def teleportOutSfx(self):
        self.outSfx = base.audio3d.loadSfx(
            "phase_3.5/audio/sfx/AV_teleport.ogg")
        base.audio3d.attachSoundToObject(self.outSfx, self.portal1)
        base.playSfx(self.outSfx, node=self)

    def throwPortal(self):
        self.doPortalBins(self.portal1)
        self.portal1.reparentTo(self.getPart('legs').find('**/joint_nameTag'))
        self.portal1.setScale(CIGlobals.PortalScale)
        self.portal1.setY(6.5)
        self.portal1.setH(180)

    def exitTeleportOut(self):
        self.notify.info(
            str(self.doId) + "-" + str(self.zoneId) + ": exitTeleportOut")
        if self.track != None:
            self.ignore(self.track.getName())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        if self.portal1:
            self.portal1.cleanup()
            self.portal1 = None
        if hasattr(self, 'shadow') and self.shadow is not None:
            self.shadow.show()
        self.__restoreHide()
        self.playingAnim = 'neutral'

    def getTeleportInTrack(self, portal):
        self.doPortalBins(portal)

        holeTrack = Sequence()
        holeTrack.append(Func(portal.reparentTo, self))
        pos = Point3(0, -2.4, 0)
        holeTrack.append(Func(portal.setPos, pos))
        holeTrack.append(
            ActorInterval(portal, 'chan', startTime=3.4, endTime=3.1))
        holeTrack.append(Wait(0.6))
        holeTrack.append(
            ActorInterval(portal, 'chan', startTime=3.1, endTime=3.4))

        def restorePortal(portal):
            portal.setPos(0, 0, 0)
            portal.detachNode()
            portal.clearBin()
            portal.clearDepthTest()
            portal.clearDepthWrite()

        holeTrack.append(Func(restorePortal, portal))
        toonTrack = Sequence(Wait(0.3), Func(self.__restoreHide),
                             ActorInterval(self, 'happy', startTime=0.45))

        if hasattr(self, 'uniqueName'):
            trackName = self.uniqueName('teleportIn')
        else:
            trackName = 'teleportIn'
        return Parallel(toonTrack, holeTrack, name=trackName)

    def enterTeleportIn(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'happy'
        self.portal2 = Actor(
            "phase_3.5/models/props/portal-mod.bam",
            {"chan": "phase_3.5/models/props/portal-chan.bam"})
        self.show()
        self.getGeomNode().hide()
        self.nametag3d.hide()
        self.track = self.getTeleportInTrack(self.portal2)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getName(), self.teleportInDone,
                        [callback, extraArgs])
        if hasattr(self, 'acquireDelayDelete'):
            self.track.delayDelete = DelayDelete.DelayDelete(
                self, self.track.getName())
        self.track.start(ts)

    def teleportInDone(self, callback, extraArgs):
        self.exitTeleportIn()
        self.__doCallback(callback, extraArgs)

    def exitTeleportIn(self):
        if self.track != None:
            self.ignore(self.track.getName())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        if self.portal2:
            self.portal2.cleanup()
            self.portal2 = None
        if self.nametag3d:
            self.nametag3d.show()
        self.playingAnim = 'neutral'

    def enterFallFWD(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'fallf'
        self.play("fallf")
        Sequence(Wait(0.5), SoundInterval(self.fallSfx, node=self)).start()

    def exitFallFWD(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterFallBCK(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'fallb'
        self.play("fallb")
        Sequence(Wait(0.5), SoundInterval(self.fallSfx, node=self)).start()

    def exitFallBCK(self):
        self.playingAnim = 'neutral'
        self.exitGeneral()

    def enterHappyJump(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'happy'
        self.play("happy")

    def exitHappyJump(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterSwim(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'swim'
        self.loop("swim")

        self.resetTorsoRotation()

        toon = self.getGeomNode()
        toon.setP(-89.0)

        if self.shadow:
            self.shadow.hide()

        self.swimBobTrack = Sequence(
            LerpPosInterval(toon,
                            duration=1,
                            pos=(0, -3, 3),
                            startPos=(0, -3, 4),
                            blendType='easeInOut'),
            LerpPosInterval(toon,
                            duration=1,
                            pos=(0, -3, 4),
                            startPos=(0, -3, 3),
                            blendType='easeInOut'))
        self.swimBobTrack.loop()
        self.nametag3d.setZ(5.0)

    def exitSwim(self):
        self.swimBobTrack.finish()
        del self.swimBobTrack
        if self.shadow:
            self.shadow.show()
        self.exitGeneral()
        self.getGeomNode().setPosHpr(0, 0, 0, 0, 0, 0)
        nt = self.nametag3d
        nt.setX(0)
        nt.setY(0)
        nt.setZ(self.getHeight() + 0.5)
        self.playingAnim = 'neutral'

    def enterDied(self, ts=0, callback=None, extraArgs=[]):
        def shouldDisableGags():
            if hasattr(self, 'disableGags'):
                self.disableGags()
            if hasattr(self, 'setEquippedAttack'):
                self.setEquippedAttack(-1)

        self.playingAnim = 'lose'
        self.isdying = True
        self.play("lose")
        self.track = Sequence(Func(self.clearForcedTorsoAnim),
                              Func(shouldDisableGags),
                              Wait(2.2),
                              Func(self.dieSfx),
                              Wait(2.8),
                              self.getGeomNode().scaleInterval(
                                  2,
                                  Point3(0.01),
                                  startScale=(self.getGeomNode().getScale())),
                              Func(self.delToon),
                              name=self.uniqueName('enterDied'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.diedDone,
                        [callback, extraArgs])
        self.track.delayDelete = DelayDelete.DelayDelete(
            self, 'enterTeleportOut')
        self.track.start(ts)

    def diedDone(self, callback, extraArgs):
        self.__doCallback(callback, extraArgs)
        self.exitDied()

    def __doCallback(self, callback, extraArgs):
        if callback:
            if extraArgs:
                callback(*extraArgs)
            else:
                callback()

    def dieSfx(self):
        self.Losesfx = base.audio3d.loadSfx("phase_5/audio/sfx/ENC_Lose.ogg")
        base.audio3d.attachSoundToObject(self.Losesfx, self)
        base.playSfx(self.Losesfx, node=self)

    def delToon(self):
        self.isdead = True

    def exitDied(self):
        if self.track != None:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        if hasattr(self, 'enableGags'):
            self.enableGags()

        self.rescaleToon()
        self.playingAnim = 'neutral'

    def enterBow(self, ts=0, callback=None, extraArgs=[]):
        self.play("bow")
        self.playingAnim = 'bow'

    def exitBow(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterJump(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'jump'
        self.loop("jump")

    def exitJump(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterLeap(self, ts=0, callback=None, extraArgs=[]):
        self.playingAnim = 'leap'
        self.loop("leap")

    def exitLeap(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterCringe(self, ts=0, callback=None, extraArgs=[]):
        self.play("cringe")

    def exitCringe(self):
        self.exitGeneral()

    def enterConked(self, ts=0, callback=None, extraArgs=[]):
        self.play("conked")

    def exitConked(self):
        self.exitGeneral()
示例#36
0
class DistributedCityCart(DistributedNode):
    notify = directNotify.newCategory('DistributedCityCart')

    def __init__(self, cr):
        DistributedNode.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedCityCart', [State('off', self.enterOff, self.exitOff), State('pathFollow', self.enterPathFollow, self.exitPathFollow), State('collision', self.enterCollision, self.exitCollision)], 'off', 'off')
        self.fsm.enterInitialState()
        self.suitInCar = None
        self.cart = None
        self.honkSfxPath = 'phase_14/audio/sfx/cogtropolis_citycar_driveby_horn.mp3'
        self.cartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam'
        self.moPaths = ['phase_14/models/paths/ct-citycar-drivepath-1.egg',
         'phase_14/models/paths/ct-citycar-drivepath-2.egg',
         'phase_14/models/paths/ct-citycar-drivepath-3.egg',
         'phase_14/models/paths/ct-citycar-drivepath-4.egg',
         'phase_14/models/paths/ct-citycar-drivepath-5.egg',
         'phase_14/models/paths/ct-citycar-drivepath-6.egg']
        self.moPath = None
        self.soundEngineLoop = None
        self.soundDriveByHorn = None
        self.ivalTDisplace = None
        self.pathIndex = None
        self.wheelSpinTrack = None
        self.collNodePath = None
        self.soundDriveBy = None
        return

    def setIvalTDisplace(self, displace):
        self.ivalTDisplace = displace

    def setPathIndex(self, index):
        self.pathIndex = index

    def setState(self, state, timestamp):
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.fsm.request(state, [ts])

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterPathFollow(self, ts):
        duration = CityCartGlobals.index2Duration[self.pathIndex]
        self.moPath = NURBSMopath.NURBSMopath(self.moPaths[self.pathIndex], name=self.uniqueName('DCityCart_moPath'))
        startT = 0.0
        if ts > 0.0:
            startT = ts % duration * (1.0 / duration)
        self.moPath.play(self, loop=True, duration=duration, startT=startT)
        base.taskMgr.add(self.__drive, self.uniqueName('DCityCart.drive'))
        self.wheelSpinTrack = Parallel()
        for name in ['leftFrontWheel',
         'rightBackWheel',
         'rightFrontWheel',
         'leftBackWheel']:
            wheel = self.find('**/' + name)
            self.wheelSpinTrack.append(LerpHprInterval(wheel, duration=0.1, hpr=(0, 360, 0), startHpr=(0, 0, 0)))

        self.wheelSpinTrack.loop()
        self.accept('enter' + self.collNodePath.node().getName(), self.__handleRanOver)

    def __handleRanOver(self, entry):
        self.suitInCar.setChat(CityCartGlobals.SuitRanOverTaunt)
        self.sendUpdate('hitByCar')
        self.cr.playGame.getPlace().fsm.request('stop')
        base.localAvatar.b_setAnimState('squish', callback=self.cr.playGame.getPlace().fsm.request, extraArgs=['walk'])

    def __drive(self, task):
        if base.localAvatar.getDistance(self) < 10.0:
            if self.soundDriveByHorn.status() == self.soundDriveByHorn.READY:
                wantsToHonk = random.randint(0, 3)
                if wantsToHonk == 3:
                    base.playSfx(self.soundDriveByHorn)
                return task.cont
        elif base.localAvatar.getDistance(self) < 20.0:
            if self.soundDriveBy.status() == self.soundDriveBy.READY:
                base.playSfx(self.soundDriveBy)
                return task.cont
        return task.cont

    def exitPathFollow(self):
        self.ignore('enter' + self.collNodePath.node().getName())
        if self.wheelSpinTrack:
            self.wheelSpinTrack.finish()
            self.wheelSpinTrack = None
        if self.moPath:
            self.moPath.stop()
            self.moPath = None
        return

    def enterCollision(self, ts):
        pass

    def exitCollision(self):
        pass

    def generate(self):
        DistributedNode.generate(self)
        self.cart = loader.loadModel(self.cartModelPath)
        self.cart.reparentTo(self)
        self.cart.setH(180)
        heads = []
        for head in CIGlobals.SuitBodyData.keys():
            if CIGlobals.SuitBodyData[head][0] != 'B':
                heads.append(head)

        head = random.choice(heads)
        suitType = CIGlobals.SuitBodyData[head][0]
        suitDept = CIGlobals.SuitBodyData[head][1]
        self.suitInCar = Suit()
        self.suitInCar.generateSuit(suitType, head, suitDept, 137, 0, False)
        self.suitInCar.loop('sit')
        self.suitInCar.disableRay()
        self.suitInCar.setScale(0.7)
        self.suitInCar.setH(180)
        self.suitInCar.setPos(0, -1, -1.5)
        self.suitInCar.reparentTo(self.cart.find('**/seat1'))
        self.soundEngineLoop = base.audio3d.loadSfx('phase_6/audio/sfx/KART_Engine_loop_0.wav')
        base.audio3d.attachSoundToObject(self.soundEngineLoop, self)
        base.playSfx(self.soundEngineLoop, looping=1)
        self.soundDriveByHorn = base.audio3d.loadSfx(self.honkSfxPath)
        base.audio3d.attachSoundToObject(self.soundDriveByHorn, self)
        self.soundDriveBy = base.audio3d.loadSfx('phase_14/audio/sfx/cogtropolis_citycar_driveby.mp3')
        base.audio3d.attachSoundToObject(self.soundDriveBy, self)
        sphere = CollisionSphere(0, 0, 0, 2.5)
        sphere.setTangible(0)
        node = CollisionNode(self.uniqueName('cartSphere'))
        node.setCollideMask(CIGlobals.WallBitmask)
        node.addSolid(sphere)
        self.collNodePath = self.attachNewNode(node)
        self.collNodePath.setZ(1.5)
        self.collNodePath.setSy(2.0)
        self.collNodePath.setSx(1.75)

    def disable(self):
        self.fsm.requestFinalState()
        if self.moPath:
            self.moPath.stop()
            self.moPath = None
        self.moPaths = None
        self.honkSfxPath = None
        self.cartModelPath = None
        self.soundEngineLoop = None
        self.soundDriveBy = None
        if self.suitInCar:
            self.suitInCar.disable()
            self.suitInCar.delete()
            self.suitInCar = None
        if self.cart:
            self.cart.removeNode()
            self.cart = None
        del self.fsm
        DistributedNode.disable(self)
        return
示例#37
0
class UberDog(AIRepository):
    notify = directNotify.newCategory("UberDog")

    def __init__(
            self, mdip, mdport, esip, esport, dcFileNames,
            serverId, minChannel, maxChannel):
        AIRepository.__init__(
            self, mdip, mdport, esip, esport, dcFileNames,
            serverId, minChannel, maxChannel, dcSuffix = 'UD')

        # We're responsible for keeping track of who's online with which avatar
        self.onlineAccountDetails = {}
        self.onlineAvatars = {}
        self.onlinePlayers = {}

        self.pending={}
        self.doId2doCache={}

        if hasattr(self, 'setVerbose'):
            if ConfigVariableBool('verbose-uberrepository', 0).getValue():
                self.setVerbose(1)

        # The AI State machine
        self.fsm = ClassicFSM(
            'UberDog', [
            State('off',
                self.enterOff,
                self.exitOff,
                ['connect']),
            State('connect',
                self.enterConnect,
                self.exitConnect,
                ['noConnection', 'playGame',]),
            State('playGame',
                self.enterPlayGame,
                self.exitPlayGame,
                ['noConnection']),
            State('noConnection',
                self.enterNoConnection,
                self.exitNoConnection,
                ['connect'])],
            # initial state
            'off',
            # final state
            'off',
            )
        self.fsm.enterInitialState()
        self.fsm.request("connect")

    def _connected(self):
        """
        Callback for when we successfully connect to the otp_server cluster.
        """
        self.setConnectionName("UberDog")
        AIRepository._connected(self)
        # Listen for Account and Avatar online/offline messages
        self.registerForChannel(CHANNEL_PUPPET_ACTION)
        self.fsm.request("playGame")

    def dispatchUpdateToDoId(self, dclassName, fieldName, doId, args, channelId=None):
        # dispatch immediately to local object if it's local, otherwise send
        # it over the wire
        obj = self.doId2do.get(doId)
        if obj is not None:
            assert obj.__class__.__name__ == (dclassName + self.dcSuffix)
            method = getattr(obj, fieldName)
            method(*args)
        else:
            self.sendUpdateToDoId(dclassName, fieldName, doId, args, channelId)

    def dispatchUpdateToGlobalDoId(self, dclassName, fieldName, doId, args):
        # dispatch immediately to local object if it's local, otherwise send
        # it over the wire
        obj = self.doId2do.get(doId)
        if obj is not None:
            assert obj.__class__.__name__ == dclassName
            method = getattr(obj, fieldName)
            method(*args)
        else:
            self.sendUpdateToGlobalDoId(dclassName, fieldName, doId, args)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def handleAccountUsage(self, di):
        priorAccount = di.getUint32() # Historic - used only in __dev__ atm
        newAccount = di.getUint32()

        if priorAccount == 0 and newAccount == 0:
            assert self.notify.debug("priorAccount==0 and newAccount==0, ignoring accountUsage message")
            return

        accountDetailRecord = AccountDetailRecord()
        accountDetailRecord.openChatEnabled = (di.getString() == "YES")
        accountDetailRecord.createFriendsWithChat = (di.getString() == "YES")
        accountDetailRecord.chatCodeCreation = (di.getString() == "YES")
        access = di.getString()
        if access == "VELVET":
            access = OTPGlobals.AccessVelvetRope
        elif access == "FULL":
            access = OTPGlobals.AccessFull
        else:
            access = OTPGlobals.AccessUnknown
        accountDetailRecord.piratesAccess = access
        accountDetailRecord.familyAccountId = di.getInt32()
        accountDetailRecord.playerAccountId = di.getInt32()
        accountDetailRecord.playerName = di.getString()
        accountDetailRecord.playerNameApproved = di.getInt8()
        accountDetailRecord.maxAvatars = di.getInt32()
        accountDetailRecord.numFamilyMembers = di.getInt16()
        accountDetailRecord.familyMembers = []
        for i in range(accountDetailRecord.numFamilyMembers):
            accountDetailRecord.familyMembers.append(di.getInt32())

        logoutReason = di.getInt32()

        # Now retrieve the subscription information
        accountDetailRecord.numSubs = di.getUint16()

        for i in range(accountDetailRecord.numSubs):
            subDetailRecord = SubDetailRecord()
            subDetailRecord.subId = di.getUint32()
            subDetailRecord.subOwnerId = di.getUint32()
            subDetailRecord.subName = di.getString()
            subDetailRecord.subActive = di.getString()
            access = di.getString()
            if access == "VELVET":
                access = OTPGlobals.AccessVelvetRope
            elif access == "FULL":
                access = OTPGlobals.AccessFull
            else:
                access = OTPGlobals.AccessUnknown
            subDetailRecord.subAccess = access
            subDetailRecord.subLevel = di.getUint8()
            subDetailRecord.subNumAvatars = di.getUint8()
            subDetailRecord.subNumConcur = di.getUint8()
            subDetailRecord.subFounder = (di.getString() == "YES")
            # Add this subscription to the dict on the account record
            accountDetailRecord.subDetails[subDetailRecord.subId] = subDetailRecord

        # How many avatar slots total do you get in this game?
        accountDetailRecord.maxAvatarSlots = di.getInt8()

        assert self.notify.debug("accountDetailRecord: %s" % accountDetailRecord)

        if priorAccount:
            # Send any previous account offline
            self.accountOffline(priorAccount)
            pass

        if newAccount:
            # Set up the new guy
            self.accountOnline(newAccount, accountDetailRecord)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def handleAvatarUsage(self, di):
        priorAvatar = di.getUint32()
        newAvatar = di.getUint32()

        if priorAvatar == 0 and newAvatar == 0:
            assert self.notify.debug("priorAvatar==0 and newAvatar==0, ignoring avatarUsage message")
            return

        newAvatarType = di.getUint16()

        accountId = di.getUint32()

        openChatEnabled = di.getString()
        createFriendsWithChat = di.getString()
        chatCodeCreation = di.getString()
        piratesAccess = di.getString()
        familyAccountId = di.getInt32()
        playerAccountId = di.getInt32()
        playerName = di.getString()
        playerNameApproved = di.getInt8()
        maxAvatars = di.getInt32()
        numFamilyMembers = di.getInt16()
        familyMembers = []
        for i in range(numFamilyMembers):
            familyMembers.append(di.getInt32())

        if openChatEnabled == "YES":
            openChatEnabled = 1
        else:
            openChatEnabled = 0

        if priorAvatar:
            # Send any previous avatar offline
            self.avatarOffline(accountId, priorAvatar)
            pass

        if newAvatar:
            # Set up the new guy
            self.avatarOnline(newAvatar, newAvatarType,
                              playerAccountId,
                              playerName,
                              playerNameApproved,
                              openChatEnabled,
                              createFriendsWithChat,
                              chatCodeCreation)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def accountOnline(self, accountId, accountDetailRecord):
        self.writeServerEvent('accountOnline', accountId, '')
        self.onlineAccountDetails[accountId] = accountDetailRecord
        messenger.send('accountOnline', [accountId])

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def accountOffline(self, accountId):
        self.writeServerEvent('accountOffline', accountId, '')
        self.onlineAccountDetails.pop(accountId, None)
        self.onlinePlayers.pop(accountId, None)
        messenger.send('accountOffline', [accountId])

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def getAccountDetails(self, accountId):
        return self.onlineAccountDetails.get(accountId)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def isAccountOnline(self, accountId):
        return accountId in self.onlineAccountDetails

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def isAvatarOnline(self, avatarId):
        return avatarId in self.onlineAvatars

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def getAvatarAccountOnline(self, avatarId):
        return self.onlineAvatars.get(avatarId, 0)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def getAccountOnlineAvatar(self, accountId):
        return self.onlinePlayers.get(accountId, 0)

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def checkAccountId(self, accountId):
        if not accountId:
            # SUSPICIOUS
            self.notify.warning("Bogus accountId: %s" % accountId)
            self.writeServerEvent('suspicious', accountId, 'bogus accountId in OtpAvatarManagerUD')
        elif not self.isAccountOnline(accountId):
            # SUSPICIOUS
            self.notify.warning("Got request from account not online: %s" % accountId)
            self.writeServerEvent('suspicious', accountId, 'request from offline account in OtpAvatarManagerUD')
        else:
            # Everything checks out
            return True
        return False

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def avatarOnline(self, avatarId, avatarType, accountId, playerName, playerNameApproved,
                     openChatEnabled, createFriendsWithChat, chatCodeCreation):
        self.writeServerEvent('avatarOnline', avatarId, '%s|%s|%s|%s|%s|%s' % (
            accountId, playerName, playerNameApproved, openChatEnabled,
            createFriendsWithChat, chatCodeCreation))

        self.onlineAvatars[avatarId] = accountId
        self.onlinePlayers[accountId] = avatarId

        simpleInfo = [avatarId, avatarType]
        fullInfo = [avatarId,
                    accountId,
                    playerName,
                    playerNameApproved,
                    openChatEnabled,
                    createFriendsWithChat,
                    chatCodeCreation]

        # necessary for local UD manager objects
        messenger.send("avatarOnline", simpleInfo)
        messenger.send("avatarOnlinePlusAccountInfo", fullInfo)
        pass

    @report(types = ['args'], dConfigParam = 'avatarmgr')
    def avatarOffline(self, accountId, avatarId):
        self.writeServerEvent('avatarOffline', avatarId, '')

        self.onlinePlayers.pop(accountId, None)
        self.onlineAvatars.pop(avatarId, None)

        # necessary for local UD manager objects
        messenger.send("avatarOffline", [avatarId])
        pass

    ###################################
    # Assumed Obsolete as of 6/29/09
    #
    # If you're reading this and there
    # haven't been any strange UD crashes
    # here lately, you can probably delete
    # the next few functions.
    ###################################
    def _addObject(self, context, distributedObject):
        """
        Handle a new distributed object arriving by adding
        it to the cache calling self.handleGotDo().
        """
        assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
        doId=distributedObject.getDoId()
        assert doId not in self.doId2doCache
        if doId not in self.doId2doCache:
            self.doId2doCache[doId]=distributedObject
            self.handleGotDo(distributedObject)

    def handleGotDo(self, distributedObject):
        """
        This allows derived classes to override the handling
        of new distributed objects arriving in the cache.
        By default, this will loop through the pending calls
        for that object and make the function calls.  It
        will also remove the handled calls from the pending set.
        """
        assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
        assert doId in self.doId2doCache
        pending=self.pending.get(doId)
        if pending is not None:
            del self.pending[doId]
            for i in pending:
                i[0](*i[2])

    def deleteObject(self, doId):
        """
        Ask for the object to be removed from the private
        distributed object cache.
        """
        assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
        if self.doId2doCache.had_key(doId):
            self.unregisterForChannel(doId)
            #self.deleteObject(doId)
            del self.doId2doCache[doId]
        #HACK:
        self.unregisterForChannel(doId)
        AIRepository.deleteObject(self.doId)

    def uniqueName(self, desc):
        return desc

    if __dev__:
        """
        Early warning system for unsupported use of the Uberdog Repository
        """
        def deleteObjects(self):
            assert 0

        def createDistrict(self, districtId, districtName):
            assert 0

        def deleteDistrict(self, districtId):
            assert 0

        def enterDistrictReset(self):
            assert 0

        def exitDistrictReset(self):
            assert 0
示例#38
0
class MakeAToon:
    MSG_BADNAME = 'Sorry, that name will not work.'

    def __init__(self):
        self.toonMade = 0
        self.slot = -1
        self.currentShop = None
        self.currentHead = 0
        self.currentTorso = 0
        self.currentLeg = 0
        self.currentShirt = 0
        self.currentShorts = 0
        self.shirt1Path = 'phase_3/maps/desat_shirt_1.jpg'
        self.shirt2Path = 'phase_3/maps/desat_shirt_2.jpg'
        self.sleeve1Path = 'phase_3/maps/desat_sleeve_1.jpg'
        self.sleeve2Path = 'phase_3/maps/desat_sleeve_2.jpg'
        self.skirt1Path = 'phase_3/maps/desat_skirt_1.jpg'
        self.short1Path = 'phase_3/maps/desat_shorts_1.jpg'
        self.short2Path = 'phase_3/maps/desat_shorts_2.jpg'
        self.currentShirtTex = self.shirt1Path
        self.currentSleeveTex = self.sleeve1Path
        self.currentShortTex = self.short1Path
        self.toonName = None
        self.matFSM = ClassicFSM('MakeAToon', [State('off', self.enterOff, self.exitOff),
         State('genderShop', self.enterGenderShop, self.exitGenderShop, ['exit', 'off', 'bodyShop']),
         State('bodyShop', self.enterBodyShop, self.exitBodyShop, ['exit',
          'off',
          'genderShop',
          'colorShop']),
         State('colorShop', self.enterColorShop, self.exitColorShop, ['exit',
          'off',
          'bodyShop',
          'clothShop']),
         State('clothShop', self.enterClothShop, self.exitClothShop, ['exit',
          'off',
          'colorShop',
          'nameShop']),
         State('nameShop', self.enterNameShop, self.exitNameShop, ['exit',
          'off',
          'clothShop',
          'done']),
         State('exit', self.enterExit, self.exitExit)], 'off', 'off')
        self.matFSM.enterInitialState()
        return

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def loadEnviron(self):
        base.camLens.setFov(CIGlobals.OriginalCameraFov)
        camera.setPos(-4.77, -17.47, 3.3)
        camera.setH(344.05)
        self.mat_gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam')
        self.cat_gui = loader.loadModel('phase_3/models/gui/create_a_toon_gui.bam')
        self.nameGui = loader.loadModel('phase_3/models/gui/nameshop_gui.bam')
        self.namePanel = self.nameGui.find('**/typeNamePanel')
        self.namePanel.reparentTo(hidden)
        self.namePanel.setScale(0.6)
        self.room = loader.loadModel('phase_3/models/makeatoon/tt_m_ara_mat_room.bam')
        self.floor = self.room.find('**/floor')
        self.floor.reparentTo(render)
        self.bg = self.room.find('**/background')
        self.bg.reparentTo(render)
        self.bg.setY(1.625)
        self.genderRoom = self.room.find('**/genderAll')
        self.genderRoom.reparentTo(hidden)
        self.bodyRoom = self.room.find('**/bodyAll')
        self.bodyRoom.reparentTo(hidden)
        self.colorRoom = self.room.find('**/colorAll')
        self.colorRoom.reparentTo(hidden)
        self.clothRoom = self.room.find('**/cothAll')
        self.clothRoom.reparentTo(hidden)
        self.nameRoom = self.room.find('**/nameAll')
        self.nameRoom.reparentTo(hidden)
        self.desatShirt1 = loader.loadTexture(self.shirt1Path)
        self.desatShirt2 = loader.loadTexture(self.shirt2Path)
        self.desatSleeve1 = loader.loadTexture(self.sleeve1Path)
        self.desatSleeve2 = loader.loadTexture(self.sleeve2Path)
        self.desatSkirt1 = loader.loadTexture(self.skirt1Path)
        self.desatShorts1 = loader.loadTexture(self.short1Path)
        self.desatShorts2 = loader.loadTexture(self.short2Path)
        self.spotlight = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_spotlight.bam')
        self.spotlight.setR(90)
        self.spotlight.setScale(0.6, 0.8, 0.8)
        self.spotlight.setColor(1, 1, 1, 0.3)
        self.spotlight_img = OnscreenImage(image=self.spotlight)
        self.toonGen = ToonGenerator(self)
        self.music = base.loadMusic('phase_3/audio/bgm/create_a_toon.mid')
        base.playMusic(self.music, volume=1.0, looping=1)

    def setSlot(self, slot):
        self.slot = slot

    def getSlot(self):
        return self.slot

    def __handleNextShop(self):
        self.okBtn.hide()
        self.nextBtn.hide()
        self.exitBtn.hide()
        self.backBtn.hide()
        self.nextBtn.hide()
        self.setNextShop(nextShops[self.currentShop])

    def __handlePrevShop(self):
        self.okBtn.hide()
        self.nextBtn.hide()
        self.exitBtn.hide()
        self.backBtn.hide()
        self.nextBtn.hide()
        self.setPrevShop(prevShops[self.currentShop])

    def __handleExit(self, direction):
        self.okBtn.hide()
        self.nextBtn.hide()
        self.exitBtn.hide()
        self.backBtn.hide()
        self.nextBtn.hide()
        base.transitions.fadeOut(0.5)
        Sequence(Wait(0.51), Func(self.exitMakeAToon, direction)).start()

    def exitMakeAToon(self, direction):
        self.matFSM.request('exit', enterArgList=[direction])

    def finishedMakeAToon(self, textEntered = None):
        self.toonName = self.nameEntry.get()
        if self.toonName.isspace() or len(self.toonName) == 0:
            self.badNameDialog = Dialog.GlobalDialog(message=self.MSG_BADNAME, doneEvent='badNameAck', style=Dialog.Ok)
            base.acceptOnce('badNameAck', self.__handleBadNameAck)
            self.badNameDialog.show()
            return
        self.__handleExit('finished')

    def __handleBadNameAck(self):
        self.badNameDialog.cleanup()
        del self.badNameDialog

    def isAvailable(self):
        return True

    def setNextShop(self, shop):
        if shop == 'body':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'bodyShop')).start()
        elif shop == 'color':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'colorShop')).start()
        elif shop == 'cloth':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'clothShop')).start()
        elif shop == 'name':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'nameShop')).start()
        self.fade()

    def setPrevShop(self, shop):
        if shop == 'gender':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'genderShop')).start()
        elif shop == 'body':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'bodyShop')).start()
        elif shop == 'color':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'colorShop')).start()
        elif shop == 'cloth':
            Sequence(Wait(0.21), Func(self.matFSM.request, 'clothShop')).start()
        self.fade()

    def exitColorShop(self):
        self.nextAllColorBtn.destroy()
        self.prevAllColorBtn.destroy()
        self.nextHeadColorBtn.destroy()
        self.prevHeadColorBtn.destroy()
        self.nextTorsoColorBtn.destroy()
        self.prevTorsoColorBtn.destroy()
        self.nextLegColorBtn.destroy()
        self.prevLegColorBtn.destroy()
        self.colorRoom.reparentTo(hidden)
        del self.nextAllColorBtn
        del self.prevAllColorBtn
        del self.nextHeadColorBtn
        del self.prevHeadColorBtn
        del self.nextTorsoColorBtn
        del self.prevTorsoColorBtn
        del self.nextLegColorBtn
        del self.prevLegColorBtn

    def load(self):
        self.exitBtn = DirectButton(text=('', 'Exit', 'Exit', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.115), geom=(self.mat_gui.find('**/tt_t_gui_mat_closeUp'),
         self.mat_gui.find('**/tt_t_gui_mat_closeDown'),
         self.mat_gui.find('**/tt_t_gui_mat_closeUp'),
         self.mat_gui.find('**/tt_t_gui_mat_closeUp')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.2, 0.2, 0.2), geom0_scale=0.6, geom1_scale=0.65, geom2_scale=0.65, geom3_scale=0.6, command=self.__handleExit, extraArgs=['quit'], parent=base.a2dBottomLeft)
        self.exitBtn.setBin('gui-popup', 60)
        self.okBtn = DirectButton(text=('', 'Ready', 'Ready', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.115), geom=(self.mat_gui.find('**/tt_t_gui_mat_okUp'),
         self.mat_gui.find('**/tt_t_gui_mat_okDown'),
         self.mat_gui.find('**/tt_t_gui_mat_okUp'),
         self.mat_gui.find('**/tt_t_gui_mat_okUp')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.2, 0.2, 0.2), geom0_scale=0.6, geom1_scale=0.65, geom2_scale=0.65, geom3_scale=0.6, command=self.finishedMakeAToon, parent=base.a2dBottomRight)
        self.okBtn.hide()
        self.okBtn.setBin('gui-popup', 60)
        self.nextBtn = DirectButton(text=('', 'Next', 'Next', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.115), geom=(self.mat_gui.find('**/tt_t_gui_mat_nextUp'),
         self.mat_gui.find('**/tt_t_gui_mat_nextDown'),
         self.mat_gui.find('**/tt_t_gui_mat_nextUp'),
         self.mat_gui.find('**/tt_t_gui_mat_nextDisabled')), relief=None, pos=(-0.2, 0.2, 0.2), geom0_scale=0.3, geom1_scale=0.35, geom2_scale=0.35, geom3_scale=0.3, command=self.__handleNextShop, parent=base.a2dBottomRight)
        self.nextBtn.setBin('gui-popup', 60)
        self.backBtn = DirectButton(text=('', 'Back', 'Back', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.115), geom=(self.mat_gui.find('**/tt_t_gui_mat_nextUp'),
         self.mat_gui.find('**/tt_t_gui_mat_nextDown'),
         self.mat_gui.find('**/tt_t_gui_mat_nextUp'),
         self.mat_gui.find('**/tt_t_gui_mat_nextDisabled')), relief=None, pos=(-0.4, 0.2, 0.2), geom3_color=Vec4(0.5, 0.5, 0.5, 0.75), geom0_scale=(-0.3, 0.3, 0.3), geom1_scale=(-0.35, 0.35, 0.35), geom2_scale=(-0.35, 0.35, 0.35), geom3_scale=(-0.3, 0.3, 0.3), command=self.__handlePrevShop, parent=base.a2dBottomRight)
        self.backBtn.setBin('gui-popup', 60)
        return

    def enterNameShop(self):
        self.okBtn.show()
        self.backBtn.show()
        self.exitBtn.show()
        base.transitions.fadeIn(0)
        self.currentShop = 'name'
        self.nameRoom.reparentTo(render)
        self.setTitle('Choose Your Name', 'yellow')
        self.spotlight_img.setX(0.55)
        self.spotlight_img.setZ(-0.08)
        self.namePanelFrame = DirectFrame(pos=(-0.4, 0, 0))
        self.namePanel.reparentTo(self.namePanelFrame)
        self.nameEntry = DirectEntry(parent=self.namePanelFrame, pos=(0.013, 0, 0.26), width=10, numLines=2, scale=0.05, text_align=TextNode.ACenter, relief=None, focus=1, command=self.finishedMakeAToon)
        self.toonGen.setToonPosForNameShop()
        return

    def exitNameShop(self):
        self.nameRoom.reparentTo(hidden)
        self.namePanel.setX(0)
        self.namePanel.reparentTo(hidden)
        self.nameEntry.destroy()
        del self.nameEntry
        self.toonGen.setToonPosForGeneralShop()
        if hasattr(self, 'badNameDialog'):
            self.badNameDialog.cleanup()
            del self.badNameDialog

    def enterGenderShop(self):
        self.nextBtn.show()
        self.exitBtn.show()
        self.backBtn.show()
        base.transitions.fadeIn(0)
        self.currentShop = 'gender'
        self.genderRoom.reparentTo(render)
        self.setTitle('Choose Boy Or Girl', 'yellow')
        self.boyBtn = DirectButton(text=('', 'Boy', 'Boy', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.19), geom=(self.mat_gui.find('**/tt_t_gui_mat_boyUp'),
         self.mat_gui.find('**/tt_t_gui_mat_boyDown'),
         self.mat_gui.find('**/tt_t_gui_mat_boyUp'),
         self.mat_gui.find('**/tt_t_gui_mat_boyDown')), relief=None, pos=(-0.45, -0.8, -0.8), geom0_scale=0.6, geom1_scale=0.7, geom2_scale=0.7, geom3_scale=0.6, command=self.generateToon, extraArgs=['boy'])
        self.girlBtn = DirectButton(text=('', 'Girl', 'Girl', ''), text_scale=0.08, text_shadow=(0, 0, 0, 1), text_fg=(1, 1, 1, 1), text_pos=(0, 0.19), geom=(self.mat_gui.find('**/tt_t_gui_mat_girlUp'),
         self.mat_gui.find('**/tt_t_gui_mat_girlDown'),
         self.mat_gui.find('**/tt_t_gui_mat_girlUp'),
         self.mat_gui.find('**/tt_t_gui_mat_girlDown')), relief=None, pos=(0.45, -0.8, -0.8), geom0_scale=0.6, geom1_scale=0.7, geom2_scale=0.7, geom3_scale=0.6, command=self.generateToon, extraArgs=['girl'])
        if not self.toonMade:
            self.nextBtn['state'] = DGG.DISABLED
        self.backBtn['state'] = DGG.DISABLED
        return

    def exitGenderShop(self):
        self.boyBtn.destroy()
        self.girlBtn.destroy()
        self.genderRoom.reparentTo(hidden)
        del self.boyBtn
        del self.girlBtn

    def enterBodyShop(self):
        self.nextBtn.show()
        self.exitBtn.show()
        self.backBtn.show()
        base.transitions.fadeIn(0)
        self.currentShop = 'body'
        self.bodyRoom.reparentTo(render)
        self.setTitle('Choose Your Type', 'sea-green')
        self.nextHeadBtn = DirectButton(text='Head', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, 0.1, 0.1), command=self.nextHead)
        self.prevHeadBtn = DirectButton(text='Head', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, 0.1, 0.1), command=self.prevHead)
        self.nextTorsoBtn = DirectButton(text='Body', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.2, -0.2), command=self.nextTorso)
        self.prevTorsoBtn = DirectButton(text='Body', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.2, -0.2), command=self.prevTorso)
        self.nextLegBtn = DirectButton(text='Legs', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.5, -0.5), command=self.nextLeg)
        self.prevLegBtn = DirectButton(text='Legs', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.5, -0.5), command=self.prevLeg)
        self.currentHead = self.toonGen.toon.head
        self.currentTorso = self.toonGen.toon.torso
        self.currentLeg = self.toonGen.toon.legs
        self.updateBodyShopButtons()
        return

    def updateBodyShopButtons(self):
        if self.currentHead == '2' and self.toonGen.toon.animal == 'cat':
            self.prevHeadBtn['state'] = DGG.NORMAL
        elif self.currentHead == '4' and self.toonGen.toon.animal == 'duck':
            self.nextHeadBtn['state'] = DGG.DISABLED
        elif self.currentHead == '1' and self.toonGen.toon.animal == 'cat':
            self.prevHeadBtn['state'] = DGG.DISABLED
        elif self.currentHead == '3' and self.toonGen.toon.animal == 'duck':
            self.nextHeadBtn['state'] = DGG.NORMAL
        if self.currentTorso == 'dgm_shorts' and self.toonGen.toon.gender == 'boy' or self.currentTorso == 'dgm_skirt' and self.toonGen.toon.gender == 'girl':
            self.prevTorsoBtn['state'] = DGG.NORMAL
        elif self.currentTorso == 'dgl_shorts' and self.toonGen.toon.gender == 'boy' or self.currentTorso == 'dgl_skirt' and self.toonGen.toon.gender == 'girl':
            self.nextTorsoBtn['state'] = DGG.DISABLED
        elif self.currentTorso == 'dgs_shorts' and self.toonGen.toon.gender == 'boy' or self.currentTorso == 'dgs_skirt' and self.toonGen.toon.gender == 'girl':
            self.prevTorsoBtn['state'] = DGG.DISABLED
        elif self.currentTorso == 'dgm_shorts' and self.toonGen.toon.gender == 'boy' or self.currentTorso == 'dgm_skirt' and self.toonGen.toon.gender == 'girl':
            self.nextTorsoBtn['state'] = DGG.NORMAL
        if self.currentLeg == 'dgm':
            self.prevLegBtn['state'] = DGG.NORMAL
        elif self.currentLeg == 'dgl':
            self.nextLegBtn['state'] = DGG.DISABLED
        elif self.currentLeg == 'dgs':
            self.prevLegBtn['state'] = DGG.DISABLED
        elif self.currentLeg == 'dgm':
            self.nextLegBtn['state'] = DGG.NORMAL
        self.backBtn['state'] = DGG.NORMAL

    def nextHead(self):
        head = self.toonGen.getNextHead()
        print head
        newAnimal = None
        if self.toonGen.toon.animal == 'dog' and head == '00' or self.toonGen.toon.animal == 'cat' and head == '04' or self.toonGen.toon.animal != 'dog' and head == '00':
            newAnimal = self.toonGen.getNextAnimal()
            if newAnimal == '00':
                self.nextHeadBtn['state'] = DGG.DISABLED
                return
        self.prevHeadBtn['state'] = DGG.NORMAL
        self.toonGen.toon.head = self.toonGen.toon.headDNA2head[head]
        if newAnimal != None:
            self.toonGen.toon.animal = self.toonGen.toon.animalDNA2animal[newAnimal]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        return

    def prevHead(self):
        head = self.toonGen.getPrevHead()
        newAnimal = None
        if self.toonGen.toon.animal == 'duck' and head == '01' or self.toonGen.toon.animal == 'bear' and head == '07' or self.toonGen.toon.animal == 'dog' and head == '03' or self.toonGen.toon.animal != 'dog' and head == '03':
            newAnimal = self.toonGen.getPrevAnimal()
            if newAnimal == '08':
                self.prevHeadBtn['state'] = DGG.DISABLED
                return
        self.nextHeadBtn['state'] = DGG.NORMAL
        self.toonGen.toon.head = self.toonGen.toon.headDNA2head[head]
        if newAnimal != None:
            self.toonGen.toon.animal = self.toonGen.toon.animalDNA2animal[newAnimal]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        return

    def nextTorso(self):
        newTorso = self.toonGen.getNextTorso()
        self.toonGen.toon.torso = self.toonGen.toon.torsoDNA2torso[newTorso]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        self.updateTorsoButtons(1)

    def updateTorsoButtons(self, direction):
        gender = self.toonGen.toon.getGender()
        if direction == 1:
            nextNewTorso = self.toonGen.getNextTorso()
            if nextNewTorso == '00' and gender == 'boy' or nextNewTorso == '03' and gender == 'girl':
                self.nextTorsoBtn['state'] = DGG.DISABLED
            self.prevTorsoBtn['state'] = DGG.NORMAL
        elif direction == 0:
            nextNewTorso = self.toonGen.getPrevTorso()
            if nextNewTorso == '02' and gender == 'boy' or nextNewTorso == '05' and gender == 'girl':
                self.prevTorsoBtn['state'] = DGG.DISABLED
            self.nextTorsoBtn['state'] = DGG.NORMAL

    def prevTorso(self):
        newTorso = self.toonGen.getPrevTorso()
        self.toonGen.toon.torso = self.toonGen.toon.torsoDNA2torso[newTorso]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        self.updateTorsoButtons(0)

    def nextLeg(self):
        newLegs = self.toonGen.getNextLeg()
        self.toonGen.toon.legs = self.toonGen.toon.legDNA2leg[newLegs]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        self.updateLegButtons(1)

    def updateLegButtons(self, direction):
        if direction == 1:
            nextNewLeg = self.toonGen.getNextLeg()
            if nextNewLeg == '00':
                self.nextLegBtn['state'] = DGG.DISABLED
            self.prevLegBtn['state'] = DGG.NORMAL
        elif direction == 0:
            nextNewLeg = self.toonGen.getPrevLeg()
            if nextNewLeg == '02':
                self.prevLegBtn['state'] = DGG.DISABLED
            self.nextLegBtn['state'] = DGG.NORMAL

    def prevLeg(self):
        newLegs = self.toonGen.getPrevLeg()
        self.toonGen.toon.legs = self.toonGen.toon.legDNA2leg[newLegs]
        self.toonGen.generateDNAStrandWithCurrentStyle()
        self.updateLegButtons(0)

    def exitBodyShop(self):
        self.nextHeadBtn.destroy()
        self.prevHeadBtn.destroy()
        self.nextTorsoBtn.destroy()
        self.prevTorsoBtn.destroy()
        self.nextLegBtn.destroy()
        self.prevLegBtn.destroy()
        self.bodyRoom.reparentTo(hidden)
        del self.nextHeadBtn
        del self.prevHeadBtn
        del self.nextTorsoBtn
        del self.prevTorsoBtn
        del self.nextLegBtn
        del self.prevLegBtn

    def enterColorShop(self):
        self.nextBtn.show()
        self.exitBtn.show()
        self.backBtn.show()
        base.transitions.fadeIn(0)
        self.currentShop = 'color'
        self.colorRoom.reparentTo(render)
        self.setTitle('Choose Your Color', 'light-blue')
        self.nextAllColorBtn = DirectButton(text='Toon', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, scale=1.3, pos=(0.45, 0.5, 0.5), command=self.nextAllColor)
        self.prevAllColorBtn = DirectButton(text='Toon', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, scale=1.3, pos=(-0.5, 0.5, 0.5), command=self.prevAllColor)
        self.nextHeadColorBtn = DirectButton(text='Head', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, 0.1, 0.1), command=self.nextHeadColor)
        self.prevHeadColorBtn = DirectButton(text='Head', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, 0.1, 0.1), command=self.prevHeadColor)
        self.nextTorsoColorBtn = DirectButton(text='Body', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.2, -0.2), command=self.nextTorsoColor)
        self.prevTorsoColorBtn = DirectButton(text='Body', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.2, -0.2), command=self.prevTorsoColor)
        self.nextLegColorBtn = DirectButton(text='Legs', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.5, -0.5), command=self.nextLegColor)
        self.prevLegColorBtn = DirectButton(text='Legs', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.5, -0.5), command=self.prevLegColor)
        self.currentColor = self.toonGen.toon.headcolor
        self.currentHeadColor = self.toonGen.toon.headcolor
        self.currentTorsoColor = self.toonGen.toon.torsocolor
        self.currentLegColor = self.toonGen.toon.legcolor
        self.updateColorShopButtons()
        return

    def setColorShopButtonsNormal(self):
        self.prevAllColorBtn['state'] = DGG.NORMAL
        self.prevHeadColorBtn['state'] = DGG.NORMAL
        self.prevTorsoColorBtn['state'] = DGG.NORMAL
        self.prevLegColorBtn['state'] = DGG.NORMAL
        self.nextAllColorBtn['state'] = DGG.NORMAL
        self.nextHeadColorBtn['state'] = DGG.NORMAL
        self.nextTorsoColorBtn['state'] = DGG.NORMAL
        self.nextLegColorBtn['state'] = DGG.NORMAL

    def updateColorShopButtons(self):
        self.setColorShopButtonsNormal()
        if self.toonGen.toon.color2colorDNA[self.currentColor] == '01':
            self.prevAllColorBtn['state'] = DGG.NORMAL
            self.prevHeadColorBtn['state'] = DGG.NORMAL
            self.prevTorsoColorBtn['state'] = DGG.NORMAL
            self.prevLegColorBtn['state'] = DGG.NORMAL
        elif self.toonGen.toon.color2colorDNA[self.currentColor] == '26':
            self.nextAllColorBtn['state'] = DGG.DISABLED
            self.nextHeadColorBtn['state'] = DGG.DISABLED
            self.nextTorsoColorBtn['state'] = DGG.DISABLED
            self.nextLegColorBtn['state'] = DGG.DISABLED
        elif self.toonGen.toon.color2colorDNA[self.currentColor] == '00':
            self.prevAllColorBtn['state'] = DGG.DISABLED
            self.prevHeadColorBtn['state'] = DGG.DISABLED
            self.prevTorsoColorBtn['state'] = DGG.DISABLED
            self.prevLegColorBtn['state'] = DGG.DISABLED
        elif self.toonGen.toon.color2colorDNA[self.currentColor] == '25':
            self.nextAllColorBtn['state'] = DGG.NORMAL
            self.nextHeadColorBtn['state'] = DGG.NORMAL
            self.nextTorsoColorBtn['state'] = DGG.NORMAL
            self.nextLegColorBtn['state'] = DGG.NORMAL

    def updateColorShopButtonsDir(self, direction):
        self.setColorShopButtonsNormal()
        if direction == 1:
            nextNewHColor = self.toonGen.getNextColor('head')
            nextNewTColor = self.toonGen.getNextColor('torso')
            nextNewLColor = self.toonGen.getNextColor('legs')
            if nextNewHColor == '00':
                self.nextAllColorBtn['state'] = DGG.DISABLED
                self.nextHeadColorBtn['state'] = DGG.DISABLED
            if nextNewTColor == '00':
                self.nextTorsoColorBtn['state'] = DGG.DISABLED
            if nextNewLColor == '00':
                self.nextLegColorBtn['state'] = DGG.DISABLED
        elif direction == 0:
            nextNewHColor = self.toonGen.getPrevColor('head')
            nextNewTColor = self.toonGen.getPrevColor('torso')
            nextNewLColor = self.toonGen.getPrevColor('legs')
            if nextNewHColor == '26':
                self.prevAllColorBtn['state'] = DGG.DISABLED
                self.prevHeadColorBtn['state'] = DGG.DISABLED
            if nextNewTColor == '26':
                self.prevTorsoColorBtn['state'] = DGG.DISABLED
            if nextNewLColor == '26':
                self.prevLegColorBtn['state'] = DGG.DISABLED

    def nextAllColor(self):
        color = self.toonGen.getNextColor('all')
        self.toonGen.toon.headcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.torsocolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.legcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(1)

    def prevAllColor(self):
        color = self.toonGen.getPrevColor('all')
        self.toonGen.toon.headcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.torsocolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.legcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(0)

    def nextHeadColor(self):
        color = self.toonGen.getNextColor('head')
        self.toonGen.toon.headcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(1)

    def prevHeadColor(self):
        color = self.toonGen.getPrevColor('head')
        self.toonGen.toon.headcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(0)

    def nextTorsoColor(self):
        color = self.toonGen.getNextColor('torso')
        self.toonGen.toon.torsocolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(1)

    def prevTorsoColor(self):
        color = self.toonGen.getPrevColor('torso')
        self.toonGen.toon.torsocolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(0)

    def nextLegColor(self):
        color = self.toonGen.getNextColor('legs')
        self.toonGen.toon.legcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(1)

    def prevLegColor(self):
        color = self.toonGen.getPrevColor('legs')
        self.toonGen.toon.legcolor = self.toonGen.toon.colorDNA2color[color]
        self.toonGen.toon.setToonColor()
        self.updateColorShopButtonsDir(0)

    def nextShirt(self):
        newShirt, newSleeve = self.toonGen.getNextShirtAndSleeve()
        newColor = self.toonGen.getNextColor('shirt')
        self.toonGen.toon.shirtColor = self.toonGen.toon.colorDNA2color[newColor]
        self.toonGen.toon.sleeveColor = self.toonGen.toon.colorDNA2color[newColor]
        if newShirt != None and newSleeve != None:
            self.toonGen.toon.shirt = self.toonGen.toon.shirtDNA2shirt[newShirt]
            self.toonGen.toon.sleeve = self.toonGen.toon.sleeveDNA2sleeve[newSleeve]
        self.toonGen.toon.setClothes()
        self.updateClothShopButtonsDir(1)
        return

    def prevShirt(self):
        newShirt, newSleeve = self.toonGen.getPrevShirtAndSleeve()
        newColor = self.toonGen.getPrevColor('shirt')
        self.toonGen.toon.shirtColor = self.toonGen.toon.colorDNA2color[newColor]
        self.toonGen.toon.sleeveColor = self.toonGen.toon.colorDNA2color[newColor]
        if newShirt != None and newSleeve != None:
            self.toonGen.toon.shirt = self.toonGen.toon.shirtDNA2shirt[newShirt]
            self.toonGen.toon.sleeve = self.toonGen.toon.sleeveDNA2sleeve[newSleeve]
        self.toonGen.toon.setClothes()
        self.updateClothShopButtonsDir(1)
        return

    def updateClothShopButtonsDir(self, direction):
        self.nextShirtBtn['state'] = DGG.NORMAL
        self.prevShirtBtn['state'] = DGG.NORMAL
        self.nextShortsBtn['state'] = DGG.NORMAL
        self.prevShortsBtn['state'] = DGG.NORMAL
        if direction == 1:
            if self.toonGen.getNextShirt() == '00':
                self.nextShirtBtn['state'] = DGG.DISABLED
            if self.toonGen.getNextShorts() == '00':
                self.nextShortsBtn['state'] = DGG.DISABLED
            if self.toonGen.getPrevShirt() == '22':
                self.prevShirtBtn['state'] = DGG.DISABLED
            if self.toonGen.getPrevShorts() == '16':
                self.prevShortsBtn['state'] = DGG.DISABLED

    def nextShorts(self):
        newShorts = self.toonGen.getNextShorts()
        newColor = self.toonGen.getNextColor('shorts')
        self.toonGen.toon.shortColor = self.toonGen.toon.colorDNA2color[newColor]
        if newShorts != None:
            self.toonGen.toon.shorts = self.toonGen.toon.shortDNA2short[newShorts]
        self.toonGen.toon.setClothes()
        self.updateClothShopButtonsDir(1)
        return

    def prevShorts(self):
        newShorts = self.toonGen.getPrevShorts()
        newColor = self.toonGen.getPrevColor('shorts')
        self.toonGen.toon.shortColor = self.toonGen.toon.colorDNA2color[newColor]
        if newShorts != None:
            self.toonGen.toon.shorts = self.toonGen.toon.shortDNA2short[newShorts]
        self.toonGen.toon.setClothes()
        self.updateClothShopButtonsDir(1)
        return

    def updateClothes(self):
        if self.currentShirt > 26:
            self.currentShirtTex = self.shirt2Path
            self.currentSleeveTex = self.sleeve2Path
        else:
            self.currentShirtTex = self.shirt1Path
            self.currentSleeveTex = self.sleeve1Path
        if self.gender == 'boy':
            if self.currentShorts > 26:
                self.currentShortTex = self.short2Path
            else:
                self.currentShortTex = self.short1Path
        elif self.gender == 'girl':
            self.currentShortTex = self.skirt1Path

    def getToonColors(self):
        hr, hg, hb, ha = toonColors[self.currentHeadColor]
        tr, tg, tb, ta = toonColors[self.currentTorsoColor]
        lr, lg, lb, la = toonColors[self.currentLegColor]
        return tuple((hr,
         hg,
         hb,
         tr,
         tg,
         tb,
         lr,
         lg,
         lb))

    def enterClothShop(self):
        self.nextBtn.show()
        self.exitBtn.show()
        self.backBtn.show()
        base.transitions.fadeIn(0)
        self.currentShop = 'cloth'
        self.clothRoom.reparentTo(render)
        self.setTitle('Choose Your Clothes', 'light-blue')
        self.nextShirtBtn = DirectButton(text='Shirt', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.2, -0.2), command=self.nextShirt)
        self.prevShirtBtn = DirectButton(text='Shirt', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.2, -0.2), command=self.prevShirt)
        self.nextShortsBtn = DirectButton(text='Shorts', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(-0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(0.45, -0.5, -0.5), command=self.nextShorts)
        self.prevShortsBtn = DirectButton(text='Shorts', text_scale=0.06, text_fg=(1, 0, 0, 1), text_pos=(0.03, 0.005), geom=(self.cat_gui.find('**/CrtATn_R_Arrow_UP'),
         self.cat_gui.find('**/CrtATn_R_Arrow_DN'),
         self.cat_gui.find('**/CrtATn_R_Arrow_RLVR'),
         self.cat_gui.find('**/CrtATn_R_Arrow_UP')), geom_scale=(-1, 1, 1), geom3_color=(0.6, 0.6, 0.6, 0.6), relief=None, pos=(-0.5, -0.5, -0.5), command=self.prevShorts)
        self.updateClothes()
        if self.currentShirt == 0:
            self.nextShirtBtn['state'] = DGG.NORMAL
            self.prevShirtBtn['state'] = DGG.DISABLED
        elif self.currentShirt == 26:
            self.nextShirtBtn['state'] = DGG.DISABLED
            self.prevShirtBtn['state'] = DGG.NORMAL
        if self.currentShorts == 0:
            self.nextShortsBtn['state'] = DGG.NORMAL
            self.prevShortsBtn['state'] = DGG.DISABLED
        if self.gender == 'boy':
            if self.currentShorts == 53:
                self.nextShortsBtn['state'] = DGG.DISABLED
                self.prevShortsBtn['state'] = DGG.NORMAL
        elif self.gender == 'girl':
            if self.currentShorts == 26:
                self.nextShortsBtn['state'] = DGG.DISABLED
                self.prevShortsBtn['state'] = DGG.NORMAL
        return

    def deleteClothShopTask(self, task):
        self.deleteClothShop()

    def exitClothShop(self):
        self.nextShirtBtn.destroy()
        self.prevShirtBtn.destroy()
        self.nextShortsBtn.destroy()
        self.prevShortsBtn.destroy()
        self.clothRoom.reparentTo(hidden)
        del self.nextShirtBtn
        del self.prevShirtBtn
        del self.nextShortsBtn
        del self.prevShortsBtn

    def generateToon(self, gender):
        self.gender = gender
        self.toonGen.generateToon(gender)
        self.toonMade = 1
        self.nextBtn['state'] = DGG.NORMAL

    def fade(self):
        base.transitions.fadeOut(0.2)

    def enterExit(self, direction):
        if direction == 'finished':
            self.toonGen.generateDNAStrandWithCurrentStyle()
            base.transitions.noTransitions()
            messenger.send('createAToonFinished', [self.toonGen.toon.dnaStrand, self.getSlot(), self.toonName])
            return
        elif direction == 'quit':
            base.transitions.noTransitions()
            messenger.send('quitCreateAToon')
            return
        else:
            self.mat_gui.remove()
            self.cat_gui.remove()
            self.nameGui.removeNode()
            self.room.remove()
            if self.toonMade:
                self.toonGen.cleanupToon()
            if self.currentShop is not None:
                self.backBtn.destroy()
                self.exitBtn.destroy()
            if self.currentShop is not None:
                self.okBtn.destroy()
                self.nextBtn.destroy()
                self.title_lbl.destroy()
                del self.exitBtn
                del self.nextBtn
                del self.backBtn
                del self.okBtn
                del self.title_lbl
            self.spotlight_img.destroy()
            self.spotlight.remove()
            self.genderRoom.remove()
            self.bodyRoom.remove()
            self.colorRoom.remove()
            self.floor.remove()
            self.bg.remove()
            del self.genderRoom
            del self.bodyRoom
            del self.colorRoom
            del self.floor
            del self.bg
            del self.mat_gui
            del self.cat_gui
            del self.room
            del self.spotlight_img
            del self.spotlight
            del self.nameGui
            self.toonName = None
            self.toonMade = 0
            self.music.stop()
            del self.music
            del self.toonGen
            base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4.0 / 3.0))
            return

    def exitExit(self):
        pass

    def setTitle(self, title, color):
        try:
            self.title_lbl.destroy()
        except:
            pass

        self.title_lbl = DirectLabel(text=title, relief=None, text_scale=0.16, text_font=loader.loadFont('phase_3/models/fonts/MickeyFont.bam'), pos=(0, 0.85, 0.85))
        if color == 'yellow':
            self.title_lbl['text_fg'] = (1, 1, 0, 1)
        elif color == 'sea-green':
            self.title_lbl['text_fg'] = (0, 0.8509803921568627, 0.4784313725490196, 1)
        elif color == 'light-blue':
            self.title_lbl['text_fg'] = (0, 0.8901960784313725, 1, 1)
        return
class DistributedBoat(DistributedObject):
    notify = directNotify.newCategory("DistributedBoat")

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedBoat', [
            State('off', self.enterOff, self.exitOff),
            State('eastToWest', self.enterEastToWest, self.exitEastToWest),
            State('westToEast', self.enterWestToEast, self.exitWestToEast)
        ], 'off', 'off')
        self.boat = None
        self.eastPier = None
        self.eastPierPath = 'east_pier'
        self.westPier = None
        self.westPierPath = 'west_pier'
        self.pierUpP = 0.0
        self.pierDownP = -45.0
        self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.ogg'
        self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.ogg'
        self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.ogg'
        self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.ogg'
        self.eastWest = 'phase_6/paths/dd-e-w.bam'
        self.westEast = 'phase_6/paths/dd-w-e.bam'
        self.track = None
        self.state = None
        self.animBoat1Track = None
        self.animBoatTrack = None

        # Variables that handle the winter collision node.
        self.crashColl = None
        self.crashCollNP = None

    def __handleOnBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat)

    def __handleOffBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPRender)
        base.localAvatar.setR(0)
        base.localAvatar.setP(0)

    def generate(self):
        DistributedObject.generate(self)
        self.soundFogHorn = base.audio3d.loadSfx(self.fogHorn)
        self.soundShipBell = base.audio3d.loadSfx(self.shipBell)
        self.soundWaterLap = base.audio3d.loadSfx(self.waterLap)
        self.soundDockCreak = base.audio3d.loadSfx(self.dockCreak)

        geom = self.cr.playGame.hood.loader.geom
        self.boatMdl = geom.find('**/*donalds_boat*')
        self.boat = geom.find("**/ddBoatRoot")
        self.boatMdl1 = geom.find("**/ddBoatMdl1")

        base.audio3d.attachSoundToObject(self.soundFogHorn, self.boat)
        base.audio3d.attachSoundToObject(self.soundShipBell, self.boat)
        base.audio3d.attachSoundToObject(self.soundWaterLap, self.boat)
        base.audio3d.attachSoundToObject(self.soundDockCreak, self.boat)

        self.soundWaterLap.setLoop(True)
        self.soundWaterLap.play()

        self.generated()

    def generated(self):
        self.eastPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.eastPierPath)
        self.westPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.westPierPath)
        base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boatMdl)
        self.accept('enterdonalds_boat_floor', self.__handleOnBoat)
        self.accept('exitdonalds_boat_floor', self.__handleOffBoat)
        self.d_requestCurrentStateAndTimestamp()
        self.fsm.enterInitialState()

        speedFactor = 2

        self.animBoatTrack = Sequence(
            LerpHprInterval(self.boatMdl,
                            duration=1 * speedFactor,
                            hpr=(0, 0, -1),
                            startHpr=(0, 0, 1),
                            blendType='easeInOut'),
            LerpHprInterval(self.boatMdl,
                            duration=1 * speedFactor,
                            hpr=(0, 0, 1),
                            startHpr=(0, 0, -1),
                            blendType='easeInOut'))

        import math

        self.animBoat1Track = Sequence(
            LerpHprInterval(self.boatMdl1,
                            duration=math.pi * speedFactor,
                            hpr=(0, 1, 0),
                            startHpr=(0, -1, 0),
                            blendType='easeInOut'),
            LerpHprInterval(self.boatMdl1,
                            duration=math.pi * speedFactor,
                            hpr=(0, -1, 0),
                            startHpr=(0, 1, 0),
                            blendType='easeInOut'))
        self.animBoat1Track.loop()
        self.animBoatTrack.loop()

        if base.cr.holidayManager.getHoliday() == HolidayType.CHRISTMAS:
            self.boat.setPosHpr(12.73, -1.6, -4.7, 341.57, 350.0, 26.5)
            self.fsm.request('off')

            self.crashColl = CollisionSphere(0, 0, 0, 15)
            self.crashCollNP = self.boat.attachNewNode(
                CollisionNode('crashed_boat_collision'))
            self.crashCollNP.node().addSolid(self.crashColl)
            self.crashCollNP.node().setCollideMask(CIGlobals.WallBitmask)
            self.crashCollNP.setSz(2)
            self.crashCollNP.setSx(0.75)
            self.crashCollNP.setSy(1.25)
            self.crashCollNP.setPosHpr(2.05, 3.21, 1.66, 8.44, 6.93, 332.61)

    def disable(self):
        base.taskMgr.remove(self.uniqueName('__pollBoat'))
        base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat)
        self.ignore('enterdonalds_boat_floor')
        self.ignore('exitdonalds_boat_floor')
        self.fsm.requestFinalState()

        if self.animBoat1Track:
            self.animBoat1Track.finish()
            self.animBoat1Track = None
        if self.animBoatTrack:
            self.animBoatTrack.finish()
            self.animBoatTrack = None

        if self.crashCollNP:
            self.crashCollNP.removeNode()
            del self.crashCollNP
            del self.crashColl

        del self.fsm
        del self.soundFogHorn
        del self.soundShipBell
        self.soundWaterLap.stop()
        del self.soundWaterLap
        del self.soundDockCreak
        self.fogHorn = None
        self.shipBell = None
        self.waterLap = None
        self.dockCreak = None
        self.boat = None
        self.boatMdl = None
        self.boatMdl1 = None
        self.track = None
        self.pierDownP = None
        self.pierUpP = None
        self.eastPier = None
        self.eastPierPath = None
        self.westPier = None
        self.westPierPath = None
        self.boatPath = None
        self.westEast = None
        self.eastWest = None
        DistributedObject.disable(self)

    def currentStateAndTimestamp(self, state, timestamp):
        self.setState(state, timestamp)

    def d_requestCurrentStateAndTimestamp(self):
        self.sendUpdate('requestCurrentStateAndTimestamp', [])

    def setState(self, state, timestamp=None):
        if timestamp is None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        self.state = state
        if self.boat and base.cr.holidayManager.getHoliday(
        ) != HolidayType.CHRISTMAS:
            self.fsm.request(state, [ts])

    def enterEastToWest(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.eastWest)
        moIval = MopathInterval(moPath, self.boat, blendType='easeInOut')

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.eastPier), moIval,
            LerpQuatInterval(self.eastPier,
                             duration=5.0,
                             quat=(90, self.pierDownP, 0),
                             startHpr=(90, self.pierUpP, 0),
                             blendType='easeInOut'),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.westPier,
                                     duration=5.0,
                                     quat=(-90, self.pierUpP, 0),
                                     startHpr=(-90, self.pierDownP, 0),
                                     blendType='easeInOut'),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.westPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitEastToWest(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterWestToEast(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.westEast)
        moIval = MopathInterval(moPath, self.boat, blendType='easeInOut')

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.westPier), moIval,
            LerpQuatInterval(self.westPier,
                             duration=5.0,
                             quat=(-90, self.pierDownP, 0),
                             startHpr=(-90, self.pierUpP, 0),
                             blendType='easeInOut'),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.eastPier,
                                     duration=5.0,
                                     quat=(90, self.pierUpP, 0),
                                     startHpr=(90, self.pierDownP, 0),
                                     blendType='easeInOut'),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.eastPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitWestToEast(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass
示例#40
0
文件: Toon.py 项目: coginvasion/src
class Toon(Avatar.Avatar, ToonHead, ToonDNA.ToonDNA):

    def __init__(self, cr, mat = 0):
        self.cr = cr
        try:
            self.Toon_initialized
            return
        except:
            self.Toon_initialized = 1

        Avatar.Avatar.__init__(self, mat)
        ToonDNA.ToonDNA.__init__(self)
        ToonHead.__init__(self, cr)
        self.forwardSpeed = 0.0
        self.rotateSpeed = 0.0
        self.avatarType = CIGlobals.Toon
        self.track = None
        self.standWalkRunReverse = None
        self.playingAnim = None
        self.tag = None
        self.money = 0
        self.lookAtTrack = None
        self.portal1 = None
        self.portal2 = None
        self.gunAttached = False
        self.gun = None
        self.tokenIcon = None
        self.tokenIconIval = None
        self.backpack = None
        self.forcedTorsoAnim = None
        self.fallSfx = base.audio3d.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.mp3')
        base.audio3d.attachSoundToObject(self.fallSfx, self)
        self.eyes = loader.loadTexture('phase_3/maps/eyes.jpg', 'phase_3/maps/eyes_a.rgb')
        self.myTaskId = random.uniform(0, 1231231232132131231232L)
        self.closedEyes = loader.loadTexture('phase_3/maps/eyesClosed.jpg', 'phase_3/maps/eyesClosed_a.rgb')
        self.soundChatBubble = loader.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.mp3')
        self.shadowCaster = None
        self.chatSoundDict = {}
        self.animFSM = ClassicFSM('Toon', [State('off', self.enterOff, self.exitOff),
         State('neutral', self.enterNeutral, self.exitNeutral),
         State('swim', self.enterSwim, self.exitSwim),
         State('walk', self.enterWalk, self.exitWalk),
         State('run', self.enterRun, self.exitRun),
         State('openBook', self.enterOpenBook, self.exitOpenBook),
         State('readBook', self.enterReadBook, self.exitReadBook),
         State('closeBook', self.enterCloseBook, self.exitCloseBook),
         State('teleportOut', self.enterTeleportOut, self.exitTeleportOut),
         State('teleportIn', self.enterTeleportIn, self.exitTeleportIn),
         State('died', self.enterDied, self.exitDied),
         State('fallFWD', self.enterFallFWD, self.exitFallFWD),
         State('fallBCK', self.enterFallBCK, self.exitFallBCK),
         State('jump', self.enterJump, self.exitJump),
         State('leap', self.enterLeap, self.exitLeap),
         State('laugh', self.enterLaugh, self.exitLaugh),
         State('happy', self.enterHappyJump, self.exitHappyJump),
         State('shrug', self.enterShrug, self.exitShrug),
         State('hdance', self.enterHDance, self.exitHDance),
         State('wave', self.enterWave, self.exitWave),
         State('scientistEmcee', self.enterScientistEmcee, self.exitScientistEmcee),
         State('scientistWork', self.enterScientistWork, self.exitScientistWork),
         State('scientistGame', self.enterScientistGame, self.exitScientistGame),
         State('scientistJealous', self.enterScientistJealous, self.exitScientistJealous),
         State('cringe', self.enterCringe, self.exitCringe),
         State('conked', self.enterConked, self.exitConked),
         State('win', self.enterWin, self.exitWin),
         State('walkBack', self.enterWalkBack, self.exitWalkBack),
         State('deadNeutral', self.enterDeadNeutral, self.exitDeadNeutral),
         State('deadWalk', self.enterDeadWalk, self.exitDeadWalk),
         State('squish', self.enterSquish, self.exitSquish),
         State('Happy', self.enterHappy, self.exitHappy),
         State('Sad', self.enterSad, self.exitSad)], 'off', 'off')
        animStateList = self.animFSM.getStates()
        self.animFSM.enterInitialState()
        if not hasattr(base, 'localAvatar') or not base.localAvatar == self:
            Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 3, 1)
        return

    def enterHappy(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = None
        self.standWalkRunReverse = (('neutral', 1.0),
         ('walk', 1.0),
         ('run', 1.0),
         ('walk', -1.0))
        self.setSpeed(self.forwardSpeed, self.rotateSpeed)
        return

    def exitHappy(self):
        self.standWalkRunReverse = None
        self.stop()
        return

    def enterSad(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'sad'
        self.standWalkRunReverse = (('dneutral', 1.0),
         ('dwalk', 1.2),
         ('dwalk', 1.2),
         ('dwalk', -1.0))
        self.setSpeed(0, 0)

    def exitSad(self):
        self.standWalkRunReverse = None
        self.stop()
        return

    def setSpeed(self, forwardSpeed, rotateSpeed):
        self.forwardSpeed = forwardSpeed
        self.rotateSpeed = rotateSpeed
        action = None
        if self.standWalkRunReverse != None:
            if forwardSpeed >= CIGlobals.RunCutOff:
                action = CIGlobals.RUN_INDEX
            elif forwardSpeed > CIGlobals.WalkCutOff:
                action = CIGlobals.WALK_INDEX
            elif forwardSpeed < -CIGlobals.WalkCutOff:
                action = CIGlobals.REVERSE_INDEX
            elif rotateSpeed != 0.0:
                action = CIGlobals.WALK_INDEX
            else:
                action = CIGlobals.STAND_INDEX
            anim, rate = self.standWalkRunReverse[action]
            if anim != self.playingAnim:
                self.playingAnim = anim
                self.stop()
                self.loop(anim)
                self.setPlayRate(rate, anim)
        return action

    def enterSquish(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'squish'
        sound = loader.loadSfx('phase_9/audio/sfx/toon_decompress.mp3')
        lerpTime = 0.1
        node = self.getGeomNode().getChild(0)
        origScale = node.getScale()
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('getSquished')
        else:
            name = 'getSquished'
        self.track = Sequence(LerpScaleInterval(node, lerpTime, VBase3(2, 2, 0.025), blendType='easeInOut'), Wait(1.0), Parallel(Sequence(Wait(0.4), LerpScaleInterval(node, lerpTime, VBase3(1.4, 1.4, 1.4), blendType='easeInOut'), LerpScaleInterval(node, lerpTime / 2.0, VBase3(0.8, 0.8, 0.8), blendType='easeInOut'), LerpScaleInterval(node, lerpTime / 3.0, origScale, blendType='easeInOut')), ActorInterval(self, 'happy', startTime=0.2), SoundInterval(sound)), name=name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.squishDone, [callback, extraArgs])
        self.track.delayDelete = DelayDelete.DelayDelete(self, name)
        self.track.start(ts)

    def squishDone(self, callback = None, extraArgs = []):
        self.__doCallback(callback, extraArgs)

    def exitSquish(self):
        if self.track:
            self.ignore(self.track.getName())
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track.finish()
            self.track = None
        self.playingAnim = 'neutral'
        return

    def enterDeadNeutral(self, ts = 0, callback = None, extraArgs = []):
        self.loop('dneutral')

    def exitDeadNeutral(self):
        self.stop()

    def enterDeadWalk(self, ts = 0, callback = None, extraArgs = []):
        self.loop('dwalk')

    def exitDeadWalk(self):
        self.stop()

    def setBackpack(self, pack):
        self.backpack = pack

    def getGhost(self):
        return 0

    def updateChatSoundDict(self):
        self.chatSoundDict['exclaim'] = base.audio3d.loadSfx(self.getToonAnimalNoise('exclaim'))
        self.chatSoundDict['question'] = base.audio3d.loadSfx(self.getToonAnimalNoise('question'))
        self.chatSoundDict['short'] = base.audio3d.loadSfx(self.getToonAnimalNoise('short'))
        self.chatSoundDict['medium'] = base.audio3d.loadSfx(self.getToonAnimalNoise('med'))
        self.chatSoundDict['long'] = base.audio3d.loadSfx(self.getToonAnimalNoise('long'))
        self.chatSoundDict['howl'] = base.audio3d.loadSfx(self.getToonAnimalNoise('howl'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['exclaim'], self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['question'], self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['short'], self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['medium'], self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['long'], self.getPart('head'))
        base.audio3d.attachSoundToObject(self.chatSoundDict['howl'], self.getPart('head'))

    def ghostOn(self):
        self.getGeomNode().hide()
        self.getNameTag().hide()
        self.getShadow().hide()
        if self.tokenIcon:
            self.tokenIcon.hide()
        self.stashBodyCollisions()

    def ghostOff(self):
        self.unstashBodyCollisions()
        if self.tokenIcon:
            self.tokenIcon.show()
        self.getShadow().show()
        self.getNameTag().show()
        self.getGeomNode().show()

    def attachGun(self, gunName):
        self.detachGun()
        if gunName == 'pistol':
            self.gun = loader.loadModel('phase_4/models/props/water-gun.bam')
            self.gun.reparentTo(self.find('**/def_joint_right_hold'))
            self.gun.setPos(Point3(0.28, 0.1, 0.08))
            self.gun.setHpr(VBase3(85.6, -4.44, 94.43))
            self.gunAttached = True
        elif gunName == 'shotgun':
            self.gun = loader.loadModel('phase_4/models/props/shotgun.egg')
            self.gun.setScale(0.75)
            self.gun.reparentTo(self.find('**/def_joint_right_hold'))
            self.gun.setPos(Point3(-0.5, -0.2, 0.19))
            self.gun.setHpr(Vec3(350, 272.05, 0))
            color = random.choice([VBase4(1, 0.25, 0.25, 1), VBase4(0.25, 1, 0.25, 1), VBase4(0.25, 0.25, 1, 1)])
            self.gun.setColorScale(color)
            self.gunAttached = True

    def detachGun(self):
        if self.gun and self.gunAttached:
            self.gun.removeNode()
            self.gun = None
            self.gunAttached = False
        return

    def stopAnimations(self):
        if hasattr(self, 'animFSM'):
            if not self.animFSM.isInternalStateInFlux():
                self.animFSM.request('off')
            else:
                notify.warning('animFSM in flux, state=%s, not requesting off' % self.animFSM.getCurrentState().getName())
        else:
            notify.warning('animFSM has been deleted')
        if self.track != None:
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        return

    def disable(self):
        try:
            self.Toon_disabled
        except:
            self.Toon_disabled = 1
            self.backpack = None
            self.stopAnimations()
            self.removeAdminToken()
            ToonHead.delete(self)
            self.deleteCurrentToon()
            self.chatSoundDict = {}

        return

    def delete(self):
        try:
            self.Toon_deleted
        except:
            self.Toon_deleted = 1
            del self.animFSM
            self.forwardSpeed = None
            self.chatSoundDict = None
            self.rotateSpeed = None
            self.avatarType = None
            self.track = None
            self.standWalkRunReverse = None
            self.currentAnim = None
            self.toon_head = None
            self.forcedTorsoAnim = None
            self.toon_torso = None
            self.toon_legs = None
            self.gender = None
            self.headtype = None
            self.head = None
            self.legtype = None
            self.torsotype = None
            self.hr = None
            self.hg = None
            self.hb = None
            self.tr = None
            self.tg = None
            self.tb = None
            self.lr = None
            self.lg = None
            self.lb = None
            self.shir = None
            self.shig = None
            self.shib = None
            self.shor = None
            self.shog = None
            self.shob = None
            self.shirt = None
            self.sleeve = None
            self.short = None
            self.tag = None
            self.money = None
            self.lookAtTrack = None
            self.portal1 = None
            self.portal2 = None
            self.backpack = None
            self.fallSfx = None
            self.eyes = None
            self.myTaskId = None
            self.closedEyes = None
            self.soundChatBubble = None
            self.lastAction = None
            self.lastState = None
            self.playingAnim = None
            Avatar.Avatar.delete(self)

        return

    def initCollisions(self):
        self.collNodePath.setCollideMask(BitMask32(0))
        self.collNodePath.node().setFromCollideMask(CIGlobals.WallBitmask)
        pusher = CollisionHandlerPusher()
        pusher.setInPattern('%in')
        pusher.addCollider(self.collNodePath, self)
        base.cTrav.addCollider(self.collNodePath, pusher)

    def deleteCurrentToon(self):
        if self.shadowCaster:
            self.shadowCaster.clear()
            self.shadowCaster = None
        try:
            self.stopLookAround()
            self.stopBlink()
        except:
            pass

        self.pupils = []
        if 'head' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['head']
        if 'torso' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['torso']
        if 'legs' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['legs']
        self.deleteShadow()
        self.removePart('head')
        self.removePart('torso')
        self.removePart('legs')
        self.detachGun()
        return

    def enterGagShop(self):
        DirectLabel(text='ENTERED GAG SHOP', relief=None, text_scale=0.08)
        return

    def setAdminToken(self, tokenId):
        tokens = {0: 500}
        if tokenId in tokens.keys():
            icons = loader.loadModel('phase_3/models/props/gm_icons.bam')
            self.tokenIcon = icons.find('**/access_level_%s' % tokens[tokenId])
            self.tokenIcon.reparentTo(self)
            x = self.getNameTag().getX()
            y = self.getNameTag().getY()
            z = self.getNameTag().getZ()
            self.tokenIcon.setPos(Vec3(x, y, z) + (0, 0, 0.5))
            self.tokenIcon.setScale(0.4)
            self.tokenIconIval = Sequence(LerpHprInterval(self.tokenIcon, duration=3.0, hpr=Vec3(360, 0, 0), startHpr=Vec3(0, 0, 0)))
            self.tokenIconIval.loop()
            icons.removeNode()

    def removeAdminToken(self):
        if self.tokenIcon != None and self.tokenIconIval != None:
            self.tokenIconIval.finish()
            self.tokenIcon.removeNode()
            self.tokenIconIval = None
            self.tokenIcon = None
        return

    def setChat(self, chatString):
        if not self.isThought(chatString):
            if not self.getGhost() or self.doId == base.localAvatar.doId:
                if 'ooo' in chatString.lower():
                    sfx = self.chatSoundDict['howl']
                elif '!' in chatString.lower():
                    sfx = self.chatSoundDict['exclaim']
                elif '?' in chatString.lower():
                    sfx = self.chatSoundDict['question']
                elif len(chatString) <= 9:
                    sfx = self.chatSoundDict['short']
                elif 10 <= len(chatString) <= 19:
                    sfx = self.chatSoundDict['medium']
                elif len(chatString) >= 20:
                    sfx = self.chatSoundDict['long']
                sfx.play()
        Avatar.Avatar.setChat(self, chatString)

    def setName(self, nameString):
        Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType)

    def setDNAStrand(self, dnaStrand, makeTag = 1):
        ToonDNA.ToonDNA.setDNAStrand(self, dnaStrand)
        self.deleteCurrentToon()
        self.generateToon(makeTag)

    def generateToon(self, makeTag = 1):
        self.generateLegs()
        self.generateTorso()
        self.generateHead()
        self.setToonColor()
        self.setClothes()
        self.setGloves()
        self.parentToonParts()
        self.rescaleToon()
        if makeTag:
            self.setupNameTag()
        Avatar.Avatar.initShadow(self)
        if self.cr.isShowingPlayerIds:
            self.showAvId()
        self.updateChatSoundDict()

    def attachTNT(self):
        self.pies.attachTNT()
        self.holdTNTAnim()

    def detachTNT(self):
        self.pies.detachTNT()
        self.animFSM.request(self.animFSM.getCurrentState().getName())

    def holdTNTAnim(self):
        self.pose('toss', 22, partName='torso')

    def parentToonParts(self):
        self.attach('head', 'torso', 'def_head')
        self.attach('torso', 'legs', 'joint_hips')

    def unparentToonParts(self):
        self.getPart('head').reparentTo(self.getGeomNode())
        self.getPart('torso').reparentTo(self.getGeomNode())
        self.getPart('legs').reparentTo(self.getGeomNode())

    def rescaleToon(self):
        animal = self.getAnimal()
        bodyScale = CIGlobals.toonBodyScales[animal]
        headScale = CIGlobals.toonHeadScales[animal][2]
        shoulderHeight = CIGlobals.legHeightDict[self.legs] * bodyScale + CIGlobals.torsoHeightDict[self.torso] * bodyScale
        height = shoulderHeight + CIGlobals.headHeightDict[self.head] * headScale
        bodyScale = CIGlobals.toonBodyScales[animal]
        self.setAvatarScale(bodyScale)
        self.setHeight(height)

    def setGloves(self):
        color = self.getGloveColor()
        gloves = self.find('**/hands')
        gloves.setColor(color)

    def setClothes(self):
        shirt, shirtcolor = self.getShirtStyle()
        short, shortcolor = self.getShortStyle()
        sleeve, sleevecolor = self.getSleeveStyle()
        torsot = self.findAllMatches('**/torso-top')
        torsob = self.findAllMatches('**/torso-bot')
        sleeves = self.findAllMatches('**/sleeves')
        torsot.setTexture(loader.loadTexture(shirt), 1)
        torsob.setTexture(loader.loadTexture(short), 1)
        sleeves.setTexture(loader.loadTexture(sleeve), 1)
        torsot.setColor(shirtcolor)
        sleeves.setColor(sleevecolor)
        torsob.setColor(shortcolor)

    def generateLegs(self):
        legtype = self.getLegs()
        self.loadModel('phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_' + str(CIGlobals.getModelDetail(self.avatarType)) + '.bam', 'legs')
        self.loadAnims({'neutral': 'phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_neutral.bam',
         'run': 'phase_3/models/char/tt_a_chr_' + legtype + '_shorts_legs_run.bam',
         'walk': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_walk.bam',
         'pie': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_pie-throw.bam',
         'fallb': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_slip-backward.bam',
         'fallf': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_slip-forward.bam',
         'lose': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_lose.bam',
         'win': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_victory-dance.bam',
         'squirt': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_water-gun.bam',
         'zend': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump-zend.bam',
         'tele': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_teleport.bam',
         'book': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_book.bam',
         'leap': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_leap_zhang.bam',
         'jump': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump-zhang.bam',
         'happy': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_jump.bam',
         'shrug': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shrug.bam',
         'hdance': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_happy-dance.bam',
         'wave': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_wave.bam',
         'scemcee': 'phase_4/models/char/tt_a_chr_dgm_shorts_legs_scientistEmcee.bam',
         'scwork': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistWork.bam',
         'scgame': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistGame.bam',
         'scjealous': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_scientistJealous.bam',
         'swim': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_swim.bam',
         'toss': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_toss.bam',
         'cringe': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_cringe.bam',
         'conked': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_conked.bam',
         'catchneutral': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_gameneutral.bam',
         'catchrun': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_gamerun.bam',
         'hold-bottle': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_hold-bottle.bam',
         'push-button': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_press-button.bam',
         'happy-dance': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_happy-dance.bam',
         'juggle': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_juggle.bam',
         'shout': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shout.bam',
         'dneutral': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_sad-neutral.bam',
         'dwalk': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_losewalk.bam',
         'smooch': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_smooch.bam',
         'conked': 'phase_3.5/models/char/tt_a_chr_' + legtype + '_shorts_legs_conked.bam',
         'sound': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_shout.bam',
         'sprinkle-dust': 'phase_5/models/char/tt_a_chr_' + legtype + '_shorts_legs_sprinkle-dust.bam',
         'start-sit': 'phase_4/models/char/tt_a_chr_' + legtype + '_shorts_legs_intoSit.bam',
         'sit': 'phase_4/models/char/char/tt_a_chr_' + legtype + '_shorts_legs_sit.bam'}, 'legs')
        self.findAllMatches('**/boots_long').stash()
        self.findAllMatches('**/boots_short').stash()
        self.findAllMatches('**/shoes').stash()

    def generateTorso(self):
        torsotype = self.getTorso()
        self.loadModel('phase_3/models/char/tt_a_chr_' + torsotype + '_torso_' + str(CIGlobals.getModelDetail(self.avatarType)) + '.bam', 'torso')
        self.loadAnims({'neutral': 'phase_3/models/char/tt_a_chr_' + torsotype + '_torso_neutral.bam',
         'run': 'phase_3/models/char/tt_a_chr_' + torsotype + '_torso_run.bam',
         'walk': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_walk.bam',
         'pie': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_pie-throw.bam',
         'fallb': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_slip-backward.bam',
         'fallf': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_slip-forward.bam',
         'lose': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_lose.bam',
         'win': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_victory-dance.bam',
         'squirt': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_water-gun.bam',
         'zend': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump-zend.bam',
         'tele': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_teleport.bam',
         'book': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_book.bam',
         'leap': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_leap_zhang.bam',
         'jump': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump-zhang.bam',
         'happy': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_jump.bam',
         'shrug': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_shrug.bam',
         'hdance': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_happy-dance.bam',
         'wave': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_wave.bam',
         'scemcee': 'phase_4/models/char/tt_a_chr_dgm_shorts_torso_scientistEmcee.bam',
         'scwork': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistWork.bam',
         'scgame': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistGame.bam',
         'scjealous': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_scientistJealous.bam',
         'swim': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_swim.bam',
         'toss': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_toss.bam',
         'cringe': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_cringe.bam',
         'conked': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_conked.bam',
         'catchneutral': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_gameneutral.bam',
         'catchrun': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_gamerun.bam',
         'hold-bottle': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_hold-bottle.bam',
         'push-button': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_press-button.bam',
         'happy-dance': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_happy-dance.bam',
         'juggle': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_juggle.bam',
         'shout': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_shout.bam',
         'dneutral': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_sad-neutral.bam',
         'dwalk': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_losewalk.bam',
         'smooch': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_smooch.bam',
         'conked': 'phase_3.5/models/char/tt_a_chr_' + torsotype + '_torso_conked.bam',
         'sound': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_shout.bam',
         'sprinkle-dust': 'phase_5/models/char/tt_a_chr_' + torsotype + '_torso_sprinkle-dust.bam',
         'start-sit': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_intoSit.bam',
         'sit': 'phase_4/models/char/tt_a_chr_' + torsotype + '_torso_sit.bam'}, 'torso')

    def generateHead(self, pat = 0):
        gender = self.getGender()
        head = self.getAnimal()
        headtype = self.getHead()
        ToonHead.generateHead(self, gender, head, headtype)

    def setToonColor(self):
        self.setHeadColor()
        self.setTorsoColor()
        self.setLegColor()

    def setLegColor(self):
        legcolor = self.getLegColor()
        self.findAllMatches('**/legs').setColor(legcolor)
        self.findAllMatches('**/feet').setColor(legcolor)

    def setTorsoColor(self):
        torsocolor = self.getTorsoColor()
        self.findAllMatches('**/arms').setColor(torsocolor)
        self.findAllMatches('**/neck').setColor(torsocolor)
        self.findAllMatches('**/hands').setColor(1, 1, 1, 1)

    def setForcedTorsoAnim(self, string):
        self.forcedTorsoAnim = string
        self.loop(string, partName='torso')

    def clearForcedTorsoAnim(self):
        self.forcedTorsoAnim = None
        self.animFSM.request(self.animFSM.getCurrentState().getName())
        return

    def enterOff(self, ts = 0, callback = None, extraArgs = []):
        self.currentAnim = None
        return

    def exitOff(self):
        pass

    def enterWin(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'win'
        self.sfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/ENC_Win.mp3')
        self.sfx.setLoop(True)
        base.audio3d.attachSoundToObject(self.sfx, self)
        base.playSfx(self.sfx)
        self.loop('win')

    def exitWin(self):
        self.stop()
        self.sfx.stop()
        del self.sfx
        self.playingAnim = 'neutral'

    def enterShrug(self, ts = 0, callback = None, extraArgs = []):
        self.play('shrug')

    def exitShrug(self):
        self.exitGeneral()

    def enterHDance(self, ts = 0, callback = None, extraArgs = []):
        self.play('hdance')

    def exitHDance(self):
        self.exitGeneral()

    def enterScientistWork(self, ts = 0, callback = None, extraArgs = []):
        self.loop('scwork')

    def exitScientistWork(self):
        self.exitGeneral()

    def enterScientistEmcee(self, ts = 0, callback = None, extraArgs = []):
        self.loop('scemcee')

    def exitScientistEmcee(self):
        self.exitGeneral()

    def enterScientistGame(self, ts = 0, callback = None, extraArgs = []):
        self.loop('scgame')

    def exitScientistGame(self):
        self.exitGeneral()

    def enterScientistJealous(self, ts = 0, callback = None, extraArgs = []):
        self.loop('scjealous')

    def exitScientistJealous(self):
        self.exitGeneral()

    def enterWave(self, ts = 0, callback = None, extraArgs = []):
        self.play('wave')

    def exitWave(self):
        self.exitGeneral()

    def enterLaugh(self, ts = 0, callback = None, extraArgs = []):
        self.setPlayRate(5.0, 'neutral')
        self.loop('neutral')

    def exitLaugh(self):
        self.setPlayRate(1.0, 'neutral')
        self.stop()

    def enterNeutral(self, ts = 0, callback = None, extraArgs = []):
        if self.backpack:
            if self.backpack.getCurrentGag():
                if self.backpack.getCurrentGag().getState() != GagState.LOADED:
                    self.loop('neutral', partName='legs')
                    if self.animal == 'dog':
                        self.loop('neutral', partName='head')
                    return
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop('neutral', partName='legs')
            return
        else:
            self.loop('neutral')
            self.playingAnim = 'neutral'
            return

    def exitNeutral(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def exitGeneral(self):
        if self.backpack:
            if self.backpack.getCurrentGag():
                if self.backpack.getCurrentGag().getState() != GagState.LOADED:
                    self.stop(partName='legs')
                else:
                    self.stop()
            else:
                self.stop()
        else:
            self.stop()

    def enterRun(self, ts = 0, callback = None, extraArgs = []):
        if self.backpack:
            if self.backpack.getCurrentGag():
                if self.backpack.getCurrentGag().getState() != GagState.LOADED:
                    self.loop('run', partName='legs')
                    if self.animal == 'dog':
                        self.loop('run', partName='head')
                    return
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop('run', partName='legs')
            return
        else:
            self.loop('run')
            return

    def exitRun(self):
        self.exitGeneral()

    def enterWalk(self, ts = 0, callback = None, extraArgs = []):
        if self.backpack:
            if self.backpack.getCurrentGag():
                if self.backpack.getCurrentGag().getState() != GagState.LOADED:
                    self.loop('walk', partName='legs')
                    if self.animal == 'dog':
                        self.loop('walk', partName='head')
                    return
        if self.forcedTorsoAnim != None:
            self.loop(self.forcedTorsoAnim, partName='torso')
            self.loop('walk', partName='legs')
            return
        else:
            self.loop('walk')
            return

    def exitWalk(self):
        self.exitGeneral()

    def enterWalkBack(self, ts = 0, callback = None, extraArgs = []):
        self.setPlayRate(-1.0, 'walk')
        self.enterWalk()

    def exitWalkBack(self):
        self.exitWalk()
        self.setPlayRate(1.0, 'walk')

    def enterOpenBook(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'book'
        self.book1 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'})
        self.book1.reparentTo(self.getPart('torso').find('**/def_joint_right_hold'))
        self.track = ActorInterval(self, 'book', startFrame=CIGlobals.OpenBookFromFrame, endFrame=CIGlobals.OpenBookToFrame, name=self.uniqueName('enterOpenBook'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.__doCallback, [callback, extraArgs])
        self.track.start(ts)
        self.book1.play('chan', fromFrame=CIGlobals.OpenBookFromFrame, toFrame=CIGlobals.OpenBookToFrame)

    def exitOpenBook(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        if self.book1:
            self.book1.cleanup()
            self.book1 = None
        self.playingAnim = 'neutral'
        return

    def enterReadBook(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'book'
        self.book2 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'})
        self.book2.reparentTo(self.getPart('torso').find('**/def_joint_right_hold'))
        self.pingpong('book', fromFrame=CIGlobals.ReadBookFromFrame, toFrame=CIGlobals.ReadBookToFrame)
        self.book2.pingpong('chan', fromFrame=CIGlobals.ReadBookFromFrame, toFrame=CIGlobals.ReadBookToFrame)

    def exitReadBook(self):
        if self.book2:
            self.book2.cleanup()
            self.book2 = None
        self.playingAnim = 'neutral'
        return

    def enterCloseBook(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'book'
        self.book3 = Actor('phase_3.5/models/props/book-mod.bam', {'chan': 'phase_3.5/models/props/book-chan.bam'})
        self.book3.reparentTo(self.getPart('torso').find('**/def_joint_right_hold'))
        self.track = ActorInterval(self, 'book', startFrame=CIGlobals.CloseBookFromFrame, endFrame=CIGlobals.CloseBookToFrame, name=self.uniqueName('enterCloseBook'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.__doCallback, [callback, extraArgs])
        self.track.start(ts)
        self.book3.play('chan', fromFrame=CIGlobals.CloseBookFromFrame, toFrame=CIGlobals.CloseBookToFrame)

    def exitCloseBook(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        if self.book3:
            self.book3.cleanup()
            self.book3 = None
        self.playingAnim = 'neutral'
        return

    def enterTeleportOut(self, ts = 0, callback = None, extraArgs = []):
        self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': enterTeleportOut')
        self.playingAnim = 'tele'
        self.portal1 = Actor('phase_3.5/models/props/portal-mod.bam', {'chan': 'phase_3.5/models/props/portal-chan.bam'})
        self.portal1.play('chan')
        self.portal1.reparentTo(self.getPart('legs').find('**/def_joint_right_hold'))
        self.play('tele')
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('enterTeleportOut')
        else:
            name = 'enterTeleportOut'
        self.track = Sequence(Wait(0.4), Func(self.teleportOutSfx), Wait(1.3), Func(self.throwPortal), Wait(3.4), name=name)
        self.track.delayDelete = DelayDelete.DelayDelete(self, name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getName(), self.teleportOutDone, [callback, extraArgs])
        self.track.start(ts)

    def doPortalBins(self, portal):
        portal.setBin('shadow', 0)
        portal.setDepthWrite(0)
        portal.setDepthTest(0)

    def teleportOutDone(self, callback, requestStatus):
        self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': teleportOutDone')
        self.__doCallback(callback, requestStatus)
        self.exitTeleportOut()

    def teleportOutSfx(self):
        self.outSfx = base.audio3d.loadSfx('phase_3.5/audio/sfx/AV_teleport.mp3')
        base.audio3d.attachSoundToObject(self.outSfx, self.portal1)
        self.outSfx.play()

    def throwPortal(self):
        self.doPortalBins(self.portal1)
        self.portal1.reparentTo(self.getPart('legs').find('**/joint_nameTag'))
        self.portal1.setScale(CIGlobals.PortalScale)
        self.portal1.setY(6.5)
        self.portal1.setH(180)

    def exitTeleportOut(self):
        self.notify.info(str(self.doId) + '-' + str(self.zoneId) + ': exitTeleportOut')
        if self.track != None:
            self.ignore(self.track.getName())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        if self.portal1:
            self.portal1.cleanup()
            self.portal1 = None
        self.playingAnim = 'neutral'
        return

    def getTeleportInTrack(self, portal):
        self.doPortalBins(portal)
        holeTrack = Sequence()
        holeTrack.append(Func(portal.reparentTo, self))
        pos = Point3(0, -2.4, 0)
        holeTrack.append(Func(portal.setPos, pos))
        holeTrack.append(ActorInterval(portal, 'chan', startTime=3.4, endTime=3.1))
        holeTrack.append(Wait(0.6))
        holeTrack.append(ActorInterval(portal, 'chan', startTime=3.1, endTime=3.4))

        def restorePortal(portal):
            portal.setPos(0, 0, 0)
            portal.detachNode()
            portal.clearBin()
            portal.clearDepthTest()
            portal.clearDepthWrite()

        holeTrack.append(Func(restorePortal, portal))
        toonTrack = Sequence(Wait(0.3), Func(self.getGeomNode().show), Func(self.getNameTag().show), ActorInterval(self, 'happy', startTime=0.45))
        if hasattr(self, 'uniqueName'):
            trackName = self.uniqueName('teleportIn')
        else:
            trackName = 'teleportIn'
        return Parallel(toonTrack, holeTrack, name=trackName)

    def enterTeleportIn(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'happy'
        self.portal2 = Actor('phase_3.5/models/props/portal-mod.bam', {'chan': 'phase_3.5/models/props/portal-chan.bam'})
        self.show()
        self.getGeomNode().hide()
        self.getNameTag().hide()
        self.track = self.getTeleportInTrack(self.portal2)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getName(), self.teleportInDone, [callback, extraArgs])
        self.track.delayDelete = DelayDelete.DelayDelete(self, self.track.getName())
        self.track.start(ts)

    def teleportInDone(self, callback, extraArgs):
        self.__doCallback(callback, extraArgs)
        self.exitTeleportIn()

    def exitTeleportIn(self):
        if self.track != None:
            self.ignore(self.track.getName())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        if self.portal2:
            self.portal2.cleanup()
            self.portal2 = None
        if self.getGeomNode():
            self.getGeomNode().show()
        if self.getNameTag():
            self.getNameTag().show()
        self.playingAnim = 'neutral'
        return

    def enterFallFWD(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'fallf'
        self.play('fallf')
        Sequence(Wait(0.5), Func(self.fallSfx.play)).start()

    def exitFallFWD(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterFallBCK(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'fallb'
        self.play('fallb')
        Sequence(Wait(0.5), Func(self.fallSfx.play)).start()

    def exitFallBCK(self):
        self.playingAnim = 'neutral'
        self.exitGeneral()

    def enterHappyJump(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'happy'
        self.play('happy')

    def exitHappyJump(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterSwim(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'swim'
        self.loop('swim')
        self.getGeomNode().setP(-89.0)
        self.getGeomNode().setZ(4.0)
        nt = self.getNameTag()
        nt.setX(0)
        nt.setY(-2)
        nt.setZ(5.0)

    def exitSwim(self):
        self.exitGeneral()
        self.getGeomNode().setP(0.0)
        self.getGeomNode().setZ(0.0)
        nt = self.getNameTag()
        nt.setX(0)
        nt.setY(0)
        nt.setZ(self.getHeight() + 0.3)
        self.playingAnim = 'neutral'

    def enterDied(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'lose'
        self.isdying = True
        self.play('lose')
        self.track = Sequence(Wait(2.2), Func(self.dieSfx), Wait(2.8), self.getGeomNode().scaleInterval(2, Point3(0.01), startScale=self.getGeomNode().getScale()), Func(self.delToon), name=self.uniqueName('enterDied'))
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.diedDone, [callback, extraArgs])
        self.track.delayDelete = DelayDelete.DelayDelete(self, 'enterTeleportOut')
        self.track.start(ts)

    def diedDone(self, callback, extraArgs):
        self.__doCallback(callback, extraArgs)
        self.exitDied()

    def __doCallback(self, callback, extraArgs):
        if callback:
            if extraArgs:
                callback(*extraArgs)
            else:
                callback()

    def dieSfx(self):
        self.Losesfx = base.audio3d.loadSfx('phase_5/audio/sfx/ENC_Lose.mp3')
        base.audio3d.attachSoundToObject(self.Losesfx, self)
        self.Losesfx.play()

    def delToon(self):
        self.isdead = True

    def exitDied(self):
        if self.track != None:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        self.rescaleToon()
        self.playingAnim = 'neutral'
        return

    def enterJump(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'jump'
        self.loop('jump')

    def exitJump(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterLeap(self, ts = 0, callback = None, extraArgs = []):
        self.playingAnim = 'leap'
        self.loop('leap')

    def exitLeap(self):
        self.exitGeneral()
        self.playingAnim = 'neutral'

    def enterCringe(self, ts = 0, callback = None, extraArgs = []):
        self.play('cringe')

    def exitCringe(self):
        self.exitGeneral()

    def enterConked(self, ts = 0, callback = None, extraArgs = []):
        self.play('conked')

    def exitConked(self):
        self.exitGeneral()
示例#41
0
class DistributedButterflyAI(DistributedNodeAI):
    notify = directNotify.newCategory('DistributedButterflyAI')

    def __init__(self, air, hood, wingType):
        DistributedNodeAI.__init__(self, air)
        self.hood = hood
        self.wingType = wingType
        self.state = 0
        self.stateChangeTimestamp = 0.0
        self.fromLoc = 0
        self.toLoc = 0

        self.fsm = ClassicFSM('DBFAI', [State('off', self.enterOff, self.exitOff),
                                        State('sit', self.enterSit, self.exitSit),
                                        State('fly', self.enterFly, self.exitFly)],
                              'off', 'off')
        self.fsm.enterInitialState()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterSit(self, fromLoc, toLoc):
        taskMgr.doMethodLater(random.uniform(*ButterflyGlobals.SitTime), self.__flySomewhere, self.uniqueName('stopSittingTask'))

    def __flySomewhere(self, task):
        toLoc = ButterflyGlobals.Spots[self.hood].index(random.choice(ButterflyGlobals.Spots[self.hood]))
        fromLoc = self.toLoc

        self.b_setState(2, fromLoc, toLoc)
        return task.done

    def exitSit(self):
        taskMgr.remove(self.uniqueName('stopSittingTask'))

    def enterFly(self, fromLoc, toLoc):
        distance = (ButterflyGlobals.Spots[self.hood][toLoc] - ButterflyGlobals.Spots[self.hood][fromLoc]).length()
        time = distance / ButterflyGlobals.Speed
        taskMgr.doMethodLater(time, self.__land, self.uniqueName('landTask'))

    def __land(self, task):
        self.b_setState(1, self.toLoc, self.toLoc)
        return task.done

    def exitFly(self):
        taskMgr.remove(self.uniqueName('landTask'))

    def setState(self, state, fromLoc, toLoc):
        self.state = state
        self.fromLoc = fromLoc
        self.toLoc = toLoc
        self.fsm.request(ButterflyGlobals.StateIdx2State[state], [fromLoc, toLoc])

    def b_setState(self, state, fromLoc, toLoc):
        self.setState(state, fromLoc, toLoc)
        self.d_setState(state, fromLoc, toLoc)

    def d_setState(self, state, fromLoc, toLoc):
        self.stateChangeTimestamp = globalClockDelta.getRealNetworkTime()
        self.sendUpdate('setState', [state, fromLoc, toLoc, self.stateChangeTimestamp])

    def getState(self):
        return [self.state, self.fromLoc, self.toLoc, self.stateChangeTimestamp]

    def getWingType(self):
        return self.wingType

    def getHood(self):
        return self.hood

    def announceGenerate(self):
        DistributedNodeAI.announceGenerate(self)
        loc = ButterflyGlobals.Spots[self.hood].index(random.choice(ButterflyGlobals.Spots[self.hood]))
        self.b_setState(1, loc, loc)

    def delete(self):
        self.fsm.requestFinalState()
        self.hood = None
        self.state = None
        self.toLoc = None
        self.fromLoc = None
        self.stateChangeTimestamp = None
        self.wingType = None
        DistributedNodeAI.delete(self)
示例#42
0
class AdminPage(StateData):
    notify = directNotify.newCategory('AdminPage')

    def __init__(self, book, parentFSM):
        self.book = book
        self.parentFSM = parentFSM
        StateData.__init__(self, 'adminPageDone')
        self.fsm = ClassicFSM('AdminPage', [State('off', self.enterOff, self.exitOff),
         State('basePage', self.enterBasePage, self.exitBasePage),
         State('kickSection', self.enterKickSection, self.exitKickSection),
         State('sysMsgSection', self.enterSysMsgSection, self.exitSysMsgSection)], 'off', 'off')
        self.fsm.enterInitialState()
        self.parentFSM.getStateNamed('adminPage').addChild(self.fsm)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enter(self):
        StateData.enter(self)
        self.fsm.request('basePage')

    def exit(self):
        self.fsm.requestFinalState()
        StateData.exit(self)

    def unload(self):
        del self.book
        del self.parentFSM
        del self.fsm
        StateData.unload(self)

    def enterSysMsgSection(self):
        self.book.createPageButtons(None, None)
        self.book.setTitle('System Message')
        geom = CIGlobals.getDefaultBtnGeom()
        self.infoLbl = OnscreenText(text='Inform all online players about something.', pos=(0, 0.45))
        self.msgEntry = DirectEntry(initialText='System Message...', scale=0.055, width=15, numLines=4, command=self.sendSystemMessageCommand, focusInCommand=base.localAvatar.chatInput.disableKeyboardShortcuts, focusOutCommand=base.localAvatar.chatInput.enableKeyboardShortcuts, pos=(-0.4, 0, 0))
        self.sendBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Send', pos=(0, 0, -0.35), text_pos=(0, -0.01), command=self.sendSystemMessageCommand)
        self.cancelBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Cancel', pos=(-0.45, 0.15, -0.55), text_pos=(0, -0.01), command=self.fsm.request, extraArgs=['basePage'])
        return

    def sendSystemMessageCommand(self, foo = None):
        msg = self.msgEntry.get()
        base.cr.myDistrict.sendUpdate('systemMessageCommand', [base.localAvatar.getAdminToken(), msg])
        self.fsm.request('basePage')

    def exitSysMsgSection(self):
        self.infoLbl.destroy()
        del self.infoLbl
        self.msgEntry.destroy()
        del self.msgEntry
        self.sendBtn.destroy()
        del self.sendBtn
        self.cancelBtn.destroy()
        del self.cancelBtn
        self.book.clearTitle()
        self.book.deletePageButtons(False, False)

    def enterKickSection(self):
        self.book.createPageButtons(None, None)
        self.book.setTitle('Kick Player')
        geom = CIGlobals.getDefaultBtnGeom()
        self.infoLbl = OnscreenText(text='Type the ID of the player you want to boot out.', pos=(0, 0.45))
        self.idEntry = DirectEntry(width=10, scale=0.12, pos=(-0.59, 0, 0.15), command=self.sendKickMessage, focusInCommand=base.localAvatar.chatInput.disableKeyboardShortcuts, focusOutCommand=base.localAvatar.chatInput.enableKeyboardShortcuts)
        self.kickBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Kick', pos=(0, 0, -0.15), text_pos=(0, -0.01), command=self.sendKickMessage)
        self.banBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Ban', pos=(0, 0, -0.25), text_pos=(0, -0.01), command=self.sendKickMessage, extraArgs=[None, 1])
        self.cancelBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Cancel', pos=(-0.45, 0.15, -0.45), text_pos=(0, -0.01), command=self.fsm.request, extraArgs=['basePage'])
        return

    def sendKickMessage(self, foo = None, andBan = 0):
        if self.idEntry.get().isspace() or len(self.idEntry.get()) == 0:
            return
        print 'Sending out kick request for avatar id: ' + str(self.idEntry.get())
        base.localAvatar.sendUpdate('requestEject', [int(self.idEntry.get()), andBan])
        self.fsm.request('basePage')

    def exitKickSection(self):
        self.banBtn.destroy()
        del self.banBtn
        self.infoLbl.destroy()
        del self.infoLbl
        self.cancelBtn.destroy()
        del self.cancelBtn
        self.idEntry.destroy()
        del self.idEntry
        self.kickBtn.destroy()
        del self.kickBtn
        self.book.deletePageButtons(False, False)
        self.book.clearTitle()

    def enterBasePage(self):
        self.book.createPageButtons('releaseNotesPage', None)
        self.book.setTitle('Admin Stuff')
        geom = CIGlobals.getDefaultBtnGeom()
        self.suitSpawnerBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='', pos=(-0.45, 0.15, 0.5), text_pos=(0, -0.01), command=self.sendSuitCommand, extraArgs=['suitSpawner'])
        self.killCogsBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Kill All Cogs', pos=(-0.45, 0.15, 0.4), text_pos=(0, -0.01), command=self.sendSuitCommand, extraArgs=['killCogs'])
        self.makeTournamentBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Make Cog Tournament', pos=(-0.45, 0.15, 0.3), text_pos=(0, -0.01), command=self.sendSuitCommand, extraArgs=['tournament'])
        self.makeInvasionBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Make Cog Invasion', pos=(-0.45, 0.15, 0.2), text_pos=(0, -0.01), command=self.sendSuitCommand, extraArgs=['invasion'])
        self.makeCogBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Make Cog', pos=(-0.45, 0.15, 0.1), text_pos=(0, -0.01), command=self.sendSuitCommand, extraArgs=['suit'])
        self.ghostBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='', pos=(0.45, 0.15, 0.5), text_pos=(0, -0.01), command=self.changeGhost)
        self.bgBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Toggle Background', pos=(0.45, 0.15, 0.4), text_pos=(0, -0.01), command=self.toggleBackground)
        self.idBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Toggle Player Ids', pos=(0.45, 0.15, 0.3), text_pos=(0, -0.01), command=self.togglePlayerIds)
        self.kickBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='Kick Player', pos=(0.45, 0.15, 0.2), text_pos=(0, -0.01), command=self.openKickPage)
        self.systemMsgBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text='System Message', pos=(0.45, 0.15, 0.1), text_pos=(0, -0.01), command=self.openSysMsgPage)
        if base.localAvatar.getGhost():
            self.ghostBtn['text'] = 'Turn Ghost Off'
        else:
            self.ghostBtn['text'] = 'Turn Ghost On'
        base.cr.playGame.getPlace().maybeUpdateAdminPage()
        del geom
        return

    def togglePlayerIds(self):
        if base.cr.isShowingPlayerIds:
            base.cr.hidePlayerIds()
        else:
            base.cr.showPlayerIds()

    def toggleBackground(self):
        if render.isHidden():
            render.show()
        else:
            render.hide()
        if self.book.book_img.isHidden():
            self.book.book_img.show()
        else:
            self.book.book_img.hide()

    def changeGhost(self):
        if base.localAvatar.getGhost():
            base.localAvatar.b_setGhost(0)
            self.ghostBtn['text'] = 'Turn Ghost On'
        else:
            base.localAvatar.b_setGhost(1)
            self.ghostBtn['text'] = 'Turn Ghost Off'

    def sendSuitCommand(self, commandName):
        if base.cr.playGame.suitManager:
            base.cr.playGame.suitManager.sendUpdate('suitAdminCommand', [base.localAvatar.getAdminToken(), commandName])

    def openKickPage(self):
        self.fsm.request('kickSection')

    def openSysMsgPage(self):
        self.fsm.request('sysMsgSection')

    def exitBasePage(self):
        self.systemMsgBtn.destroy()
        del self.systemMsgBtn
        self.idBtn.destroy()
        del self.idBtn
        self.kickBtn.destroy()
        del self.kickBtn
        self.bgBtn.destroy()
        del self.bgBtn
        self.ghostBtn.destroy()
        del self.ghostBtn
        self.suitSpawnerBtn.destroy()
        del self.suitSpawnerBtn
        self.killCogsBtn.destroy()
        del self.killCogsBtn
        self.makeTournamentBtn.destroy()
        del self.makeTournamentBtn
        self.makeInvasionBtn.destroy()
        del self.makeInvasionBtn
        self.makeCogBtn.destroy()
        del self.makeCogBtn
        self.book.clearTitle()
        self.book.deletePageButtons(True, False)
示例#43
0
class TownLoader(StateData):
    notify = directNotify.newCategory('TownLoader')

    def __init__(self, hood, parentFSMState, doneEvent):
        self.hood = hood
        self.parentFSMState = parentFSMState
        StateData.__init__(self, doneEvent)
        self.fsm = ClassicFSM('TownLoader', [State('start', self.enterStart, self.exitStart, ['quietZone', 'street']),
         State('street', self.enterStreet, self.exitStreet, ['quietZone']),
         State('toonInterior', self.enterToonInterior, self.exitToonInterior, ['quietZone']),
         State('quietZone', self.enterQuietZone, self.exitQuietZone, ['street', 'toonInterior']),
         State('final', self.enterFinal, self.exitFinal, ['start'])], 'start', 'final')
        self.branchZone = None
        self.canonicalBranchZone = None
        self.placeDoneEvent = 'placeDone'
        self.linkTunnels = []
        return

    def findAndMakeLinkTunnels(self, requestStatus):
        for tunnel in self.geom.findAllMatches('**/*linktunnel*'):
            dnaRootStr = tunnel.getName()
            zone = LinkTunnel.getZoneFromDNARootStr(dnaRootStr)
            zone = LinkTunnel.maybeFixZone(zone)
            tunnelClass = LinkTunnel.getRecommendedTunnelClassFromZone(zone)
            link = tunnelClass(tunnel, dnaRootStr)
            self.linkTunnels.append(link)

    def load(self, zoneId):
        StateData.load(self)
        self.zoneId = zoneId
        self.branchZone = ZoneUtil.getBranchZone(zoneId)
        self.canonicalBranchZone = ZoneUtil.getCanonicalBranchZone(zoneId)
        self.music = base.loadMusic(self.musicFile)
        self.interiorMusic = base.loadMusic(self.interiorMusicFile)

    def unload(self):
        self.parentFSMState.removeChild(self.fsm)
        del self.parentFSMState
        del self.fsm
        del self.streetClass
        self.landmarkBlocks.removeNode()
        del self.landmarkBlocks
        self.hood.dnaStore.resetSuitPoints()
        self.hood.dnaStore.resetBattleCells()
        del self.hood
        del self.nodeDict
        del self.zoneDict
        del self.fadeInDict
        del self.fadeOutDict
        del self.nodeList
        self.geom.removeNode()
        del self.geom
        del self.music
        del self.interiorMusic
        ModelPool.garbageCollect()
        TexturePool.garbageCollect()
        StateData.unload(self)

    def enter(self, requestStatus):
        StateData.enter(self)
        self.findAndMakeLinkTunnels(requestStatus)
        self.fsm.enterInitialState()
        self.setState(requestStatus['where'], requestStatus)

    def exit(self):
        self.fsm.requestFinalState()
        self.ignoreAll()
        ModelPool.garbageCollect()
        TexturePool.garbageCollect()
        StateData.exit(self)

    def setState(self, state, requestStatus):
        self.fsm.request(state, [requestStatus])

    def enterStart(self):
        pass

    def exitStart(self):
        pass

    def enterStreet(self, requestStatus):
        self.acceptOnce(self.placeDoneEvent, self.streetDone)
        self.place = self.streetClass(self, self.fsm, self.placeDoneEvent)
        self.place.load()

    def exitStreet(self):
        self.ignore(self.placeDoneEvent)
        self.place.exit()
        self.place.unload()
        self.place = None
        base.cr.playGame.setPlace(self.place)
        return

    def streetDone(self):
        self.requestStatus = self.place.doneStatus
        status = self.place.doneStatus
        if status['loader'] == 'townLoader' and ZoneUtil.getBranchZone(status['zoneId']) == self.branchZone and status['shardId'] == None or status['how'] == 'doorOut':
            self.fsm.request('quietZone', [status])
        else:
            self.doneStatus = status
            messenger.send(self.doneEvent)
        return

    def enterToonInterior(self, requestStatus):
        self.acceptOnce(self.placeDoneEvent, self.handleToonInteriorDone)
        self.place = ToonInterior.ToonInterior(self, self.fsm, self.placeDoneEvent)
        self.place.load()

    def exitToonInterior(self):
        self.ignore(self.placeDoneEvent)
        self.place.exit()
        self.place.unload()
        self.place = None
        base.cr.playGame.setPlace(self.place)
        return

    def enterThePlace(self, requestStatus):
        base.cr.playGame.setPlace(self.place)
        self.place.enter(requestStatus)

    def handleToonInteriorDone(self):
        status = self.place.doneStatus
        if status['loader'] == 'townLoader' and ZoneUtil.getBranchZone(status['zoneId']) == self.branchZone and status['shardId'] == None or status['how'] == 'doorOut':
            self.fsm.request('quietZone', [status])
        else:
            self.doneStatus = status
            messenger.send(self.doneEvent)
        return

    def enterQuietZone(self, requestStatus):
        self.fsm.request(requestStatus['where'], [requestStatus], exitCurrent=0)
        self.quietZoneDoneEvent = uniqueName('quietZoneDone')
        self.acceptOnce(self.quietZoneDoneEvent, self.handleQuietZoneDone)
        self.quietZoneStateData = QuietZoneState(self.quietZoneDoneEvent)
        self.quietZoneStateData.load()
        self.quietZoneStateData.enter(requestStatus)

    def exitQuietZone(self):
        self.ignore(self.quietZoneDoneEvent)
        del self.quietZoneDoneEvent
        self.quietZoneStateData.exit()
        self.quietZoneStateData.unload()
        self.quietZoneStateData = None
        return

    def handleQuietZoneDone(self):
        status = self.quietZoneStateData.getRequestStatus()
        self.exitQuietZone()
        self.enterThePlace(status)

    def enterFinal(self):
        pass

    def exitFinal(self):
        pass

    def createHood(self, dnaFile, loadStorage = 1):
        if loadStorage:
            loader.loadDNAFile(self.hood.dnaStore, 'phase_5/dna/storage_town.dna')
            loader.loadDNAFile(self.hood.dnaStore, self.townStorageDNAFile)
        node = loader.loadDNAFile(self.hood.dnaStore, dnaFile)
        if node.getNumParents() == 1:
            self.geom = NodePath(node.getParent(0))
            self.geom.reparentTo(hidden)
        else:
            self.geom = hidden.attachNewNode(node)
        self.makeDictionaries(self.hood.dnaStore)
        self.reparentLandmarkBlockNodes()
        self.renameFloorPolys(self.nodeList)
        gsg = base.win.getGsg()
        if gsg:
            self.geom.prepareScene(gsg)
        self.geom.flattenLight()
        self.geom.setName('town_top_level')

    def reparentLandmarkBlockNodes(self):
        bucket = self.landmarkBlocks = hidden.attachNewNode('landmarkBlocks')
        npc = self.geom.findAllMatches('**/sb*:*_landmark_*_DNARoot')
        for i in xrange(npc.getNumPaths()):
            nodePath = npc.getPath(i)
            nodePath.wrtReparentTo(bucket)

        npc = self.geom.findAllMatches('**/sb*:*animated_building*_DNARoot')
        for i in xrange(npc.getNumPaths()):
            nodePath = npc.getPath(i)
            nodePath.wrtReparentTo(bucket)

    def makeDictionaries(self, dnaStore):
        self.nodeDict = {}
        self.zoneDict = {}
        self.zoneVisDict = {}
        self.nodeList = []
        self.fadeInDict = {}
        self.fadeOutDict = {}
        a1 = Vec4(1, 1, 1, 1)
        a0 = Vec4(1, 1, 1, 0)
        numVisGroups = dnaStore.getNumDNAVisGroupsAI()
        for i in xrange(numVisGroups):
            groupFullName = dnaStore.getDNAVisGroupName(i)
            visGroup = dnaStore.getDNAVisGroupAI(i)
            groupName = base.cr.hoodMgr.extractGroupName(groupFullName)
            zoneId = int(groupName)
            zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
            groupNode = self.geom.find('**/' + groupFullName)
            if groupNode.isEmpty():
                continue
            else:
                if ':' in groupName:
                    groupName = '%s%s' % (zoneId, groupName[groupName.index(':'):])
                else:
                    groupName = '%s' % zoneId
                groupNode.setName(groupName)
            groupNode.flattenMedium()
            self.nodeDict[zoneId] = []
            self.nodeList.append(groupNode)
            self.zoneDict[zoneId] = groupNode
            visibles = []
            for i in xrange(visGroup.getNumVisibles()):
                visibles.append(int(visGroup.visibles[i]))

            visibles.append(ZoneUtil.getBranchZone(zoneId))
            self.zoneVisDict[zoneId] = visibles
            fadeDuration = 0.5
            self.fadeOutDict[groupNode] = Sequence(Func(groupNode.setTransparency, 1), LerpColorScaleInterval(groupNode, fadeDuration, a0, startColorScale=a1), Func(groupNode.clearColorScale), Func(groupNode.clearTransparency), Func(groupNode.stash), name='fadeZone-' + str(zoneId), autoPause=1)
            self.fadeInDict[groupNode] = Sequence(Func(groupNode.unstash), Func(groupNode.setTransparency, 1), LerpColorScaleInterval(groupNode, fadeDuration, a1, startColorScale=a0), Func(groupNode.clearColorScale), Func(groupNode.clearTransparency), name='fadeZone-' + str(zoneId), autoPause=1)

        for i in xrange(numVisGroups):
            groupFullName = dnaStore.getDNAVisGroupName(i)
            zoneId = int(base.cr.hoodMgr.extractGroupName(groupFullName))
            zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
            for j in xrange(dnaStore.getNumVisiblesInDNAVisGroup(i)):
                visName = dnaStore.getVisibleName(i, j)
                groupName = base.cr.hoodMgr.extractGroupName(visName)
                nextZoneId = int(groupName)
                nextZoneId = ZoneUtil.getTrueZoneId(nextZoneId, self.zoneId)
                visNode = self.zoneDict[nextZoneId]
                self.nodeDict[zoneId].append(visNode)

        self.hood.dnaStore.resetPlaceNodes()
        self.hood.dnaStore.resetDNAGroups()
        self.hood.dnaStore.resetDNAVisGroups()
        self.hood.dnaStore.resetDNAVisGroupsAI()

    def renameFloorPolys(self, nodeList):
        for i in nodeList:
            collNodePaths = i.findAllMatches('**/+CollisionNode')
            numCollNodePaths = collNodePaths.getNumPaths()
            visGroupName = i.node().getName()
            for j in xrange(numCollNodePaths):
                collNodePath = collNodePaths.getPath(j)
                bitMask = collNodePath.node().getIntoCollideMask()
                if bitMask.getBit(1):
                    collNodePath.node().setName(visGroupName)
示例#44
0
class DistributedBoat(DistributedObject):
    notify = directNotify.newCategory('DistributedBoat')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedBoat', [State('off', self.enterOff, self.exitOff), State('eastToWest', self.enterEastToWest, self.exitEastToWest), State('westToEast', self.enterWestToEast, self.exitWestToEast)], 'off', 'off')
        self.boat = None
        self.eastPier = None
        self.eastPierPath = 'east_pier'
        self.westPier = None
        self.westPierPath = 'west_pier'
        self.pierUpP = 0.0
        self.pierDownP = -45.0
        self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.mp3'
        self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.mp3'
        self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.mp3'
        self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.mp3'
        self.eastWest = 'phase_6/paths/dd-e-w.bam'
        self.westEast = 'phase_6/paths/dd-w-e.bam'
        self.boatPath = '*donalds_boat*'
        self.track = None
        self.state = None
        return

    def __handleOnBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat)
        base.playSfx(self.soundWaterLap, looping=1)

    def __handleOffBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPRender)
        self.soundWaterLap.stop()

    def __pollBoat(self, task):
        try:
            self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath)
        except:
            return task.cont

        self.generated()
        return task.done

    def generate(self):
        DistributedObject.generate(self)
        self.soundFogHorn = base.loadSfx(self.fogHorn)
        self.soundShipBell = base.loadSfx(self.shipBell)
        self.soundWaterLap = base.loadSfx(self.waterLap)
        self.soundDockCreak = base.loadSfx(self.dockCreak)
        self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath)
        self.generated()

    def generated(self):
        self.eastPier = self.cr.playGame.hood.loader.geom.find('**/' + self.eastPierPath)
        self.westPier = self.cr.playGame.hood.loader.geom.find('**/' + self.westPierPath)
        base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boat)
        self.accept('enterdonalds_boat_floor', self.__handleOnBoat)
        self.accept('exitdonalds_boat_floor', self.__handleOffBoat)
        self.d_requestCurrentStateAndTimestamp()
        self.fsm.enterInitialState()

    def disable(self):
        base.taskMgr.remove(self.uniqueName('__pollBoat'))
        base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat)
        self.ignore('enterdonalds_boat_floor')
        self.ignore('exitdonalds_boat_floor')
        self.fsm.requestFinalState()
        del self.fsm
        del self.soundFogHorn
        del self.soundShipBell
        del self.soundWaterLap
        del self.soundDockCreak
        self.fogHorn = None
        self.shipBell = None
        self.waterLap = None
        self.dockCreak = None
        self.boat = None
        self.track = None
        self.pierDownP = None
        self.pierUpP = None
        self.eastPier = None
        self.eastPierPath = None
        self.westPier = None
        self.westPierPath = None
        self.boatPath = None
        self.westEast = None
        self.eastWest = None
        DistributedObject.disable(self)
        return

    def currentStateAndTimestamp(self, state, timestamp):
        self.setState(state, timestamp)

    def d_requestCurrentStateAndTimestamp(self):
        self.sendUpdate('requestCurrentStateAndTimestamp', [])

    def setState(self, state, timestamp = None):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        self.state = state
        if self.boat:
            self.fsm.request(state, [ts])
        return

    def enterEastToWest(self, ts = 0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.eastWest)
        moIval = MopathInterval(moPath, self.boat)
        self.track = Parallel(SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.eastPier), moIval, LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierDownP, 0), startHpr=(90, self.pierUpP, 0)), Sequence(Wait(15.0), Parallel(LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierUpP, 0), startHpr=(-90, self.pierDownP, 0)), Sequence(Wait(2.0), SoundInterval(self.soundDockCreak, node=self.westPier))), SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitEastToWest(self):
        if self.track:
            self.track.finish()
            self.track = None
        return

    def enterWestToEast(self, ts = 0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.westEast)
        moIval = MopathInterval(moPath, self.boat)
        self.track = Parallel(SoundInterval(self.soundShipBell, node=self.boat), SoundInterval(self.soundDockCreak, node=self.westPier), moIval, LerpQuatInterval(self.westPier, duration=5.0, quat=(-90, self.pierDownP, 0), startHpr=(-90, self.pierUpP, 0)), Sequence(Wait(15.0), Parallel(LerpQuatInterval(self.eastPier, duration=5.0, quat=(90, self.pierUpP, 0), startHpr=(90, self.pierDownP, 0)), Sequence(Wait(2.0), SoundInterval(self.soundDockCreak, node=self.eastPier))), SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitWestToEast(self):
        if self.track:
            self.track.finish()
            self.track = None
        return

    def enterOff(self):
        pass

    def exitOff(self):
        pass
示例#45
0
class RemoteToonBattleAvatar(RemoteAvatar):
    notify = directNotify.newCategory("RemoteToonBattleAvatar")

    def __init__(self, mg, cr, avId, gunName="pistol"):
        RemoteAvatar.__init__(self, mg, cr, avId)
        self.track = None
        self.gunName = gunName
        self.fsm = ClassicFSM('RemoteToonBattleAvatar', [
            State('off', self.enterOff, self.exitOff),
            State('shoot', self.enterShoot, self.exitShoot),
            State('die', self.enterDie, self.exitDie),
            State('dead', self.enterDead, self.exitDead)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.soundGrunt = None
        self.retrieveAvatar()

    def setTeam(self, team):
        RemoteAvatar.setTeam(self, team)

        self.teamText.node().setText(GGG.TeamNameById[team][0])
        self.teamText.node().setTextColor(GGG.TeamColorById[team])

    def setGunName(self, gunName):
        self.gunName = gunName
        self.avatar.attachGun(gunName)
        if self.gunName == 'shotgun':
            if self.team:
                color = GGG.TeamColorById[self.team]
                self.avatar.gun.setColorScale(color)
        elif self.gunName == 'sniper':
            if self.team:
                color = GGG.TeamColorById[self.team]
                self.avatar.gun.setColorScale(color)

    def getGunName(self):
        return self.gunName

    def retrieveAvatar(self):
        RemoteAvatar.retrieveAvatar(self)
        if self.avatar:
            self.soundGrunt = base.loadSfx(
                'phase_4/audio/sfx/target_impact_grunt1.ogg')

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def grunt(self):
        base.playSfx(self.soundGrunt, node=self.avatar)

    def enterDead(self):
        if self.avatar:
            self.avatar.stash()

    def exitDead(self):
        if self.avatar:
            self.avatar.unstash()
            self.avatar.clearColorScale()
            self.avatar.getGeomNode().clearColorScale()
            self.avatar.clearTransparency()
            self.avatar.getGeomNode().clearTransparency()
            self.avatar.getNameTag().clearColorScale()

    def enterDie(self, ts):
        if self.avatar:
            dieSound = base.audio3d.loadSfx(
                self.avatar.getToonAnimalNoise('exclaim'))
            base.audio3d.attachSoundToObject(dieSound, self.avatar)
            self.avatar.setTransparency(1)
            self.avatar.getGeomNode().setTransparency(1)
            SoundInterval(dieSound, node=self.avatar).start()
            self.track = Sequence(
                Parallel(
                    LerpColorScaleInterval(self.avatar.getGeomNode(),
                                           colorScale=VBase4(1, 1, 1, 0),
                                           startColorScale=VBase4(1, 1, 1, 1),
                                           duration=0.5),
                    LerpColorScaleInterval(self.avatar.getNameTag(),
                                           colorScale=VBase4(1, 1, 1, 0),
                                           startColorScale=VBase4(1, 1, 1, 1),
                                           duration=0.5),
                    ActorInterval(self.avatar, 'fallb')),
                Func(self.fsm.request, 'dead'))
            self.track.start()
            del dieSound

    def exitDie(self):
        self.resetTrack()

    def resetTrack(self):
        if self.track:
            self.track.pause()
            self.track = None
        #self.avatar.stop()

    def run(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('run', partName='legs')
            else:
                self.avatar.loop('run')

    def strafe(self, playRate):
        if self.avatar:
            self.avatar.setPlayRate(playRate, 'strafe')
            if self.track and self.track.isPlaying():
                self.avatar.loop('strafe', partName='legs')
            else:
                self.avatar.loop('strafe')

    def stand(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('neutral', partName='legs')
            else:
                self.avatar.loop('neutral')

    def jump(self):
        if self.avatar:
            if self.track and self.track.isPlaying():
                self.avatar.loop('jump', partName='legs')
            else:
                self.avatar.loop('jump')

    def enterShoot(self, ts):
        if self.avatar:

            def createBullet():
                if not self.avatar or not self.avatar.gun:
                    return
                if self.gunName == "pistol":
                    Bullet(self.mg, self.avatar.gun.find('**/joint_nozzle'), 0,
                           self.gunName)
                elif self.gunName == "shotgun":
                    b1 = Bullet(self.mg,
                                self.avatar.gun.find('**/joint_nozzle'), 0,
                                self.gunName)
                    b2 = Bullet(self.mg,
                                self.avatar.gun.find('**/joint_nozzle'), 0,
                                self.gunName)
                elif self.gunName == "sniper":
                    b1 = Bullet(self.mg,
                                self.avatar.gun.find('**/joint_nozzle'), 0,
                                self.gunName)
                    b2 = Bullet(self.mg,
                                self.avatar.gun.find('**/joint_nozzle'), 0,
                                self.gunName)

            def changeToLegAnim():
                if not self.avatar:
                    return
                self.avatar.loop(self.avatar.getCurrentAnim(partName='legs'))

            if self.gunName == "pistol":
                gunSound = base.audio3d.loadSfx(
                    "phase_4/audio/sfx/pistol_shoot.ogg")
            elif self.gunName == "shotgun":
                gunSound = base.audio3d.loadSfx(
                    "phase_4/audio/sfx/shotgun_shoot.ogg")
            elif self.gunName == "sniper":
                gunSound = base.audio3d.loadSfx(
                    "phase_4/audio/sfx/shotgun_shoot.ogg")
            base.audio3d.attachSoundToObject(gunSound, self.avatar)
            SoundInterval(gunSound, node=self.avatar).start()
            self.track = Sequence(
                Func(createBullet),
                ActorInterval(self.avatar,
                              "squirt",
                              partName='torso',
                              startFrame=48,
                              endFrame=58),
                ActorInterval(self.avatar,
                              "squirt",
                              partName='torso',
                              startFrame=107,
                              endFrame=126,
                              playRate=3), Func(changeToLegAnim))
            self.track.start()
            del gunSound

            self.mg.makeSmokeEffect(
                self.avatar.gun.find('**/joint_nozzle').getPos(render))

    def exitShoot(self):
        self.resetTrack()

    def cleanup(self):
        if self.avatar:
            self.avatar.detachGun()
        self.soundGrunt = None
        if self.track:
            self.track.pause()
        del self.track
        RemoteAvatar.cleanup(self)
示例#46
0
class DistributedWeatherCycle(DistributedObject):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedWeatherCycle')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM(self.__class__.__name__, [
            State('off', self.enterOff, self.exitOff, ['morning']),
            State('morning', self.enterMorning, self.exitMorning,
                  ['afternoon']),
            State('afternoon', self.enterAfternoon, self.exitAfternoon,
                  ['evening']),
            State('evening', self.enterEvening, self.exitEvening,
                  ['midnight']),
            State('midnight', self.enterMidnight, self.exitMidnight,
                  ['morning'])
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.__interval = None

    def setState(self, state):
        self.fsm.request(state)

    def getState(self):
        return self.fsm.getCurrentState()._State__name

    def setDuration(self, duration):
        self.duration = duration

    def getDuration(self):
        return self.duration

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterMorning(self):
        self.__interval = LerpColorScaleInterval(
            render,
            self.getDuration(),
            WeatherGlobals.cycleColors[0],
            startColorScale=render.getColorScale())
        self.__interval.start()

    def exitMorning(self):
        if not self.__interval:
            return
        self.__interval.finish()
        self.__interval = None

    def enterAfternoon(self):
        self.__interval = LerpColorScaleInterval(
            render,
            self.getDuration(),
            WeatherGlobals.cycleColors[1],
            startColorScale=render.getColorScale())
        self.__interval.start()

    def exitAfternoon(self):
        if not self.__interval:
            return
        self.__interval.finish()
        self.__interval = None

    def enterEvening(self):
        self.__interval = LerpColorScaleInterval(
            render,
            self.getDuration(),
            WeatherGlobals.cycleColors[2],
            startColorScale=render.getColorScale())
        self.__interval.start()

    def exitEvening(self):
        if not self.__interval:
            return
        self.__interval.finish()
        self.__interval = None

    def enterMidnight(self):
        self.__interval = LerpColorScaleInterval(
            render,
            self.getDuration(),
            WeatherGlobals.cycleColors[3],
            startColorScale=render.getColorScale())
        self.__interval.start()

    def exitMidnight(self):
        if not self.__interval:
            return
        self.__interval.finish()
        self.__interval = None
示例#47
0
class DistributedBoat(DistributedObject):
    notify = directNotify.newCategory("DistributedBoat")

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedBoat', [
            State('off', self.enterOff, self.exitOff),
            State('eastToWest', self.enterEastToWest, self.exitEastToWest),
            State('westToEast', self.enterWestToEast, self.exitWestToEast)
        ], 'off', 'off')
        self.boat = None
        self.eastPier = None
        self.eastPierPath = 'east_pier'
        self.westPier = None
        self.westPierPath = 'west_pier'
        self.pierUpP = 0.0
        self.pierDownP = -45.0
        self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.ogg'
        self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.ogg'
        self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.ogg'
        self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.ogg'
        self.eastWest = 'phase_6/paths/dd-e-w.bam'
        self.westEast = 'phase_6/paths/dd-w-e.bam'
        self.boatPath = '*donalds_boat*'
        self.track = None
        self.state = None

    def __handleOnBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat)
        base.playSfx(self.soundWaterLap, looping=1)

    def __handleOffBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPRender)
        self.soundWaterLap.stop()

    def __pollBoat(self, task):
        try:
            self.boat = self.cr.playGame.hood.loader.geom.find('**/' +
                                                               self.boatPath)
        except:
            return task.cont
        self.generated()
        return task.done

    def generate(self):
        DistributedObject.generate(self)
        self.soundFogHorn = base.loadSfx(self.fogHorn)
        self.soundShipBell = base.loadSfx(self.shipBell)
        self.soundWaterLap = base.loadSfx(self.waterLap)
        self.soundDockCreak = base.loadSfx(self.dockCreak)
        #try:
        #    self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath)
        #except:
        #        base.taskMgr.add(self.__pollBoat, self.uniqueName('__pollBoat'))
        #        return
        self.boat = self.cr.playGame.hood.loader.geom.find('**/' +
                                                           self.boatPath)
        self.generated()

    def generated(self):
        self.eastPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.eastPierPath)
        self.westPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.westPierPath)
        base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boat)
        self.accept('enterdonalds_boat_floor', self.__handleOnBoat)
        self.accept('exitdonalds_boat_floor', self.__handleOffBoat)
        self.d_requestCurrentStateAndTimestamp()
        self.fsm.enterInitialState()

    def disable(self):
        base.taskMgr.remove(self.uniqueName('__pollBoat'))
        base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat)
        self.ignore('enterdonalds_boat_floor')
        self.ignore('exitdonalds_boat_floor')
        self.fsm.requestFinalState()
        del self.fsm
        del self.soundFogHorn
        del self.soundShipBell
        del self.soundWaterLap
        del self.soundDockCreak
        self.fogHorn = None
        self.shipBell = None
        self.waterLap = None
        self.dockCreak = None
        self.boat = None
        self.track = None
        self.pierDownP = None
        self.pierUpP = None
        self.eastPier = None
        self.eastPierPath = None
        self.westPier = None
        self.westPierPath = None
        self.boatPath = None
        self.westEast = None
        self.eastWest = None
        DistributedObject.disable(self)

    def currentStateAndTimestamp(self, state, timestamp):
        self.setState(state, timestamp)

    def d_requestCurrentStateAndTimestamp(self):
        self.sendUpdate('requestCurrentStateAndTimestamp', [])

    def setState(self, state, timestamp=None):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        self.state = state
        if self.boat:
            self.fsm.request(state, [ts])

    def enterEastToWest(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.eastWest)
        moIval = MopathInterval(moPath, self.boat)

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.eastPier), moIval,
            LerpQuatInterval(self.eastPier,
                             duration=5.0,
                             quat=(90, self.pierDownP, 0),
                             startHpr=(90, self.pierUpP, 0)),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.westPier,
                                     duration=5.0,
                                     quat=(-90, self.pierUpP, 0),
                                     startHpr=(-90, self.pierDownP, 0)),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.westPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitEastToWest(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterWestToEast(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.westEast)
        moIval = MopathInterval(moPath, self.boat)

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.westPier), moIval,
            LerpQuatInterval(self.westPier,
                             duration=5.0,
                             quat=(-90, self.pierDownP, 0),
                             startHpr=(-90, self.pierUpP, 0)),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.eastPier,
                                     duration=5.0,
                                     quat=(90, self.pierUpP, 0),
                                     startHpr=(90, self.pierDownP, 0)),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.eastPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitWestToEast(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass
示例#48
0
class OptionPage(StateData):

    def __init__(self, book, parentFSM):
        self.book = book
        self.parentFSM = parentFSM
        StateData.__init__(self, 'optionPageDone')
        self.fsm = ClassicFSM('OptionPage', [State('off', self.enterOff, self.exitOff), State('basePage', self.enterBasePage, self.exitBasePage), State('displayPage', self.enterDisplayPage, self.exitDisplayPage)], 'off', 'off')
        self.fsm.enterInitialState()
        self.parentFSM.getStateNamed('optionPage').addChild(self.fsm)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def load(self):
        StateData.load(self)

    def unload(self):
        StateData.unload(self)

    def enter(self):
        StateData.enter(self)
        self.fsm.request('basePage')

    def exit(self):
        self.fsm.request('off')
        StateData.exit(self)

    def openDisplayPage(self):
        self.fsm.request('displayPage')

    def enterDisplayPage(self):
        self.book.createPageButtons(False, False)
        self.book.setTitle('Display Options')
        dialog_gui = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui.bam')
        width, height, fs, music, sfx, tex_detail, model_detail, aa, af = SettingsManager().getSettings('settings.json')
        self.width = width
        self.height = height
        self.windowType = [fs]
        self.buttons = [DirectRadioButton(text='Windowed', variable=self.windowType, value=[False], scale=0.1, pos=(-0.45, 0.15, 0.15)), DirectRadioButton(text='Fullscreen', variable=self.windowType, value=[True], scale=0.1, pos=(-0.45, -0.15, -0.15))]
        for button in self.buttons:
            button.setOthers(self.buttons)

        self.resoLbl = DirectLabel(text='%sx%s' % (width, height), scale=0.08, relief=None, pos=(0.25, 0, 0))
        self.resSlider = DirectSlider(range=(0, 200), pageSize=50, command=self.setResoText, scale=0.3, orientation=DGG.VERTICAL, pos=(0.6, 0, 0))
        self.okBtn = DirectButton(text='OK', geom=CIGlobals.getOkayBtnGeom(), relief=None, pos=(-0.5, -0.5, -0.5), text_scale=0.05, text_pos=(0, -0.11), command=self.applyDisplaySettings)
        self.cancelBtn = DirectButton(text='Cancel', geom=CIGlobals.getCancelBtnGeom(), relief=None, pos=(-0.3, -0.5, -0.5), text_scale=0.05, text_pos=(0, -0.11), command=self.cancelDisplaySettings)
        if self.resoLbl['text'] == '640x480':
            self.resSlider['value'] = 0
        elif self.resoLbl['text'] == '800x600':
            self.resSlider['value'] = 50
        elif self.resoLbl['text'] == '1024x768':
            self.resSlider['value'] = 100
        elif self.resoLbl['text'] == '1280x1024':
            self.resSlider['value'] = 150
        elif self.resoLbl['text'] == '1600x1200':
            self.resSlider['value'] = 200
        return

    def exitDisplayPage(self):
        for button in self.buttons:
            button.destroy()
            del button

        self.resoLbl.destroy()
        del self.resoLbl
        self.resSlider.destroy()
        del self.resSlider
        self.okBtn.destroy()
        del self.okBtn
        self.cancelBtn.destroy()
        del self.cancelBtn
        del self.width
        del self.height
        del self.windowType
        del self.buttons
        self.book.clearTitle()

    def changeSetting(self, setting, value):
        if setting == 'music':
            if value:
                value = False
            elif not value:
                value = True
            base.enableMusic(value)
            self.music_btn['extraArgs'] = ['music', value]
            if value:
                valueTxt = 'On'
            else:
                valueTxt = 'Off'
            self.music_lbl['text'] = str(valueTxt).capitalize()
        elif setting == 'sfx':
            if value:
                value = False
            elif not value:
                value = True
            base.enableSoundEffects(value)
            self.sfx_btn['extraArgs'] = ['sfx', value]
            if value:
                valueTxt = 'On'
            else:
                valueTxt = 'Off'
            self.sfx_lbl['text'] = str(valueTxt).capitalize()
        elif setting == 'model-detail':
            if value == 'high':
                value = 'low'
            elif value == 'medium':
                value = 'high'
            elif value == 'low':
                value = 'medium'
            self.moddet_lbl['text'] = value.capitalize()
            self.moddet_btn['extraArgs'] = ['model-detail', value]
        elif setting == 'texture-detail':
            if value == 'normal':
                value = 'low'
                loadPrcFileData('', 'compressed-textures 1')
            elif value == 'low':
                value = 'normal'
                loadPrcFileData('', 'compressed-textures 0')
            self.texdet_lbl['text'] = value.capitalize()
            self.texdet_btn['extraArgs'] = ['texture-detail', value]
        elif setting == 'aa':
            if value == 'on':
                value = 'off'
                render.clear_antialias()
            elif value == 'off':
                value = 'on'
                render.set_antialias(AntialiasAttrib.MAuto)
            self.aa_lbl['text'] = value.capitalize()
            self.aa_btn['extraArgs'] = ['aa', value]
        elif setting == 'af':
            if value == 'on':
                value = 'off'
            elif value == 'off':
                value = 'on'
            self.af_lbl['text'] = value.capitalize()
            self.af_btn['extraArgs'] = ['af', value]
        SettingsManager().writeSettingToFile(setting, value, 'settings.json')

    def setResoText(self):
        if self.resSlider['value'] == 200:
            self.width = 1600
            self.height = 1200
        elif 150 <= self.resSlider['value'] <= 199:
            self.width = 1280
            self.height = 1024
        elif 100 <= self.resSlider['value'] <= 149:
            self.width = 1024
            self.height = 768
        elif 50 <= self.resSlider['value'] <= 99:
            self.width = 800
            self.height = 600
        elif self.resSlider['value'] == 0:
            self.width = 640
            self.height = 480
        self.resoLbl['text'] = str(self.width) + 'x' + str(self.height)

    def applyDisplaySettings(self):
        SettingsManager().writeSettingToFile('resolution', (self.width, self.height), 'settings.json', apply=1)
        SettingsManager().writeSettingToFile('fullscreen', self.windowType, 'settings.json', apply=1)
        self.fsm.request('basePage')

    def cancelDisplaySettings(self):
        self.fsm.request('basePage')

    def enterBasePage(self):
        self.book.createPageButtons(None, 'districtPage')
        self.book.setTitle('Options')
        width, height, fs, music, sfx, tex_detail, model_detail, aa, af = SettingsManager().getSettings('settings.json')
        if music:
            musicTxt = 'On'
        else:
            musicTxt = 'Off'
        if sfx:
            sfxTxt = 'On'
        else:
            sfxTxt = 'Off'
        if fs:
            fsTxt = 'On'
        else:
            fsTxt = 'Off'
        self.music_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Music', scale=1, text_scale=0.055, command=self.changeSetting, extraArgs=['music', music], pos=(-0.45, 0.55, 0.55), text_pos=(0, -0.01))
        self.music_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, 0.55, 0.52), text_align=TextNode.ACenter)
        self.music_lbl['text'] = str(musicTxt).capitalize()
        self.sfx_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='SFX', scale=1, text_scale=0.055, command=self.changeSetting, extraArgs=['sfx', sfx], pos=(-0.45, 0.45, 0.45), text_pos=(0, -0.01))
        self.sfx_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, 0.45, 0.42), text_align=TextNode.ACenter)
        self.sfx_lbl['text'] = str(sfxTxt).capitalize()
        self.moddet_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Model Detail', scale=1, text_scale=0.055, command=self.changeSetting, extraArgs=['model-detail', model_detail], pos=(-0.45, 0.35, 0.35), text_pos=(0, -0.01))
        self.moddet_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, 0.35, 0.32), text_align=TextNode.ACenter)
        self.moddet_lbl['text'] = model_detail.capitalize()
        self.moddet_btn.bind(DGG.ENTER, self.createMustRestartGui)
        self.moddet_btn.bind(DGG.EXIT, self.removeMustRestartGui)
        self.texdet_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Texture Detail', scale=1, text_scale=0.0535, command=self.changeSetting, extraArgs=['texture-detail', tex_detail], pos=(-0.45, 0.25, 0.25), text_pos=(0, -0.01))
        self.texdet_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, 0.25, 0.22), text_align=TextNode.ACenter)
        self.texdet_lbl['text'] = tex_detail.capitalize()
        self.texdet_btn.bind(DGG.ENTER, self.createMustRestartGui)
        self.texdet_btn.bind(DGG.EXIT, self.removeMustRestartGui)
        self.display_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Display', command=self.openDisplayPage, scale=1, text_scale=0.0535, pos=(-0.45, -0.25, 0.02), text_pos=(0, -0.01))
        self.display_lbl = DirectLabel(relief=None, scale=0.06, pos=(0.45, -0.25, 0.02), text_align=TextNode.ACenter)
        self.display_lbl['text'] = 'Fullscreen: %s\nResolution: %s' % (str(fsTxt).capitalize(), (width, height))
        self.aa_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Anti-Aliasing', command=self.changeSetting, extraArgs=['aa', aa], scale=1, text_scale=0.0535, pos=(-0.45, -0.35, -0.18), text_pos=(0, -0.01))
        self.aa_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, -0.35, -0.21), text_align=TextNode.ACenter)
        self.aa_lbl['text'] = aa.capitalize()
        self.af_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Anisotropic Filtering', command=self.changeSetting, extraArgs=['af', af], scale=1, text_scale=0.0435, pos=(-0.45, -0.35, -0.28), text_pos=(0, -0.01))
        self.af_lbl = DirectLabel(relief=None, scale=0.09, pos=(0.45, -0.35, -0.31), text_align=TextNode.ACenter)
        self.af_lbl['text'] = af.capitalize()
        self.af_btn.bind(DGG.ENTER, self.createMustRestartGui)
        self.af_btn.bind(DGG.EXIT, self.removeMustRestartGui)
        self.exit_btn = DirectButton(geom=(qt_btn.find('**/QuitBtn_UP'), qt_btn.find('**/QuitBtn_DN'), qt_btn.find('**/QuitBtn_RLVR')), relief=None, text='Exit Toontown', scale=1.2, text_scale=0.0535, command=self.book.finished, extraArgs=['exit'], pos=(-0.45, -0.65, -0.6), text_pos=(0, -0.01))
        return

    def createMustRestartGui(self, foo):
        self.mustRestartLbl = DirectLabel(text='Changing this setting requires a game restart.', text_fg=(0.9, 0, 0, 1), text_shadow=(0, 0, 0, 1), text_scale=0.06, text_align=TextNode.ACenter, pos=(0, 0, -0.435), relief=None)
        return

    def removeMustRestartGui(self, foo):
        if hasattr(self, 'mustRestartLbl'):
            self.mustRestartLbl.destroy()
            del self.mustRestartLbl

    def exitBasePage(self):
        self.music_btn.destroy()
        del self.music_btn
        self.sfx_btn.destroy()
        del self.sfx_btn
        self.moddet_btn.destroy()
        del self.moddet_btn
        self.texdet_btn.destroy()
        del self.texdet_btn
        self.display_btn.destroy()
        del self.display_btn
        self.aa_btn.destroy()
        del self.aa_btn
        self.exit_btn.destroy()
        del self.exit_btn
        self.music_lbl.destroy()
        del self.music_lbl
        self.sfx_lbl.destroy()
        del self.sfx_lbl
        self.moddet_lbl.destroy()
        del self.moddet_lbl
        self.texdet_lbl.destroy()
        del self.texdet_lbl
        self.display_lbl.destroy()
        del self.display_lbl
        self.aa_lbl.destroy()
        del self.aa_lbl
        self.af_btn.destroy()
        del self.af_btn
        self.af_lbl.destroy()
        del self.af_lbl
        self.book.deletePageButtons(False, True)
        self.book.clearTitle()
示例#49
0
class NamePage(StateData):
    notify = directNotify.newCategory('NamePage')

    def __init__(self, book, parentFSM):
        self.book = book
        self.parentFSM = parentFSM
        StateData.__init__(self, 'namePageDone')
        self.fsm = ClassicFSM('NamePage', [
            State('off', self.enterOff, self.exitOff),
            State('basePage', self.enterBasePage, self.exitBasePage)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.parentFSM.getStateNamed('namePage').addChild(self.fsm)
        self.nameServ = base.cr.nameServicesManager
        self.baseRequestIndex = 0
        self.requestsPerCluster = 5
        self.requestsContainer = {}
        self.loadingLabel = None
        self.selectedName = None
        self.nameButtons = []
        self.avId2NameData = {}
        geom = CIGlobals.getDefaultBtnGeom()
        self.acceptBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=0.5,
                                      text='Accept',
                                      pos=(0.5, posY, 0),
                                      text_pos=(0, -0.01),
                                      command=self.acceptName)
        self.acceptBtn.hide()
        self.declineBtn = DirectButton(geom=geom,
                                       text_scale=0.04,
                                       relief=None,
                                       scale=0.5,
                                       text='Decline',
                                       pos=(0.75, posY, 0),
                                       text_pos=(0, -0.01),
                                       command=self.declineName)
        self.declineBtn.hide()
        self.avIdLbl = OnscreenText(text='',
                                    scale=0.08,
                                    pos=(0.3, 0, 0.5),
                                    align=TextNode.ACenter)
        self.avIdLbl.hide()
        self.accIdLbl = OnscreenText(text='',
                                     scale=0.08,
                                     pos=(0.3, 0, 0.3),
                                     align=TextNode.ACenter)
        self.accIdLbl.hide()
        return

    def handleRequests(self):
        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        self.nameList = DirectScrolledList(
            relief=None,
            pos=(-0.54, 0, 0.08),
            incButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_scale=(arrowButtonScale, arrowButtonScale,
                             -arrowButtonScale),
            incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999),
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            incButton_command=self.__moveItems,
            incButton_extraArgs=[1],
            decButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_scale=(arrowButtonScale, arrowButtonScale,
                             arrowButtonScale),
            decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125),
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_command=self.__moveItems,
            decButton_extraArgs=[0],
            itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(listXorigin, listXorigin + listFrameSizeX,
                                 listZorigin, listZorigin + listFrameSizeZ),
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=5,
            forceHeight=0.075,
            items=self.nameButtons)
        self.__buildItems()
        return

    def __moveItems(self, direction):
        if direction == 0:
            self.baseRequestIndex += 1
        else:
            if direction == 1:
                self.baseRequestIndex -= 1
        self.clearItems()
        self.__buildItems()

    def clearItems(self):
        for btn in self.nameButtons:
            btn.destroy()

        self.nameButtons = []
        self.nameList.removeAndDestroyAllItems()

    def __buildItems(self):
        for i in xrange(self.requestsPerCluster):
            request = self.nameServ.getNameRequests()[self.baseRequestIndex +
                                                      i]
            date = request['date']
            date = date.replace(' ', '-')
            data = NameData(request['name'], date, request['avId'],
                            request['accId'])
            self.avId2NameData[data.avId] = data
            btn = DirectButton(relief=None,
                               text=data.name,
                               text_scale=0.07,
                               text_align=TextNode.ALeft,
                               text1_bg=textDownColor,
                               text2_bg=textRolloverColor,
                               text3_fg=textDisabledColor,
                               textMayChange=0,
                               command=self.__handleNameButton,
                               extraArgs=[data],
                               text_pos=(0, 0, 0.0))
            data.btn = btn
            self.nameButtons.append(btn)

        self.loadingLabel.hide()
        return

    def __handleNameButton(self, data):
        self.selectedName = data
        data.btn['state'] = DGG.DISABLED
        self.avIdLbl.setText('Avatar ID:\n' + str(data.avId))
        self.avIdLbl.show()
        self.accIdLbl.setText('Account ID:\n' + str(data.accId))
        self.accIdLbl.show()
        self.acceptBtn.show()
        self.declineBtn.show()

    def acceptName(self):
        pass

    def load(self):
        StateData.load(self)
        self.loadingLabel = OnscreenText(text='Loading...',
                                         font=CIGlobals.getToonFont(),
                                         pos=(0, 0.1, 0),
                                         scale=0.08,
                                         parent=aspect2d)

    def unload(self):
        StateData.unload(self)
        self.loadingLabel.destroy()
        self.loadingLabel = None
        for request in self.requestsContainer.values():
            for element in request:
                element.destroy()

        self.requestsContainer = {}
        return

    def enter(self):
        StateData.enter(self)
        self.fsm.request('basePage')
        base.acceptOnce(self.nameServ.getRequestCompleteName(),
                        self.handleRequests)
        self.nameServ.d_requestNameData()

    def exit(self):
        self.fsm.requestFinalState()
        StateData.exit(self)

    def enterBasePage(self):
        self.book.createPageButtons('adminPage', None)
        self.book.setTitle('Name Approval')
        return

    def exitBasePage(self):
        self.book.deletePageButtons(True, False)
        self.book.clearTitle()

    def enterOff(self):
        pass

    def exitOff(self):
        pass
class ToonHood(Hood.Hood):
    def __init__(self, parentFSM, doneEvent, dnaStore, hoodId):
        Hood.Hood.__init__(self, parentFSM, doneEvent, dnaStore, hoodId)
        self.safeZoneLoader = None
        self.townLoader = None
        self.fsm = ClassicFSM('Hood', [
            State('off', self.enterOff, self.exitOff),
            State('safeZoneLoader', self.enterSafeZoneLoader,
                  self.exitSafeZoneLoader, ['quietZone', 'townLoader']),
            State('townLoader', self.enterTownLoader, self.exitTownLoader,
                  ['quietZone', 'safeZoneLoader']),
            State('quietZone', self.enterQuietZone, self.exitQuietZone,
                  ['safeZoneLoader', 'townLoader'])
        ], 'off', 'off')
        self.fsm.enterInitialState()
        return

    def loadLoader(self, requestStatus):
        loader = requestStatus['loader']
        if loader == 'safeZoneLoader':
            if self.safeZoneLoader:
                self.loader = self.safeZoneLoader(
                    self, self.fsm.getStateNamed('safeZoneLoader'),
                    self.loaderDoneEvent)
                self.loader.load()
            else:
                self.notify.error(
                    'ToonHood.ToonHood.safeZoneLoader cannot be None!' %
                    loader)
        else:
            if loader == 'townLoader':
                if self.townLoader:
                    self.loader = self.townLoader(
                        self, self.fsm.getStateNamed('townLoader'),
                        self.loaderDoneEvent)
                    self.loader.load(requestStatus['zoneId'])
            else:
                self.notify.error('Unknown loader %s!' % loader)

    def enterTownLoader(self, requestStatus):
        self.acceptOnce(self.loaderDoneEvent, self.handleTownLoaderDone)
        self.loader.enter(requestStatus)
        self.spawnTitleText(requestStatus['zoneId'])

    def exitTownLoader(self):
        taskMgr.remove('titleText')
        self.hideTitleText()
        self.ignore(self.loaderDoneEvent)
        self.loader.exit()
        self.loader.unload()
        del self.loader

    def handleTownLoaderDone(self):
        doneStatus = self.loader.getDoneStatus()
        if self.isSameHood(doneStatus):
            self.fsm.request('quietZone', [doneStatus])
        else:
            self.doneStatus = doneStatus
            messenger.send(self.doneEvent)

    def load(self):
        Hood.Hood.load(self)
        self.whiteFogColor = Vec4(0.8, 0.8, 0.8, 1)
        self.underwaterFogColor = Vec4(0.0, 0.0, 0.6, 1.0)

    def unload(self):
        del self.safeZoneLoader
        Hood.Hood.unload(self)

    def enter(self, requestStatus):
        self.loadLoader(requestStatus)
        Hood.Hood.enter(self, requestStatus)

    def exit(self):
        Hood.Hood.exit(self)

    def setUnderwaterFog(self):
        if base.wantFog:
            self.fog.setColor(self.underwaterColor)
            self.fog.setLinearRange(0.1, 100.0)
            render.setFog(self.fog)
            self.sky.setFog(self.fog)

    def setWhiteFog(self):
        if base.wantFog:
            self.fog.setColor(self.whiteFogColor)
            self.fog.setLinearRange(0.0, 400.0)
            render.clearFog()
            render.setFog(self.fog)
            self.sky.clearFog()
            self.sky.setFog(self.fog)

    def setNoFog(self):
        if base.wantFog:
            render.clearFog()
            self.sky.clearFog()
class DistributedRaceGame(DistributedMinigame.DistributedMinigame):
    def __init__(self, cr):
        try:
            self.DistributedRaceGame_initialized
            return
        except:
            self.DistributedRaceGame_initialized = 1
        DistributedMinigame.DistributedMinigame.__init__(self, cr)
        self.movement = RaceGameMovement.RaceGameMovement(base.localAvatar)
        self.skyUtil = SkyUtil()
        self.raceFSM = ClassicFSM('DistributedRaceGame', [
            State('race', self.enterRace, self.exitRace),
            State('raceTransition', self.enterRaceTransition,
                  self.exitRaceTransition),
            State('off', self.enterRaceOff, self.exitRaceOff)
        ], 'off', 'off')
        self.raceFSM.enterInitialState()
        self.cr = cr
        self.track = None
        self.sky = None
        self.countSfx = base.loadSfx("phase_5/audio/sfx/firehydrant_popup.ogg")
        self.goSfx = base.loadSfx("phase_4/audio/sfx/AA_sound_whistle.ogg")
        self.game = CIGlobals.RaceGame
        self.trackPath = "phase_4/models/minigames/sprint_track.egg"
        self.skyPath = "phase_3.5/models/props/TT_sky.bam"
        self.lanePos = [(-22.00, -205.00, 0.00), (-11.66, -205.00, 0.00),
                        (0.00, -205.00, 0.00), (-33.66, -205.00, 0.00)]
        self.initialCamPos = {
            "pos": (41.10, -145.00, 25.88),
            "hpr": (135.00, 345.96, 0.0)
        }
        self.raceCamPos = (-24.52, -37.22, 25.00)
        self.lane = 0
        return

    def load(self):
        self.deleteWorld()
        self.track = loader.loadModel(self.trackPath)
        self.track.reparentTo(render)
        self.sky = loader.loadModel(self.skyPath)
        self.sky.reparentTo(self.track)
        self.skyUtil.startSky(self.sky)
        self.setMinigameMusic("phase_4/audio/bgm/MG_toontag.ogg")
        self.setDescription("Tap the left and right arrow keys repeatedly, in turns, as fast as " + \
         "you can to win the race! Every time your power bar hits the top, the boost bar starts" + \
         " to fill. When the boost bar is full, press CTRL to boost for a few seconds.")
        self.setWinnerPrize(100)
        self.setLoserPrize(5)
        self.d_requestToonLane()
        camera.reparentTo(render)
        camera.setPos(self.initialCamPos["pos"])
        camera.setHpr(self.initialCamPos["hpr"])
        DistributedMinigame.DistributedMinigame.load(self)

    def enterPlay(self):
        DistributedMinigame.DistributedMinigame.enterPlay(self)
        self.raceFSM.request('raceTransition')

    def exitPlay(self):
        DistributedMinigame.DistributedMinigame.exitPlay(self)
        self.raceFSM.request('off')

    def enterRace(self):
        self.startMovement()

    def exitRace(self):
        self.stopMovement()

    def enterRaceOff(self):
        pass

    def exitRaceOff(self):
        pass

    def enterRaceTransition(self):
        self.raceTrans = Sequence(Wait(0.5), Func(self.moveCameraToToon),
                                  Wait(4.5), Func(self.moveCameraToTop),
                                  Wait(4.5), Func(self.startCountdown))
        self.raceTrans.start()

    def exitRaceTransition(self):
        self.raceTrans.pause()
        del self.raceTrans

    def startMovement(self):
        self.movement.createGui()
        self.movement.fsm.request('run')

    def enterGameOver(self, winner=0, winnerDoId=0, allPrize=0):
        self.raceFSM.request('off')
        DistributedMinigame.DistributedMinigame.enterGameOver(
            self, winner, winnerDoId, allPrize)

    def stopMovement(self):
        self.movement.cleanup()
        self.movement.deleteGui()

    def startCountdown(self):
        """ Start the countdown to the start of the race. """
        self.countdownLbl = DirectLabel(text="",
                                        text_scale=0.3,
                                        text_font=CIGlobals.getMickeyFont(),
                                        text_fg=(1, 1, 0, 1),
                                        pos=(0, 0, 0.5))
        Sequence(Func(self.setCountdownText, "3"), Wait(1.0),
                 Func(self.setCountdownText, "2"), Wait(1.0),
                 Func(self.setCountdownText, "1"), Wait(1.0),
                 Func(self.setCountdownText, "GO!"), Wait(1.5),
                 Func(self.deleteCountdownLabel)).start()

    def setCountdownText(self, number):
        self.countdownLbl['text'] = number
        if number == "GO!":
            self.countdownLbl['text_fg'] = (0, 1, 0, 1)
            self.goSfx.play()
            self.raceFSM.request('race')
        else:
            self.countSfx.play()

    def deleteCountdownLabel(self):
        self.countdownLbl.destroy()
        del self.countdownLbl

    def moveCameraToToon(self):
        camPInt = LerpPosInterval(camera,
                                  duration=3.0,
                                  pos=self.localAv.getPos(render) + (0, 15, 3),
                                  startPos=(camera.getPos(render)),
                                  blendType="easeInOut")
        camQInt = camera.quatInterval(3.0,
                                      hpr=Vec3(180, 0, 0),
                                      blendType="easeInOut")
        camPInt.start()
        camQInt.start()

    def moveCameraToTop(self):
        camera.setPos(camera.getPos(self.localAv))
        camera.reparentTo(self.localAv)
        oldPos = camera.getPos()
        camera.setPos(self.raceCamPos)
        oldHpr = camera.getHpr()
        camera.lookAt(self.localAv.getPart('head'))
        newHpr = camera.getHpr()
        camera.setHpr(oldHpr)
        camera.setPos(oldPos)
        camPInt = LerpPosInterval(camera,
                                  duration=3.0,
                                  pos=self.raceCamPos,
                                  startPos=oldPos,
                                  blendType="easeInOut")
        camQInt = camera.quatInterval(3.0, hpr=newHpr, blendType="easeInOut")
        camPInt.start()
        camQInt.start()

    def deleteWorld(self):
        if self.track:
            self.track.removeNode()
            self.track = None
        if self.sky:
            self.skyUtil.stopSky()
            self.sky.removeNode()
            self.sky = None

    def setToonLane(self, lane):
        self.lane = lane
        base.localAvatar.setPos(self.lanePos[lane])
        base.localAvatar.setHpr(0, 0, 0)

    def getToonLane(self):
        return self.lane

    def d_requestToonLane(self):
        self.sendUpdate('requestToonLane', [])

    def announceGenerate(self):
        DistributedMinigame.DistributedMinigame.announceGenerate(self)
        self.load()

    def disable(self):
        DistributedMinigame.DistributedMinigame.disable(self)
        self.deleteWorld()
        self.raceFSM.requestFinalState()
        del self.raceFSM
        self.countSfx = None
        self.goSfx = None
示例#52
0
文件: Street.py 项目: coginvasion/src
class Street(Place):
    notify = directNotify.newCategory('Street')

    def __init__(self, loader, parentFSM, doneEvent):
        self.parentFSM = parentFSM
        Place.__init__(self, loader, doneEvent)
        self.fsm = ClassicFSM('Street', [State('start', self.enterStart, self.exitStart, ['walk',
          'doorOut',
          'teleportIn',
          'tunnelOut']),
         State('walk', self.enterWalk, self.exitWalk, ['stop',
          'tunnelIn',
          'shtickerBook',
          'teleportOut']),
         State('shtickerBook', self.enterShtickerBook, self.exitShtickerBook, ['teleportOut', 'walk']),
         State('teleportOut', self.enterTeleportOut, self.exitTeleportOut, ['teleportIn', 'stop']),
         State('tunnelOut', self.enterTunnelOut, self.exitTunnelOut, ['walk']),
         State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['stop']),
         State('stop', self.enterStop, self.exitStop, ['walk',
          'died',
          'teleportOut',
          'doorIn']),
         State('doorIn', self.enterDoorIn, self.exitDoorIn, ['stop']),
         State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk']),
         State('teleportIn', self.enterTeleportIn, self.exitTeleportIn, ['walk', 'stop']),
         State('final', self.enterFinal, self.exitFinal, ['final'])], 'start', 'final')

    def enter(self, requestStatus, visibilityFlag = 1):
        Place.enter(self)
        self.fsm.enterInitialState()
        base.playMusic(self.loader.music, volume=0.8, looping=1)
        self.loader.geom.reparentTo(render)
        if visibilityFlag:
            self.visibilityOn()
        self.loader.hood.startSky()
        self.enterZone(requestStatus['zoneId'])
        self.fsm.request(requestStatus['how'], [requestStatus])

    def exit(self, vis = 1):
        if vis:
            self.visibilityOff()
        self.loader.geom.reparentTo(hidden)
        self.loader.hood.stopSky()
        self.loader.music.stop()
        Place.exit(self)

    def load(self):
        Place.load(self)
        self.parentFSM.getStateNamed('street').addChild(self.fsm)

    def unload(self):
        self.parentFSM.getStateNamed('street').removeChild(self.fsm)
        del self.fsm
        del self.parentFSM
        self.enterZone(None)
        self.ignoreAll()
        Place.unload(self)
        return

    def hideAllVisibles(self):
        for i in self.loader.nodeList:
            i.stash()

    def showAllVisibles(self):
        for i in self.loader.nodeList:
            i.unstash()

    def visibilityOn(self):
        self.hideAllVisibles()
        self.accept('on-floor', self.enterZone)

    def visibilityOff(self):
        self.ignore('on-floor')
        self.showAllVisibles()

    def enterZone(self, newZone):
        if isinstance(newZone, CollisionEntry):
            try:
                newZoneId = int(newZone.getIntoNode().getName())
            except:
                self.notify.warning('Invalid floor collision node in street: %s' % newZone.getIntoNode().getName())
                return

        else:
            newZoneId = newZone
        self.doEnterZone(newZoneId)

    def doEnterZone(self, newZoneId):
        visualizeZones = 0
        if self.zoneId != None:
            for i in self.loader.nodeDict[self.zoneId]:
                if newZoneId:
                    if i not in self.loader.nodeDict[newZoneId]:
                        self.loader.fadeOutDict[i].start()
                else:
                    i.stash()

        if newZoneId != None:
            for i in self.loader.nodeDict[newZoneId]:
                if self.zoneId:
                    if i not in self.loader.nodeDict[self.zoneId]:
                        self.loader.fadeInDict[i].start()
                else:
                    if self.loader.fadeOutDict[i].isPlaying():
                        self.loader.fadeOutDict[i].finish()
                    if self.loader.fadeInDict[i].isPlaying():
                        self.loader.fadeInDict[i].finish()
                    i.unstash()

        if newZoneId != self.zoneId:
            if visualizeZones:
                if self.zoneId != None:
                    self.loader.zoneDict[self.zoneId].clearColor()
                if newZoneId != None:
                    self.loader.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100)
            if newZoneId is not None:
                loader = base.cr.playGame.getPlace().loader
                if newZoneId in loader.zoneVisDict:
                    base.cr.sendSetZoneMsg(newZoneId, loader.zoneVisDict[newZoneId])
                else:
                    visList = [newZoneId] + loader.zoneVisDict.values()[0]
                    base.cr.sendSetZoneMsg(newZoneId, visList)
            self.zoneId = newZoneId
        geom = base.cr.playGame.getPlace().loader.geom
        return
示例#53
0
class ToonHead(Actor.Actor):
    notify = DirectNotifyGlobal.directNotify.newCategory('ToonHead')
    EyesOpen = loader.loadTexture('phase_3/maps/eyes.jpg',
                                  'phase_3/maps/eyes_a.rgb')
    EyesOpen.setMinfilter(Texture.FTLinear)
    EyesOpen.setMagfilter(Texture.FTLinear)
    EyesClosed = loader.loadTexture('phase_3/maps/eyesClosed.jpg',
                                    'phase_3/maps/eyesClosed_a.rgb')
    EyesClosed.setMinfilter(Texture.FTLinear)
    EyesClosed.setMagfilter(Texture.FTLinear)
    EyesSadOpen = loader.loadTexture('phase_3/maps/eyesSad.jpg',
                                     'phase_3/maps/eyesSad_a.rgb')
    EyesSadOpen.setMinfilter(Texture.FTLinear)
    EyesSadOpen.setMagfilter(Texture.FTLinear)
    EyesSadClosed = loader.loadTexture('phase_3/maps/eyesSadClosed.jpg',
                                       'phase_3/maps/eyesSadClosed_a.rgb')
    EyesSadClosed.setMinfilter(Texture.FTLinear)
    EyesSadClosed.setMagfilter(Texture.FTLinear)
    EyesAngryOpen = loader.loadTexture('phase_3/maps/eyesAngry.jpg',
                                       'phase_3/maps/eyesAngry_a.rgb')
    EyesAngryOpen.setMinfilter(Texture.FTLinear)
    EyesAngryOpen.setMagfilter(Texture.FTLinear)
    EyesAngryClosed = loader.loadTexture('phase_3/maps/eyesAngryClosed.jpg',
                                         'phase_3/maps/eyesAngryClosed_a.rgb')
    EyesAngryClosed.setMinfilter(Texture.FTLinear)
    EyesAngryClosed.setMagfilter(Texture.FTLinear)
    EyesSurprised = loader.loadTexture('phase_3/maps/eyesSurprised.jpg',
                                       'phase_3/maps/eyesSurprised_a.rgb')
    EyesSurprised.setMinfilter(Texture.FTLinear)
    EyesSurprised.setMagfilter(Texture.FTLinear)
    Muzzle = loader.loadTexture('phase_3/maps/muzzleShrtGeneric.jpg')
    Muzzle.setMinfilter(Texture.FTLinear)
    Muzzle.setMagfilter(Texture.FTLinear)
    MuzzleSurprised = loader.loadTexture(
        'phase_3/maps/muzzleShortSurprised.jpg')
    MuzzleSurprised.setMinfilter(Texture.FTLinear)
    MuzzleSurprised.setMagfilter(Texture.FTLinear)
    LeftA = Point3(0.06, 0.0, 0.14)
    LeftB = Point3(-0.13, 0.0, 0.1)
    LeftC = Point3(-0.05, 0.0, 0.0)
    LeftD = Point3(0.06, 0.0, 0.0)
    RightA = Point3(0.13, 0.0, 0.1)
    RightB = Point3(-0.06, 0.0, 0.14)
    RightC = Point3(-0.06, 0.0, 0.0)
    RightD = Point3(0.05, 0.0, 0.0)
    LeftAD = Point3(
        LeftA[0] - LeftA[2] * (LeftD[0] - LeftA[0]) / (LeftD[2] - LeftA[2]),
        0.0, 0.0)
    LeftBC = Point3(
        LeftB[0] - LeftB[2] * (LeftC[0] - LeftB[0]) / (LeftC[2] - LeftB[2]),
        0.0, 0.0)
    RightAD = Point3(
        RightA[0] - RightA[2] * (RightD[0] - RightA[0]) /
        (RightD[2] - RightA[2]), 0.0, 0.0)
    RightBC = Point3(
        RightB[0] - RightB[2] * (RightC[0] - RightB[0]) /
        (RightC[2] - RightB[2]), 0.0, 0.0)

    def __init__(self):
        Actor.Actor.__init__(self)
        self.toonName = 'ToonHead-' + str(self.this)
        self.__blinkName = 'blink-' + self.toonName
        self.__stareAtName = 'stareAt-' + self.toonName
        self.__lookName = 'look-' + self.toonName
        self.lookAtTrack = None
        self.__muzzles = []
        self.__surpriseMuzzles = []
        self.__angryMuzzles = []
        self.__sadMuzzles = []
        self.__smileMuzzles = []
        self.__laughMuzzles = []
        self.__eyes = None
        self.__eyelashOpen = None
        self.__eyelashClosed = None
        self.__lod500Eyes = None
        self.__lod250Eyes = None
        self.__lpupil = None
        self.__lod500lPupil = None
        self.__lod250lPupil = None
        self.__rpupil = None
        self.__lod500rPupil = None
        self.__lod250rPupil = None
        self.__muzzle = None
        self.__eyesOpen = ToonHead.EyesOpen
        self.__eyesClosed = ToonHead.EyesClosed
        self.__height = 0.0
        self.__eyelashesHiddenByGlasses = False
        self.randGen = random.Random()
        self.randGen.seed(random.random())
        self.eyelids = ClassicFSM('eyelids', [
            State('off', self.enterEyelidsOff, self.exitEyelidsOff,
                  ['open', 'closed', 'surprised']),
            State('open', self.enterEyelidsOpen, self.exitEyelidsOpen,
                  ['closed', 'surprised', 'off']),
            State('surprised', self.enterEyelidsSurprised,
                  self.exitEyelidsSurprised, ['open', 'closed', 'off']),
            State('closed', self.enterEyelidsClosed, self.exitEyelidsClosed,
                  ['open', 'surprised', 'off'])
        ], 'off', 'off')
        self.eyelids.enterInitialState()
        self.emote = None
        self.__stareAtNode = NodePath()
        self.__defaultStarePoint = Point3(0, 0, 0)
        self.__stareAtPoint = self.__defaultStarePoint
        self.__stareAtTime = 0
        self.lookAtPositionCallbackArgs = None

    def delete(self):
        try:
            self.ToonHead_deleted
        except:
            self.ToonHead_deleted = 1
            taskMgr.remove(self.__blinkName)
            taskMgr.remove(self.__lookName)
            taskMgr.remove(self.__stareAtName)
            if self.lookAtTrack:
                self.lookAtTrack.finish()
                self.lookAtTrack = None
            del self.eyelids
            del self.__stareAtNode
            del self.__stareAtPoint
            if self.__eyes:
                del self.__eyes
            if self.__lpupil:
                del self.__lpupil
            if self.__rpupil:
                del self.__rpupil
            if self.__eyelashOpen:
                del self.__eyelashOpen
            if self.__eyelashClosed:
                del self.__eyelashClosed
            self.lookAtPositionCallbackArgs = None
            Actor.Actor.delete(self)

        return

    def setupHead(self, dna, forGui=0):
        self.__height = self.generateToonHead(dna, forGui=forGui)
        self.generateToonColor(dna)
        animalStyle = dna.getAnimal()
        bodyScale = toonBodyScales[animalStyle]
        headScale = toonHeadScales[animalStyle]
        self.getGeomNode().setScale(headScale[0] * bodyScale * 1.3,
                                    headScale[1] * bodyScale * 1.3,
                                    headScale[2] * bodyScale * 1.3)
        if forGui:
            self.getGeomNode().setDepthWrite(1)
            self.getGeomNode().setDepthTest(1)
        if dna.getAnimal() == 'dog':
            self.loop('neutral')

    def fitAndCenterHead(self, maxDim, forGui=0):
        p1 = Point3()
        p2 = Point3()
        self.calcTightBounds(p1, p2)
        if forGui:
            h = 180
            t = p1[0]
            p1.setX(-p2[0])
            p2.setX(-t)
        else:
            h = 0
        d = p2 - p1
        biggest = max(d[0], d[2])
        s = maxDim / biggest
        mid = (p1 + d / 2.0) * s
        self.setPosHprScale(-mid[0], -mid[1] + 1, -mid[2], h, 0, 0, s, s, s)

    def setLookAtPositionCallbackArgs(self, argTuple):
        self.lookAtPositionCallbackArgs = argTuple

    def getHeight(self):
        return self.__height

    def getRandomForwardLookAtPoint(self):
        x = self.randGen.choice((-0.8, -0.5, 0, 0.5, 0.8))
        z = self.randGen.choice((-0.5, 0, 0.5, 0.8))
        return Point3(x, 1.5, z)

    def findSomethingToLookAt(self):
        if self.lookAtPositionCallbackArgs is not None:
            pnt = self.lookAtPositionCallbackArgs[0].getLookAtPosition(
                self.lookAtPositionCallbackArgs[1],
                self.lookAtPositionCallbackArgs[2])
            self.startStareAt(self, pnt)
            return
        if self.randGen.random() < 0.33:
            lookAtPnt = self.getRandomForwardLookAtPoint()
        else:
            lookAtPnt = self.__defaultStarePoint
        self.lerpLookAt(lookAtPnt, blink=1)
        return

    def generateToonHead(self, style, lods=['1000'], forGui=0):
        headStyle = style.head
        fix = None
        if headStyle == 'dls':
            filePrefix = HeadDict['dls']
            headHeight = 0.75
        elif headStyle == 'dss':
            filePrefix = HeadDict['dss']
            headHeight = 0.5
        elif headStyle == 'dsl':
            filePrefix = HeadDict['dsl']
            headHeight = 0.5
        elif headStyle == 'dll':
            filePrefix = HeadDict['dll']
            headHeight = 0.75
        elif headStyle == 'cls':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'css':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'csl':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'cll':
            filePrefix = HeadDict['c']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'hls':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'hss':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'hsl':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'hll':
            filePrefix = HeadDict['h']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'mls':
            filePrefix = HeadDict['m']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'mss':
            filePrefix = HeadDict['m']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'rls':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'rss':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'rsl':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'rll':
            filePrefix = HeadDict['r']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'fls':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'fss':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'fsl':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'fll':
            filePrefix = HeadDict['f']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'pls':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'pss':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'psl':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'pll':
            filePrefix = HeadDict['p']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'bls':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'bss':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'bsl':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'bll':
            filePrefix = HeadDict['b']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        elif headStyle == 'sls':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadLongShort
            headHeight = 0.75
        elif headStyle == 'sss':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadShortShort
            headHeight = 0.5
        elif headStyle == 'ssl':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadShortLong
            headHeight = 0.5
        elif headStyle == 'sll':
            filePrefix = HeadDict['s']
            fix = self.__fixHeadLongLong
            headHeight = 0.75
        else:
            ToonHead.notify.error('unknown head style: %s' % headStyle)
        if len(lods) == 1:
            self.loadModel('phase_3' + filePrefix + lods[0], 'head', 'lodRoot',
                           1)
            if fix is not None:
                fix(style, None, 1)
            if not forGui:
                self.__lods = lods
                self.__style = style
                self.__headStyle = headStyle
                self.__copy = 1
        else:
            for lod in lods:
                self.loadModel('phase_3' + filePrefix + lod, 'head', lod, 1)
                if fix is not None:
                    fix(style, lod, 1)
                if not forGui:
                    self.__lods = lods
                    self.__style = style
                    self.__headStyle = headStyle
                    self.__copy = 1

        self.__fixEyes(style, forGui)
        self.setupEyelashes(style)
        self.eyelids.request('closed')
        self.eyelids.request('open')
        self.setupMuzzles(style)
        return headHeight

    def hideEars(self):
        self.findAllMatches('**/ears*;+s').stash()

    def showEars(self):
        self.findAllMatches('**/ears*;+s').unstash()

    def hideEyelashes(self):
        if self.__eyelashOpen:
            self.__eyelashOpen.stash()
        if self.__eyelashClosed:
            self.__eyelashClosed.stash()
        self.__eyelashesHiddenByGlasses = True

    def showEyelashes(self):
        if self.__eyelashOpen:
            self.__eyelashOpen.unstash()
        if self.__eyelashClosed:
            self.__eyelashClosed.unstash()
        self.__eyelashesHiddenByGlasses = False

    def generateToonColor(self, style):
        parts = self.findAllMatches('**/head*')
        parts.setColor(style.getHeadColor())
        animalType = style.getAnimal()
        if animalType == 'cat' or animalType == 'rabbit' or animalType == 'bear' or animalType == 'mouse' or animalType == 'pig':
            parts = self.findAllMatches('**/ear?-*')
            parts.setColor(style.getHeadColor())

    def __fixEyes(self, style, forGui=0):
        mode = -3
        if forGui:
            mode = -2
        if self.hasLOD():
            for lodName in self.getLODNames():
                self.drawInFront('eyes*', 'head-front*', mode, lodName=lodName)
                if not self.find('**/joint_pupil*').isEmpty():
                    self.drawInFront('joint_pupil*',
                                     'eyes*',
                                     -1,
                                     lodName=lodName)
                else:
                    self.drawInFront('def_*_pupil',
                                     'eyes*',
                                     -1,
                                     lodName=lodName)

            self.__eyes = self.getLOD(1000).find('**/eyes*')
            self.__lod500Eyes = self.getLOD(500).find('**/eyes*')
            self.__lod250Eyes = self.getLOD(250).find('**/eyes*')
            if self.__lod500Eyes.isEmpty():
                self.__lod500Eyes = None
            else:
                self.__lod500Eyes.setColorOff()
                if not self.find('**/joint_pupilL*').isEmpty():
                    self.__lod500lPupil = self.__lod500Eyes.find(
                        '**/joint_pupilL*')
                    self.__lod500rPupil = self.__lod500Eyes.find(
                        '**/joint_pupilR*')
                else:
                    self.__lod500lPupil = self.__lod500Eyes.find(
                        '**/def_left_pupil*')
                    self.__lod500rPupil = self.__lod500Eyes.find(
                        '**/def_right_pupil*')

            if self.__lod250Eyes.isEmpty():
                self.__lod250Eyes = None
            else:
                self.__lod250Eyes.setColorOff()
                if not self.find('**/joint_pupilL*').isEmpty():
                    self.__lod250lPupil = self.__lod250Eyes.find(
                        '**/joint_pupilL*')
                    self.__lod250rPupil = self.__lod250Eyes.find(
                        '**/joint_pupilR*')
                else:
                    self.__lod250lPupil = self.__lod250Eyes.find(
                        '**/def_left_pupil*')
                    self.__lod250rPupil = self.__lod250Eyes.find(
                        '**/def_right_pupil*')

        else:
            self.drawInFront('eyes*', 'head-front*', mode)
            if not self.find('joint_pupil*').isEmpty():
                self.drawInFront('joint_pupil*', 'eyes*', -1)
            else:
                self.drawInFront('def_*_pupil', 'eyes*', -1)

            self.__eyes = self.find('**/eyes*')
        if not self.__eyes.isEmpty():
            self.__eyes.setColorOff()
            self.__lpupil = None
            self.__rpupil = None
            if not self.find('**/joint_pupilL*').isEmpty():
                if self.getLOD(1000):
                    lp = self.getLOD(1000).find('**/joint_pupilL*')
                    rp = self.getLOD(1000).find('**/joint_pupilR*')
                else:
                    lp = self.find('**/joint_pupilL*')
                    rp = self.find('**/joint_pupilR*')
            elif not self.getLOD(1000):
                lp = self.find('**/def_left_pupil*')
                rp = self.find('**/def_right_pupil*')
            else:
                lp = self.getLOD(1000).find('**/def_left_pupil*')
                rp = self.getLOD(1000).find('**/def_right_pupil*')

            if lp.isEmpty() or rp.isEmpty():
                print('Unable to locate pupils.')
            else:
                leye = self.__eyes.attachNewNode('leye')
                reye = self.__eyes.attachNewNode('reye')
                lmat = Mat4(0.802174, 0.59709, 0, 0, -0.586191, 0.787531,
                            0.190197, 0, 0.113565, -0.152571, 0.981746, 0,
                            -0.233634, 0.418062, 0.0196875, 1)
                leye.setMat(lmat)
                rmat = Mat4(0.786788, -0.617224, 0, 0, 0.602836, 0.768447,
                            0.214658, 0, -0.132492, -0.16889, 0.976689, 0,
                            0.233634, 0.418062, 0.0196875, 1)
                reye.setMat(rmat)
                self.__lpupil = leye.attachNewNode('lpupil')
                self.__rpupil = reye.attachNewNode('rpupil')
                lpt = self.__eyes.attachNewNode('')
                rpt = self.__eyes.attachNewNode('')
                lpt.wrtReparentTo(self.__lpupil)
                rpt.wrtReparentTo(self.__rpupil)
                lp.reparentTo(lpt)
                rp.reparentTo(rpt)
                self.__lpupil.adjustAllPriorities(1)
                self.__rpupil.adjustAllPriorities(1)
                if self.__lod500Eyes:
                    self.__lod500lPupil.adjustAllPriorities(1)
                    self.__lod500rPupil.adjustAllPriorities(1)
                if self.__lod250Eyes:
                    self.__lod250lPupil.adjustAllPriorities(1)
                    self.__lod250rPupil.adjustAllPriorities(1)
                animalType = style.getAnimal()
                if animalType != 'dog':
                    self.__lpupil.flattenStrong()
                    self.__rpupil.flattenStrong()

    def __setPupilDirection(self, x, y):
        if y < 0.0:
            y2 = -y
            left1 = self.LeftAD + (self.LeftD - self.LeftAD) * y2
            left2 = self.LeftBC + (self.LeftC - self.LeftBC) * y2
            right1 = self.RightAD + (self.RightD - self.RightAD) * y2
            right2 = self.RightBC + (self.RightC - self.RightBC) * y2
        else:
            y2 = y
            left1 = self.LeftAD + (self.LeftA - self.LeftAD) * y2
            left2 = self.LeftBC + (self.LeftB - self.LeftBC) * y2
            right1 = self.RightAD + (self.RightA - self.RightAD) * y2
            right2 = self.RightBC + (self.RightB - self.RightBC) * y2
        left0 = Point3(
            0.0, 0.0, left1[2] - left1[0] * (left2[2] - left1[2]) /
            (left2[0] - left1[0]))
        right0 = Point3(
            0.0, 0.0, right1[2] - right1[0] * (right2[2] - right1[2]) /
            (right2[0] - right1[0]))
        if x < 0.0:
            x2 = -x
            left = left0 + (left2 - left0) * x2
            right = right0 + (right2 - right0) * x2
        else:
            x2 = x
            left = left0 + (left1 - left0) * x2
            right = right0 + (right1 - right0) * x2
        self.__lpupil.setPos(left)
        self.__rpupil.setPos(right)

    def __lookPupilsAt(self, node, point):
        if node is not None:
            mat = node.getMat(self.__eyes)
            point = mat.xformPoint(point)
        distance = 1.0
        recip_z = 1.0 / max(0.1, point[1])
        x = distance * point[0] * recip_z
        y = distance * point[2] * recip_z
        x = min(max(x, -1), 1)
        y = min(max(y, -1), 1)
        self.__setPupilDirection(x, y)

    def __lookHeadAt(self, node, point, frac=1.0, lod=None):
        reachedTarget = 1
        if lod is None:
            head = self.getPart('head', self.getLODNames()[0])
        else:
            head = self.getPart('head', lod)
        if node is not None:
            headParent = head.getParent()
            mat = node.getMat(headParent)
            point = mat.xformPoint(point)
        rot = Mat3(0, 0, 0, 0, 0, 0, 0, 0, 0)
        lookAt(rot, Vec3(point), Vec3(0, 0, 1), CSDefault)
        scale = VBase3(0, 0, 0)
        hpr = VBase3(0, 0, 0)
        if decomposeMatrix(rot, scale, hpr, CSDefault):
            hpr = VBase3(min(max(hpr[0], -60), 60), min(max(hpr[1], -20), 30),
                         0)
            if frac != 1:
                currentHpr = head.getHpr()
                reachedTarget = abs(hpr[0] - currentHpr[0]) < 1.0 and abs(
                    hpr[1] - currentHpr[1]) < 1.0
                hpr = currentHpr + (hpr - currentHpr) * frac
            if lod is None:
                for lodName in self.getLODNames():
                    head = self.getPart('head', lodName)
                    head.setHpr(hpr)

            else:
                head.setHpr(hpr)
        return reachedTarget

    def setupEyelashes(self, style):
        if style.getGender() == 'm':
            if self.__eyelashOpen:
                self.__eyelashOpen.removeNode()
                self.__eyelashOpen = None
            if self.__eyelashClosed:
                self.__eyelashClosed.removeNode()
                self.__eyelashClosed = None
        else:
            if self.__eyelashOpen:
                self.__eyelashOpen.removeNode()
            if self.__eyelashClosed:
                self.__eyelashClosed.removeNode()
            animal = style.head[0]
            model = loader.loadModel('phase_3' + EyelashDict[animal])
            if self.hasLOD():
                head = self.getPart('head', '1000')
            else:
                head = self.getPart('head', 'lodRoot')
            length = style.head[1]
            if length == 'l':
                openString = 'open-long'
                closedString = 'closed-long'
            else:
                openString = 'open-short'
                closedString = 'closed-short'
            self.__eyelashOpen = model.find('**/' + openString).copyTo(head)
            self.__eyelashClosed = model.find('**/' +
                                              closedString).copyTo(head)
            model.removeNode()

    def __fixHeadLongLong(self, style, lodName=None, copy=1):
        if lodName is None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        otherParts = searchRoot.findAllMatches('**/*short*')
        for partNum in range(0, otherParts.getNumPaths()):
            if copy:
                otherParts.getPath(partNum).removeNode()
            else:
                otherParts.getPath(partNum).stash()

    def __fixHeadLongShort(self, style, lodName=None, copy=1):
        animalType = style.getAnimal()
        if lodName is None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        if animalType != 'duck' and animalType != 'horse':
            if animalType == 'rabbit':
                if copy:
                    searchRoot.find('**/ears-long').removeNode()
                else:
                    searchRoot.find('**/ears-long').hide()
            elif copy:
                searchRoot.find('**/ears-short').removeNode()
            else:
                searchRoot.find('**/ears-short').hide()
        if animalType != 'rabbit':
            if copy:
                searchRoot.find('**/eyes-short').removeNode()
            else:
                searchRoot.find('**/eyes-short').hide()
        if animalType != 'dog':
            if copy:
                searchRoot.find('**/joint_pupilL_short').removeNode()
                searchRoot.find('**/joint_pupilR_short').removeNode()
            else:
                searchRoot.find('**/joint_pupilL_short').stash()
                searchRoot.find('**/joint_pupilR_short').stash()
        if copy:
            self.find('**/head-short').removeNode()
            self.find('**/head-front-short').removeNode()
        else:
            self.find('**/head-short').hide()
            self.find('**/head-front-short').hide()
        if animalType != 'rabbit':
            muzzleParts = searchRoot.findAllMatches('**/muzzle-long*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

        else:
            muzzleParts = searchRoot.findAllMatches('**/muzzle-short*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

    def __fixHeadShortLong(self, style, lodName=None, copy=1):
        animalType = style.getAnimal()
        if lodName is None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        if animalType != 'duck' and animalType != 'horse':
            if animalType == 'rabbit':
                if copy:
                    searchRoot.find('**/ears-short').removeNode()
                else:
                    searchRoot.find('**/ears-short').hide()
            elif copy:
                searchRoot.find('**/ears-long').removeNode()
            else:
                searchRoot.find('**/ears-long').hide()
        if animalType != 'rabbit':
            if copy:
                searchRoot.find('**/eyes-long').removeNode()
            else:
                searchRoot.find('**/eyes-long').hide()
        if animalType != 'dog':
            if copy:
                searchRoot.find('**/joint_pupilL_long').removeNode()
                searchRoot.find('**/joint_pupilR_long').removeNode()
            else:
                searchRoot.find('**/joint_pupilL_long').stash()
                searchRoot.find('**/joint_pupilR_long').stash()
        if copy:
            searchRoot.find('**/head-long').removeNode()
            searchRoot.find('**/head-front-long').removeNode()
        else:
            searchRoot.find('**/head-long').hide()
            searchRoot.find('**/head-front-long').hide()
        if animalType != 'rabbit':
            muzzleParts = searchRoot.findAllMatches('**/muzzle-short*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

        else:
            muzzleParts = searchRoot.findAllMatches('**/muzzle-long*')
            for partNum in range(0, muzzleParts.getNumPaths()):
                if copy:
                    muzzleParts.getPath(partNum).removeNode()
                else:
                    muzzleParts.getPath(partNum).hide()

    def __fixHeadShortShort(self, style, lodName=None, copy=1):
        if lodName is None:
            searchRoot = self
        else:
            searchRoot = self.find('**/' + str(lodName))
        otherParts = searchRoot.findAllMatches('**/*long*')
        for partNum in range(0, otherParts.getNumPaths()):
            if copy:
                otherParts.getPath(partNum).removeNode()
            else:
                otherParts.getPath(partNum).stash()

    def __blinkOpenEyes(self, task):
        if self.eyelids.getCurrentState().getName() == 'closed':
            self.eyelids.request('open')
        r = self.randGen.random()
        if r < 0.1:
            t = 0.2
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self.__blinkCloseEyes, self.__blinkName)
        return task.done

    def __blinkCloseEyes(self, task):
        if self.eyelids.getCurrentState().getName() != 'open':
            taskMgr.doMethodLater(4.0, self.__blinkCloseEyes, self.__blinkName)
        else:
            self.eyelids.request('closed')
            taskMgr.doMethodLater(0.125, self.__blinkOpenEyes,
                                  self.__blinkName)
        return task.done

    def startBlink(self):
        taskMgr.remove(self.__blinkName)
        if self.__eyes:
            self.openEyes()
        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1,
                              self.__blinkCloseEyes, self.__blinkName)

    def stopBlink(self):
        taskMgr.remove(self.__blinkName)
        if self.__eyes:
            self.eyelids.request('open')

    def closeEyes(self):
        self.eyelids.request('closed')

    def openEyes(self):
        self.eyelids.request('open')

    def surpriseEyes(self):
        self.eyelids.request('surprised')

    def sadEyes(self):
        self.__eyesOpen = ToonHead.EyesSadOpen
        self.__eyesClosed = ToonHead.EyesSadClosed

    def angryEyes(self):
        self.__eyesOpen = ToonHead.EyesAngryOpen
        self.__eyesClosed = ToonHead.EyesAngryClosed

    def normalEyes(self):
        self.__eyesOpen = ToonHead.EyesOpen
        self.__eyesClosed = ToonHead.EyesClosed

    def blinkEyes(self):
        taskMgr.remove(self.__blinkName)
        self.eyelids.request('closed')
        taskMgr.doMethodLater(0.1, self.__blinkOpenEyes, self.__blinkName)

    def __stareAt(self, task):
        frac = 2 * globalClock.getDt()
        reachedTarget = self.__lookHeadAt(self.__stareAtNode,
                                          self.__stareAtPoint, frac)
        self.__lookPupilsAt(self.__stareAtNode, self.__stareAtPoint)
        if reachedTarget and self.__stareAtNode is None:
            return task.done
        return task.cont

    def doLookAroundToStareAt(self, node, point):
        self.startStareAt(node, point)
        self.startLookAround()

    def startStareAtHeadPoint(self, point):
        self.startStareAt(self, point)

    def startStareAt(self, node, point):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        self.__stareAtNode = node
        if point is not None:
            self.__stareAtPoint = point
        else:
            self.__stareAtPoint = self.__defaultStarePoint
        self.__stareAtTime = globalClock.getFrameTime()
        taskMgr.add(self.__stareAt, self.__stareAtName)

    def lerpLookAt(self, point, time=1.0, blink=0):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        lodNames = self.getLODNames()
        if lodNames:
            lodName = lodNames[0]
        else:
            return 0
        head = self.getPart('head', lodName)
        startHpr = head.getHpr()
        startLpupil = self.__lpupil.getPos()
        startRpupil = self.__rpupil.getPos()
        self.__lookHeadAt(None, point, lod=lodName)
        self.__lookPupilsAt(None, point)
        endHpr = head.getHpr()
        endLpupil = self.__lpupil.getPos() * 0.5
        endRpupil = self.__rpupil.getPos() * 0.5
        head.setHpr(startHpr)
        self.__lpupil.setPos(startLpupil)
        self.__rpupil.setPos(startRpupil)
        if startHpr.almostEqual(endHpr, 10):
            return 0
        if blink:
            self.blinkEyes()
        lookToTgt_TimeFraction = 0.2
        lookToTgtTime = time * lookToTgt_TimeFraction
        returnToEyeCenterTime = time - lookToTgtTime - 0.5
        origin = Point3(0, 0, 0)
        blendType = 'easeOut'
        self.lookAtTrack = Parallel(Sequence(
            LerpPosInterval(self.__lpupil,
                            lookToTgtTime,
                            endLpupil,
                            blendType=blendType), Wait(0.5),
            LerpPosInterval(self.__lpupil,
                            returnToEyeCenterTime,
                            origin,
                            blendType=blendType)),
                                    Sequence(
                                        LerpPosInterval(self.__rpupil,
                                                        lookToTgtTime,
                                                        endRpupil,
                                                        blendType=blendType),
                                        Wait(0.5),
                                        LerpPosInterval(self.__rpupil,
                                                        returnToEyeCenterTime,
                                                        origin,
                                                        blendType=blendType)),
                                    name=self.__stareAtName)
        for lodName in self.getLODNames():
            head = self.getPart('head', lodName)
            self.lookAtTrack.append(
                LerpHprInterval(head, time, endHpr, blendType='easeInOut'))

        self.lookAtTrack.start()
        return 1

    def stopStareAt(self):
        self.lerpLookAt(Vec3.forward())

    def stopStareAtNow(self):
        taskMgr.remove(self.__stareAtName)
        if self.lookAtTrack:
            self.lookAtTrack.finish()
            self.lookAtTrack = None
        if self.__lpupil and self.__rpupil:
            self.__setPupilDirection(0, 0)
        for lodName in self.getLODNames():
            head = self.getPart('head', lodName)
            head.setHpr(0, 0, 0)

    def __lookAround(self, task):
        self.findSomethingToLookAt()
        t = self.randGen.random() * 4.0 + 3.0
        taskMgr.doMethodLater(t, self.__lookAround, self.__lookName)
        return task.done

    def startLookAround(self):
        taskMgr.remove(self.__lookName)
        t = self.randGen.random() * 5.0 + 2.0
        taskMgr.doMethodLater(t, self.__lookAround, self.__lookName)

    def stopLookAround(self):
        taskMgr.remove(self.__lookName)
        self.stopStareAt()

    def stopLookAroundNow(self):
        taskMgr.remove(self.__lookName)
        self.stopStareAtNow()

    def enterEyelidsOff(self):
        pass

    def exitEyelidsOff(self):
        pass

    def enterEyelidsOpen(self):
        if not self.__eyes.isEmpty():
            self.__eyes.setTexture(self.__eyesOpen, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.show()
            if self.__eyelashClosed:
                self.__eyelashClosed.hide()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(self.__eyesOpen, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(self.__eyesOpen, 1)
            if self.__lpupil:
                self.__lpupil.show()
                self.__rpupil.show()
            if self.__lod500lPupil:
                self.__lod500lPupil.show()
                self.__lod500rPupil.show()
            if self.__lod250lPupil:
                self.__lod250lPupil.show()
                self.__lod250rPupil.show()

    def exitEyelidsOpen(self):
        pass

    def enterEyelidsClosed(self):
        if not self.__eyes.isEmpty() and self.__eyesClosed:
            self.__eyes.setTexture(self.__eyesClosed, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.hide()
            if self.__eyelashClosed:
                self.__eyelashClosed.show()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(self.__eyesClosed, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(self.__eyesClosed, 1)
            if self.__lpupil:
                self.__lpupil.hide()
                self.__rpupil.hide()
            if self.__lod500lPupil:
                self.__lod500lPupil.hide()
                self.__lod500rPupil.hide()
            if self.__lod250lPupil:
                self.__lod250lPupil.hide()
                self.__lod250rPupil.hide()

    def exitEyelidsClosed(self):
        pass

    def enterEyelidsSurprised(self):
        if not self.__eyes.isEmpty() and ToonHead.EyesSurprised:
            self.__eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__eyelashOpen:
                self.__eyelashOpen.hide()
            if self.__eyelashClosed:
                self.__eyelashClosed.hide()
            if self.__lod500Eyes:
                self.__lod500Eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__lod250Eyes:
                self.__lod250Eyes.setTexture(ToonHead.EyesSurprised, 1)
            if self.__muzzle:
                self.__muzzle.setTexture(ToonHead.MuzzleSurprised, 1)
            if self.__lpupil:
                self.__lpupil.show()
                self.__rpupil.show()
            if self.__lod500lPupil:
                self.__lod500lPupil.show()
                self.__lod500rPupil.show()
            if self.__lod250lPupil:
                self.__lod250lPupil.show()
                self.__lod250rPupil.show()

    def exitEyelidsSurprised(self):
        if self.__muzzle:
            self.__muzzle.setTexture(ToonHead.Muzzle, 1)

    def setupMuzzles(self, style):
        self.__muzzles = []
        self.__surpriseMuzzles = []
        self.__angryMuzzles = []
        self.__sadMuzzles = []
        self.__smileMuzzles = []
        self.__laughMuzzles = []

        def hideAddNonEmptyItemToList(item, list):
            if not item.isEmpty():
                item.hide()
                list.append(item)

        if self.hasLOD():
            for lodName in self.getLODNames():
                animal = style.getAnimal()
                if animal != 'dog':
                    muzzle = self.find('**/' + lodName + '/**/muzzle*neutral')
                else:
                    muzzle = self.find('**/' + lodName + '/**/muzzle*')
                    if lodName == '1000' or lodName == '500':
                        filePrefix = DogMuzzleDict[style.head]
                        muzzles = loader.loadModel('phase_3' + filePrefix +
                                                   lodName)
                        if not self.find(
                                '**/' + lodName +
                                '/**/__Actor_head/def_head').isEmpty():
                            muzzles.reparentTo(
                                self.find('**/' + lodName +
                                          '/**/__Actor_head/def_head'))
                        else:
                            muzzles.reparentTo(
                                self.find('**/' + lodName +
                                          '/**/joint_toHead'))

                surpriseMuzzle = self.find('**/' + lodName +
                                           '/**/muzzle*surprise')
                angryMuzzle = self.find('**/' + lodName + '/**/muzzle*angry')
                sadMuzzle = self.find('**/' + lodName + '/**/muzzle*sad')
                smileMuzzle = self.find('**/' + lodName + '/**/muzzle*smile')
                laughMuzzle = self.find('**/' + lodName + '/**/muzzle*laugh')
                self.__muzzles.append(muzzle)
                hideAddNonEmptyItemToList(surpriseMuzzle,
                                          self.__surpriseMuzzles)
                hideAddNonEmptyItemToList(angryMuzzle, self.__angryMuzzles)
                hideAddNonEmptyItemToList(sadMuzzle, self.__sadMuzzles)
                hideAddNonEmptyItemToList(smileMuzzle, self.__smileMuzzles)
                hideAddNonEmptyItemToList(laughMuzzle, self.__laughMuzzles)

        else:
            if style.getAnimal() != 'dog':
                muzzle = self.find('**/muzzle*neutral')
            else:
                muzzle = self.find('**/muzzle*')
                filePrefix = DogMuzzleDict[style.head]
                muzzles = loader.loadModel('phase_3' + filePrefix + '1000')
                if not self.find('**/def_head').isEmpty():
                    muzzles.reparentTo(self.find('**/def_head'))
                else:
                    muzzles.reparentTo(self.find('**/joint_toHead'))

            surpriseMuzzle = self.find('**/muzzle*surprise')
            angryMuzzle = self.find('**/muzzle*angry')
            sadMuzzle = self.find('**/muzzle*sad')
            smileMuzzle = self.find('**/muzzle*smile')
            laughMuzzle = self.find('**/muzzle*laugh')
            self.__muzzles.append(muzzle)
            hideAddNonEmptyItemToList(surpriseMuzzle, self.__surpriseMuzzles)
            hideAddNonEmptyItemToList(angryMuzzle, self.__angryMuzzles)
            hideAddNonEmptyItemToList(sadMuzzle, self.__sadMuzzles)
            hideAddNonEmptyItemToList(smileMuzzle, self.__smileMuzzles)
            hideAddNonEmptyItemToList(laughMuzzle, self.__laughMuzzles)

    def getMuzzles(self):
        return self.__muzzles

    def getSurpriseMuzzles(self):
        return self.__surpriseMuzzles

    def getAngryMuzzles(self):
        return self.__angryMuzzles

    def getSadMuzzles(self):
        return self.__sadMuzzles

    def getSmileMuzzles(self):
        return self.__smileMuzzles

    def getLaughMuzzles(self):
        return self.__laughMuzzles

    def showNormalMuzzle(self):
        for muzzleNum in range(len(self.__muzzles)):
            self.__muzzles[muzzleNum].show()

    def hideNormalMuzzle(self):
        for muzzleNum in range(len(self.__muzzles)):
            self.__muzzles[muzzleNum].hide()

    def showAngryMuzzle(self):
        for muzzleNum in range(len(self.__angryMuzzles)):
            self.__angryMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideAngryMuzzle(self):
        for muzzleNum in range(len(self.__angryMuzzles)):
            self.__angryMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSadMuzzle(self):
        for muzzleNum in range(len(self.__sadMuzzles)):
            self.__sadMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSadMuzzle(self):
        for muzzleNum in range(len(self.__sadMuzzles)):
            self.__sadMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSmileMuzzle(self):
        for muzzleNum in range(len(self.__smileMuzzles)):
            self.__smileMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSmileMuzzle(self):
        for muzzleNum in range(len(self.__smileMuzzles)):
            self.__smileMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showLaughMuzzle(self):
        for muzzleNum in range(len(self.__laughMuzzles)):
            self.__laughMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideLaughMuzzle(self):
        for muzzleNum in range(len(self.__laughMuzzles)):
            self.__laughMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()

    def showSurpriseMuzzle(self):
        for muzzleNum in range(len(self.__surpriseMuzzles)):
            self.__surpriseMuzzles[muzzleNum].show()
            self.__muzzles[muzzleNum].hide()

    def hideSurpriseMuzzle(self):
        for muzzleNum in range(len(self.__surpriseMuzzles)):
            self.__surpriseMuzzles[muzzleNum].hide()
            self.__muzzles[muzzleNum].show()
class Human(HumanBase.HumanBase, Biped.Biped):
    notify = DirectNotifyGlobal.directNotify.newCategory("Human")
    prebuiltAnimData = {}

    def __init__(self, other=None):
        Biped.Biped.__init__(self, other, HumanAnimationMixer)
        self.zombie = False
        self.crazyColorSkin = False
        self.crazyColorSkinIndex = 0
        self.flattenPending = None
        self.flattenSuperLowName = None
        self.optimizeLOD = base.config.GetBool("optimize-avatar-lod", 1)
        self.loaded = 0
        self.playingRate = None
        self.shadowFileName = "models/misc/drop_shadow"
        self.setFont(PiratesGlobals.getInterfaceFont())
        self._Human__blinkName = "blink-" + str(self.this)
        self.eyeLids = None
        self.eyeBalls = None
        self.eyeIris = None
        self.reducedAnimList = None
        self.headNode = None
        self.headEffects = NodePath("headEffects")
        self.extraNode = None
        self.scaleNode = None
        self.rootNode = None
        self.floorOffsetZ = 0.0
        self.isGhost = 0
        self.headFudgeHpr = Vec3(0, 0, 0)
        self.randGen = random.Random()
        self.randGen.seed(random.random())
        self.eyeFSM = ClassicFSM(
            "eyeFSM",
            [
                State("off", self.enterEyeFSMOff, self.exitEyeFSMOff, ["open", "closed"]),
                State("open", self.enterEyeFSMOpen, self.exitEyeFSMOpen, ["closed", "off"]),
                State("closed", self.enterEyeFSMClosed, self.exitEyeFSMClosed, ["open", "off"]),
            ],
            "off",
            "off",
        )
        self.eyeFSM.enterInitialState()
        if other != None:
            self.copyHuman(other)

    def removeCopiedNodes(self):
        self.dropShadow = self.find("**/drop_shadow*")
        if not self.dropShadow.isEmpty():
            self.deleteDropShadow()
        else:
            self.dropShadow = None
        billboardNode = self.find("**/billboardNode")
        if not billboardNode.isEmpty():
            billboardNode.removeNode()

        self.getGeomNode().getParent().removeNode()

    def flattenHuman(self):
        self.getWeaponJoints()

    def flattenSuperLow(self):
        name = "flattenSuperLow-%s" % self.this
        self.flattenSuperLowName = name
        model = self.getLOD("500")
        self.accept(name, self._Human__doneFlattenSuperLow)
        taskMgr.remove(name)
        taskMgr.add(self.flattenSuperLowTask, name, extraArgs=[model], taskChain="background")

    def flattenSuperLowTask(self, model):
        model = model.copyTo(NodePath())
        rhn = model.find("**/rightHand")
        lhn = model.find("**/leftHand")
        if lhn:
            lhn.detachNode()

        if rhn:
            rhn.detachNode()

        node = model.node()
        gr = SceneGraphReducer()
        model.node().setAttrib(TransparencyAttrib.make(0), 2000)
        gr.applyAttribs(
            node,
            SceneGraphReducer.TTApplyTextureColor
            | SceneGraphReducer.TTTexMatrix
            | SceneGraphReducer.TTOther
            | SceneGraphReducer.TTCullFace
            | SceneGraphReducer.TTTransform
            | SceneGraphReducer.TTColor
            | SceneGraphReducer.TTColorScale,
        )
        num_removed = gr.flatten(node, -1)
        gr.makeCompatibleState(node)
        gr.collectVertexData(
            node, ~(SceneGraphReducer.CVDFormat | SceneGraphReducer.CVDName | SceneGraphReducer.CVDAnimationType)
        )
        gr.unify(node, 0)
        name = self.flattenSuperLowName
        if name:
            messenger.send(name, [model], taskChain="default")

    def _Human__doneFlattenSuperLow(self, flat):
        self.headNode = flat.find("**/def_head01")
        self.rootNode = flat.find("**/dx_root")
        self.getWeaponJoints()
        orig = self.getLOD("500")
        orig.getChildren().detach()
        self.loadModel(flat, lodName="500", copy=False, autoBindAnims=False)
        self.getWeaponJoints()
        if hasattr(self, "animProp") and self.animProp:
            self.resetAnimProp()

        self.findAllMatches("**/def_head01").detach()
        self.findAllMatches("**/dx_root").detach()
        for lodName in self.getLODNames():
            if lodName == "500":
                self.headNode.reparentTo(self.getLOD(lodName).find("**/+Character"))
                self.rootNode.reparentTo(self.getLOD(lodName).find("**/+Character"))
                continue
            self.headNode.instanceTo(self.getLOD(lodName).find("**/+Character"))
            self.rootNode.instanceTo(self.getLOD(lodName).find("**/+Character"))

        self.headEffects.reparentTo(self.headNode)

    def _Human__doneFlattenHuman(self, models):
        self.flattenPending = None
        self.getWeaponJoints()

    def copyHuman(self, other):
        self.gender = other.gender
        self.loaded = other.loaded
        self.loadAnimatedHead = other.loadAnimatedHead
        self.rootScale = other.rootScale

    def delete(self):

        try:
            pass
        except:
            self.Human_deleted = 1
            taskMgr.remove(self._Human__blinkName)
            name = self.flattenSuperLowName
            if name:
                self.flattenSuperLowName = None
                self.ignore(name)
                taskMgr.remove(name)

            if self.dropShadow and not self.dropShadow.isEmpty():
                self.deleteDropShadow()

            del self.eyeFSM
            self.controlShapes = None
            self.sliderNames = None
            Biped.Biped.delete(self)

    def isDeleted(self):

        try:
            if self.Human_deleted == 1:
                return True
        except:
            return False

    def fixEyes(self):
        self.eyeLids = {}
        self.eyeBalls = {}
        self.eyeIris = {}
        for lodName in self.getLODNames():
            geom = self.getPart("head", lodName)
            self.eyeLids[lodName] = geom.findAllMatches("**/*eyelid*")
            self.eyeBalls[lodName] = geom.findAllMatches("**/eye_ball*")
            self.eyeIris[lodName] = geom.findAllMatches("**/eye_iris*")
            self.eyeLids[lodName].stash()
            self.eyeBalls[lodName].unstash()
            self.eyeIris[lodName].unstash()

    def makeAnimDict(self, gender, animNames):
        self.animTable = []
        for currAnim in animNames:
            anim = animNames.get(currAnim)
            for currAnimName in anim:
                self.animTable.append([currAnimName, currAnimName])

        self.reducedAnimList = self.animTable

    def forceLoadAnimDict(self):
        for anim in self.animDict.keys():
            self.getAnimControls(anim)

    def createAnimDict(self, customList=None):
        filePrefix = "models/char/m"
        genderPrefix = "m"
        if self.style.gender == "f":
            self.type = BodyDefs.femaleFrames[self.style.getBodyShape()]
            filePrefix = "models/char/f"
            genderPrefix = "f"
        else:
            self.type = BodyDefs.maleFrames[self.style.getBodyShape()]
        if self.reducedAnimList is None:
            self.animDict = self.prebuiltAnimData[genderPrefix + self.type]
            return None

        filePrefix += "p"
        animList = self.reducedAnimList
        self.animDict = {}
        for anim in animList:
            animSuffix = ""
            for i in range(0, len(CustomAnimDict[genderPrefix + self.type])):
                if anim[0] == CustomAnimDict[genderPrefix + self.type][i]:
                    animSuffix = "_" + genderPrefix + NewModelDict.get(self.type)
                    break
                    continue

            self.animDict[anim[0]] = filePrefix + "_" + anim[1] + animSuffix

        return filePrefix

    def getIsPaid(self):
        return True

    def setupGhostNodes(self):
        lod = NodePath(self.getLODNode())
        for node in lod.getChildren():
            eyes = node.findAllMatches("**/eye*")
            if eyes:
                eyes.wrtReparentTo(eyes[0].getParent().attachNewNode(ModelNode("eyes")))
                continue

    def loadHuman(self, other):
        other.style = self.style
        other.gender = self.style.gender
        other.model.dna = self.style
        self.createAnimDict()
        if self.style.gender == "f":
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 1
        else:
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 0
        other.zombie = self.zombie
        other.crazyColorSkin = self.crazyColorSkin
        other.setCrazyColorSkinIndex(self.getCrazyColorSkinIndex())
        yieldThread("anim dict")
        other.isPaid = self.getIsPaid()
        other.showLOD(2000)
        yieldThread("showLOD")
        base.loadingScreen.tick()
        if other.zombie:
            other.showZombie()

        if hasattr(self, "motionFSM"):
            self.motionFSM.setAvatar(self)

        base.loadingScreen.tick()
        yieldThread("zombie")
        other.applyBodyShaper()
        base.loadingScreen.tick()
        yieldThread("body shaper")
        base.loadingScreen.tick()
        other.applyHeadShaper()
        yieldThread("head shaper")
        base.loadingScreen.tick()
        if self.zombie == 2:
            other.model.eyeBalls.unstash()
            other.model.irises.stash()
        elif self.zombie:
            other.model.eyeBalls.stash()
            other.model.irises.stash()
        else:
            other.model.eyeBalls.unstash()
            other.model.irises.unstash()
        base.loadingScreen.tick()
        self.copyActor(other)
        base.loadingScreen.tick()
        self.floorOffsetZ = other.rootNode.getZ()
        yieldThread("copyActor")
        self.copyHuman(other)
        if self.isGhost:
            self.setupGhostNodes()

        gnodes = self.getLOD("500").findAllMatches("**/+GeomNode")
        for node in gnodes:
            node.setTextureOff(other.model.tattooStage)

        base.loadingScreen.tick()
        self.flattenSuperLow()
        self.rootNode = self.getLOD("500").find("**/dx_root")
        self.headNode = self.getLOD("500").find("**/def_head01")
        lodNames = self.getLODNames()
        self.scaleNode = self.controlJoint(None, "legs", "def_scale_jt", lodNames[0])
        if len(lodNames) > 1:
            for i in range(1, len(lodNames)):
                self.controlJoint(self.scaleNode, "legs", "def_scale_jt", lodNames[i])

        self.setGlobalScale(self.calcBodyScale())
        yieldThread("copyHuman")
        base.loadingScreen.tick()
        self.loadAnimsOnAllLODs(self.animDict, "modelRoot")
        base.loadingScreen.tick()
        yieldThread("loadAnims")
        other.zombie = 0
        other.crazyColorSkin = 0
        other.setCrazyColorSkinIndex(0)
        other.showNormal()
        yieldThread("show normal")
        self.initializeNametag3d()
        self.initializeDropShadow()
        self.setName(self.getName())
        yieldThread("misc nodes")
        base.loadingScreen.tick()
        self.loaded = 1

    def setGlobalScale(self, scale):
        self.scaleNode.setScale(scale)
        self.rootScale = scale
        self.scaleNode.setZ(-(self.floorOffsetZ * (1 - scale)))

    def initializeMiscNodes(self):
        self.initializeNametag3d()
        self.initializeDropShadow()

    def undoControlJoints(self):
        self.getGeomNode().getParent().findAllMatches("def_*").detach()
        self.getGeomNode().getParent().findAllMatches("trs_*").detach()
        self.findAllMatches("def_*").detach()
        self.findAllMatches("trs_*").detach()

    def cleanupHuman(self, gender="m"):
        self.eyeFSM.request("off")
        self.undoControlJoints()
        self.removeCopiedNodes()
        self.eyeLids = {}
        self.eyeBalls = {}
        self.eyeIris = {}
        self.flush()
        self.loaded = 0
        self.master = 0

    def getCrazyColorSkinIndex(self):
        return self.crazyColorSkinIndex

    def setCrazyColorSkinIndex(self, index):
        if len(HumanDNA.crazySkinColors) > index:
            self.crazyColorSkinIndex = index
        else:
            self.notify.warning(
                "(Human)index: %d is out of bounds for crazyColorSkin: %d" % (index, len(HumanDNA.crazySkinColors))
            )

    def generateHuman(self, gender, others, useFaceTex=False):
        parent = self.getParent()
        self.detachNode()
        if gender == "f":
            other = others[1]
        else:
            other = others[0]
        if self.loaded:
            self.cleanupHuman()

        other.useFaceTex = useFaceTex
        self.loadHuman(other)
        if self.isLocal():
            self.renderReflection = True

        self.setRenderReflection()
        self.resetEffectParent()
        self.enableMixing()
        self.reparentTo(parent)

    def getShadowJoint(self):
        return self.nametagNodePath

    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle("modelRoot", lodName)
            joint = bundle.findChild("name_tag")
            if joint:
                joints.append(joint)
                continue

        return joints

    def _Human__blinkOpenEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() == "closed":
            self.eyeFSM.request("open")

        r = self.randGen.random()
        if r < 0.10000000000000001:
            t = 0.20000000000000001
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self._Human__blinkCloseEyes, self._Human__blinkName)
        return Task.done

    def _Human__blinkCloseEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() != "open":
            taskMgr.doMethodLater(4.0, self._Human__blinkCloseEyes, self._Human__blinkName)
        else:
            self.eyeFSM.request("closed")
            taskMgr.doMethodLater(0.125, self._Human__blinkOpenEyes, self._Human__blinkName)
        return Task.done

    def startBlink(self):
        taskMgr.remove(self._Human__blinkName)
        if self.eyeLids:
            self.openEyes()

        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1, self._Human__blinkCloseEyes, self._Human__blinkName)

    def stopBlink(self):
        taskMgr.remove(self._Human__blinkName)
        if self.eyeLids:
            self.eyeFSM.request("open")

    def closeEyes(self):
        self.eyeFSM.request("closed")

    def openEyes(self):
        self.eyeFSM.request("open")

    def enterEyeFSMOff(self):
        pass

    def exitEyeFSMOff(self):
        pass

    def enterEyeFSMOpen(self):
        for lodName in self.getLODNames():
            self.eyeLids[lodName].hide()
            self.eyeBalls[lodName].show()
            self.eyeIris[lodName].show()

    def exitEyeFSMOpen(self):
        pass

    def enterEyeFSMClosed(self):
        return None
        for lodName in self.getLODNames():
            self.eyeLids[lodName].show()
            self.eyeBalls[lodName].hide()
            self.eyeIris[lodName].hide()

    def exitEyeFSMClosed(self):
        pass

    def getGlobalScale(self):
        return self.rootScale

    def calcBodyScale(self):
        idx = 0
        if self.gender == "f":
            idx = 1

        mappedValue = (0.80000000000000004 + (1 + self.style.getBodyHeight()) * 0.20000000000000001) * BodyScales[idx][
            self.style.getBodyShape()
        ]
        return mappedValue

    def setupAnimDicts(cls):
        for t in BodyDefs.maleFrames:
            cls.storeAnimDict("models/char/mp", "m", t)

        for t in BodyDefs.femaleFrames:
            cls.storeAnimDict("models/char/fp", "f", t)

    setupAnimDicts = classmethod(setupAnimDicts)

    def storeAnimDict(cls, prefix, gender, type):
        qualifier = gender + type
        animList = AnimListDict[type]
        cls.prebuiltAnimData[qualifier] = {}
        for anim in animList:
            if anim[0] == "intro":
                continue

            animSuffix = ""
            for i in range(0, len(CustomAnimDict[qualifier])):
                if anim[0] == CustomAnimDict[qualifier][i]:
                    animSuffix = "_" + gender + NewModelDict.get(type)
                    break
                    continue

            cls.prebuiltAnimData[qualifier][anim[0]] = prefix + "_" + anim[1] + animSuffix

    storeAnimDict = classmethod(storeAnimDict)
示例#55
0
文件: Human.py 项目: Kealigal/POS2013
class Human(HumanBase.HumanBase, Biped.Biped):
    notify = DirectNotifyGlobal.directNotify.newCategory('Human')
    prebuiltAnimData = {}

    def __init__(self, other=None):
        Biped.Biped.__init__(self, other, HumanAnimationMixer)
        self.zombie = False
        self.crazyColorSkin = False
        self.crazyColorSkinIndex = 0
        self.flattenPending = None
        self.flattenSuperLowName = None
        self.optimizeLOD = base.config.GetBool('optimize-avatar-lod', 1)
        self.loaded = 0
        self.playingRate = None
        self.shadowFileName = 'models/misc/drop_shadow'
        self.setFont(PiratesGlobals.getInterfaceFont())
        self._Human__blinkName = 'blink-' + str(self.this)
        self.eyeLids = None
        self.eyeBalls = None
        self.eyeIris = None
        self.reducedAnimList = None
        self.headNode = None
        self.headEffects = NodePath('headEffects')
        self.extraNode = None
        self.scaleNode = None
        self.rootNode = None
        self.floorOffsetZ = 0.0
        self.isGhost = 0
        self.headFudgeHpr = Vec3(0, 0, 0)
        self.randGen = random.Random()
        self.randGen.seed(random.random())
        self.eyeFSM = ClassicFSM('eyeFSM', [
            State('off', self.enterEyeFSMOff, self.exitEyeFSMOff,
                  ['open', 'closed']),
            State('open', self.enterEyeFSMOpen, self.exitEyeFSMOpen,
                  ['closed', 'off']),
            State('closed', self.enterEyeFSMClosed, self.exitEyeFSMClosed,
                  ['open', 'off'])
        ], 'off', 'off')
        self.eyeFSM.enterInitialState()
        if other != None:
            self.copyHuman(other)

    def removeCopiedNodes(self):
        self.dropShadow = self.find('**/drop_shadow*')
        if not self.dropShadow.isEmpty():
            self.deleteDropShadow()
        else:
            self.dropShadow = None
        billboardNode = self.find('**/billboardNode')
        if not billboardNode.isEmpty():
            billboardNode.removeNode()

        self.getGeomNode().getParent().removeNode()

    def flattenHuman(self):
        self.getWeaponJoints()

    def flattenSuperLow(self):
        name = 'flattenSuperLow-%s' % self.this
        self.flattenSuperLowName = name
        model = self.getLOD('500')
        self.accept(name, self._Human__doneFlattenSuperLow)
        taskMgr.remove(name)
        taskMgr.add(self.flattenSuperLowTask,
                    name,
                    extraArgs=[model],
                    taskChain='background')

    def flattenSuperLowTask(self, model):
        model = model.copyTo(NodePath())
        rhn = model.find('**/rightHand')
        lhn = model.find('**/leftHand')
        if lhn:
            lhn.detachNode()

        if rhn:
            rhn.detachNode()

        node = model.node()
        gr = SceneGraphReducer()
        model.node().setAttrib(TransparencyAttrib.make(0), 2000)
        gr.applyAttribs(
            node, SceneGraphReducer.TTApplyTextureColor
            | SceneGraphReducer.TTTexMatrix | SceneGraphReducer.TTOther
            | SceneGraphReducer.TTCullFace | SceneGraphReducer.TTTransform
            | SceneGraphReducer.TTColor | SceneGraphReducer.TTColorScale)
        num_removed = gr.flatten(node, -1)
        gr.makeCompatibleState(node)
        gr.collectVertexData(
            node, ~(SceneGraphReducer.CVDFormat | SceneGraphReducer.CVDName
                    | SceneGraphReducer.CVDAnimationType))
        gr.unify(node, 0)
        name = self.flattenSuperLowName
        if name:
            messenger.send(name, [model], taskChain='default')

    def _Human__doneFlattenSuperLow(self, flat):
        self.headNode = flat.find('**/def_head01')
        self.rootNode = flat.find('**/dx_root')
        self.getWeaponJoints()
        orig = self.getLOD('500')
        orig.getChildren().detach()
        self.loadModel(flat, lodName='500', copy=False, autoBindAnims=False)
        self.getWeaponJoints()
        if hasattr(self, 'animProp') and self.animProp:
            self.resetAnimProp()

        self.findAllMatches('**/def_head01').detach()
        self.findAllMatches('**/dx_root').detach()
        for lodName in self.getLODNames():
            if lodName == '500':
                self.headNode.reparentTo(
                    self.getLOD(lodName).find('**/+Character'))
                self.rootNode.reparentTo(
                    self.getLOD(lodName).find('**/+Character'))
                continue
            self.headNode.instanceTo(
                self.getLOD(lodName).find('**/+Character'))
            self.rootNode.instanceTo(
                self.getLOD(lodName).find('**/+Character'))

        self.headEffects.reparentTo(self.headNode)

    def _Human__doneFlattenHuman(self, models):
        self.flattenPending = None
        self.getWeaponJoints()

    def copyHuman(self, other):
        self.gender = other.gender
        self.loaded = other.loaded
        self.loadAnimatedHead = other.loadAnimatedHead
        self.rootScale = other.rootScale

    def delete(self):

        try:
            pass
        except:
            self.Human_deleted = 1
            taskMgr.remove(self._Human__blinkName)
            name = self.flattenSuperLowName
            if name:
                self.flattenSuperLowName = None
                self.ignore(name)
                taskMgr.remove(name)

            if self.dropShadow and not self.dropShadow.isEmpty():
                self.deleteDropShadow()

            del self.eyeFSM
            self.controlShapes = None
            self.sliderNames = None
            Biped.Biped.delete(self)

    def isDeleted(self):

        try:
            if self.Human_deleted == 1:
                return True
        except:
            return False

    def fixEyes(self):
        self.eyeLids = {}
        self.eyeBalls = {}
        self.eyeIris = {}
        for lodName in self.getLODNames():
            geom = self.getPart('head', lodName)
            self.eyeLids[lodName] = geom.findAllMatches('**/*eyelid*')
            self.eyeBalls[lodName] = geom.findAllMatches('**/eye_ball*')
            self.eyeIris[lodName] = geom.findAllMatches('**/eye_iris*')
            self.eyeLids[lodName].stash()
            self.eyeBalls[lodName].unstash()
            self.eyeIris[lodName].unstash()

    def makeAnimDict(self, gender, animNames):
        self.animTable = []
        for currAnim in animNames:
            anim = animNames.get(currAnim)
            for currAnimName in anim:
                self.animTable.append([currAnimName, currAnimName])

        self.reducedAnimList = self.animTable

    def forceLoadAnimDict(self):
        for anim in self.animDict.keys():
            self.getAnimControls(anim)

    def createAnimDict(self, customList=None):
        filePrefix = 'models/char/m'
        genderPrefix = 'm'
        if self.style.gender == 'f':
            self.type = BodyDefs.femaleFrames[self.style.getBodyShape()]
            filePrefix = 'models/char/f'
            genderPrefix = 'f'
        else:
            self.type = BodyDefs.maleFrames[self.style.getBodyShape()]
        if self.reducedAnimList is None:
            self.animDict = self.prebuiltAnimData[genderPrefix + self.type]
            return None

        filePrefix += 'p'
        animList = self.reducedAnimList
        self.animDict = {}
        for anim in animList:
            animSuffix = ''
            for i in range(0, len(CustomAnimDict[genderPrefix + self.type])):
                if anim[0] == CustomAnimDict[genderPrefix + self.type][i]:
                    animSuffix = '_' + genderPrefix + NewModelDict.get(
                        self.type)
                    break
                    continue

            self.animDict[anim[0]] = filePrefix + '_' + anim[1] + animSuffix

        return filePrefix

    def getIsPaid(self):
        return True

    def setupGhostNodes(self):
        lod = NodePath(self.getLODNode())
        for node in lod.getChildren():
            eyes = node.findAllMatches('**/eye*')
            if eyes:
                eyes.wrtReparentTo(eyes[0].getParent().attachNewNode(
                    ModelNode('eyes')))
                continue

    def loadHuman(self, other):
        other.style = self.style
        other.gender = self.style.gender
        other.model.dna = self.style
        self.createAnimDict()
        if self.style.gender == 'f':
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 1
        else:
            self.headFudgeHpr = Vec3(0, 0, 0)
            idx = 0
        other.zombie = self.zombie
        other.crazyColorSkin = self.crazyColorSkin
        other.setCrazyColorSkinIndex(self.getCrazyColorSkinIndex())
        yieldThread('anim dict')
        other.isPaid = self.getIsPaid()
        other.showLOD(2000)
        yieldThread('showLOD')
        base.loadingScreen.tick()
        if other.zombie:
            other.showZombie()

        if hasattr(self, 'motionFSM'):
            self.motionFSM.setAvatar(self)

        base.loadingScreen.tick()
        yieldThread('zombie')
        other.applyBodyShaper()
        base.loadingScreen.tick()
        yieldThread('body shaper')
        base.loadingScreen.tick()
        other.applyHeadShaper()
        yieldThread('head shaper')
        base.loadingScreen.tick()
        if self.zombie == 2:
            other.model.eyeBalls.unstash()
            other.model.irises.stash()
        elif self.zombie:
            other.model.eyeBalls.stash()
            other.model.irises.stash()
        else:
            other.model.eyeBalls.unstash()
            other.model.irises.unstash()
        base.loadingScreen.tick()
        self.copyActor(other)
        base.loadingScreen.tick()
        self.floorOffsetZ = other.rootNode.getZ()
        yieldThread('copyActor')
        self.copyHuman(other)
        if self.isGhost:
            self.setupGhostNodes()

        gnodes = self.getLOD('500').findAllMatches('**/+GeomNode')
        for node in gnodes:
            node.setTextureOff(other.model.tattooStage)

        base.loadingScreen.tick()
        self.flattenSuperLow()
        self.rootNode = self.getLOD('500').find('**/dx_root')
        self.headNode = self.getLOD('500').find('**/def_head01')
        lodNames = self.getLODNames()
        self.scaleNode = self.controlJoint(None, 'legs', 'def_scale_jt',
                                           lodNames[0])
        if len(lodNames) > 1:
            for i in range(1, len(lodNames)):
                self.controlJoint(self.scaleNode, 'legs', 'def_scale_jt',
                                  lodNames[i])

        self.setGlobalScale(self.calcBodyScale())
        yieldThread('copyHuman')
        base.loadingScreen.tick()
        self.loadAnimsOnAllLODs(self.animDict, 'modelRoot')
        base.loadingScreen.tick()
        yieldThread('loadAnims')
        other.zombie = 0
        other.crazyColorSkin = 0
        other.setCrazyColorSkinIndex(0)
        other.showNormal()
        yieldThread('show normal')
        self.initializeNametag3d()
        self.initializeDropShadow()
        self.setName(self.getName())
        yieldThread('misc nodes')
        base.loadingScreen.tick()
        self.loaded = 1

    def setGlobalScale(self, scale):
        self.scaleNode.setScale(scale)
        self.rootScale = scale
        self.scaleNode.setZ(-(self.floorOffsetZ * (1 - scale)))

    def initializeMiscNodes(self):
        self.initializeNametag3d()
        self.initializeDropShadow()

    def undoControlJoints(self):
        self.getGeomNode().getParent().findAllMatches('def_*').detach()
        self.getGeomNode().getParent().findAllMatches('trs_*').detach()
        self.findAllMatches('def_*').detach()
        self.findAllMatches('trs_*').detach()

    def cleanupHuman(self, gender='m'):
        self.eyeFSM.request('off')
        self.undoControlJoints()
        self.removeCopiedNodes()
        self.eyeLids = {}
        self.eyeBalls = {}
        self.eyeIris = {}
        self.flush()
        self.loaded = 0
        self.master = 0

    def getCrazyColorSkinIndex(self):
        return self.crazyColorSkinIndex

    def setCrazyColorSkinIndex(self, index):
        if len(HumanDNA.crazySkinColors) > index:
            self.crazyColorSkinIndex = index
        else:
            self.notify.warning(
                '(Human)index: %d is out of bounds for crazyColorSkin: %d' %
                (index, len(HumanDNA.crazySkinColors)))

    def generateHuman(self, gender, others, useFaceTex=False):
        parent = self.getParent()
        self.detachNode()
        if gender == 'f':
            other = others[1]
        else:
            other = others[0]
        if self.loaded:
            self.cleanupHuman()

        other.useFaceTex = useFaceTex
        self.loadHuman(other)
        if self.isLocal():
            self.renderReflection = True

        self.setRenderReflection()
        self.resetEffectParent()
        self.enableMixing()
        self.reparentTo(parent)

    def getShadowJoint(self):
        return self.nametagNodePath

    def getNametagJoints(self):
        joints = []
        for lodName in self.getLODNames():
            bundle = self.getPartBundle('modelRoot', lodName)
            joint = bundle.findChild('name_tag')
            if joint:
                joints.append(joint)
                continue

        return joints

    def _Human__blinkOpenEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() == 'closed':
            self.eyeFSM.request('open')

        r = self.randGen.random()
        if r < 0.10000000000000001:
            t = 0.20000000000000001
        else:
            t = r * 4.0 + 1.0
        taskMgr.doMethodLater(t, self._Human__blinkCloseEyes,
                              self._Human__blinkName)
        return Task.done

    def _Human__blinkCloseEyes(self, task):
        if self.eyeFSM.getCurrentState().getName() != 'open':
            taskMgr.doMethodLater(4.0, self._Human__blinkCloseEyes,
                                  self._Human__blinkName)
        else:
            self.eyeFSM.request('closed')
            taskMgr.doMethodLater(0.125, self._Human__blinkOpenEyes,
                                  self._Human__blinkName)
        return Task.done

    def startBlink(self):
        taskMgr.remove(self._Human__blinkName)
        if self.eyeLids:
            self.openEyes()

        taskMgr.doMethodLater(self.randGen.random() * 4.0 + 1,
                              self._Human__blinkCloseEyes,
                              self._Human__blinkName)

    def stopBlink(self):
        taskMgr.remove(self._Human__blinkName)
        if self.eyeLids:
            self.eyeFSM.request('open')

    def closeEyes(self):
        self.eyeFSM.request('closed')

    def openEyes(self):
        self.eyeFSM.request('open')

    def enterEyeFSMOff(self):
        pass

    def exitEyeFSMOff(self):
        pass

    def enterEyeFSMOpen(self):
        for lodName in self.getLODNames():
            self.eyeLids[lodName].hide()
            self.eyeBalls[lodName].show()
            self.eyeIris[lodName].show()

    def exitEyeFSMOpen(self):
        pass

    def enterEyeFSMClosed(self):
        return None
        for lodName in self.getLODNames():
            self.eyeLids[lodName].show()
            self.eyeBalls[lodName].hide()
            self.eyeIris[lodName].hide()

    def exitEyeFSMClosed(self):
        pass

    def getGlobalScale(self):
        return self.rootScale

    def calcBodyScale(self):
        idx = 0
        if self.gender == 'f':
            idx = 1

        mappedValue = (0.80000000000000004 +
                       (1 + self.style.getBodyHeight()) * 0.20000000000000001
                       ) * BodyScales[idx][self.style.getBodyShape()]
        return mappedValue

    def setupAnimDicts(cls):
        for t in BodyDefs.maleFrames:
            cls.storeAnimDict('models/char/mp', 'm', t)

        for t in BodyDefs.femaleFrames:
            cls.storeAnimDict('models/char/fp', 'f', t)

    setupAnimDicts = classmethod(setupAnimDicts)

    def storeAnimDict(cls, prefix, gender, type):
        qualifier = gender + type
        animList = AnimListDict[type]
        cls.prebuiltAnimData[qualifier] = {}
        for anim in animList:
            if anim[0] == 'intro':
                continue

            animSuffix = ''
            for i in range(0, len(CustomAnimDict[qualifier])):
                if anim[0] == CustomAnimDict[qualifier][i]:
                    animSuffix = '_' + gender + NewModelDict.get(type)
                    break
                    continue

            cls.prebuiltAnimData[qualifier][
                anim[0]] = prefix + '_' + anim[1] + animSuffix

    storeAnimDict = classmethod(storeAnimDict)
class CogInvasionClientRepository(AstronClientRepository):
    notify = directNotify.newCategory("CIClientRepository")
    GameGlobalsId = DO_ID_COGINVASION
    SetZoneDoneEvent = 'CICRSetZoneDone'
    EmuSetZoneDoneEvent = 'CICREmuSetZoneDone'
    SetInterest = 'Set'
    ClearInterest = 'Clear'
    ClearInterestDoneEvent = 'CICRClearInterestDone'
    ITAG_PERM = 'perm'
    ITAG_AVATAR = 'avatar'
    ITAG_SHARD = 'shard'
    ITAG_WORLD = 'world'
    ITAG_GAME = 'game'

    def __init__(self, serverVersion):
        self.serverVersion = serverVersion
        AstronClientRepository.__init__(
            self, ['phase_3/etc/direct.dc', 'phase_3/etc/toon.dc'])
        self.loginFSM = ClassicFSM('login', [
            State('off', self.enterOff, self.exitOff),
            State('connect', self.enterConnect, self.exitConnect),
            State('disconnect', self.enterDisconnect, self.exitDisconnect),
            State('avChoose', self.enterAvChoose, self.exitAvChoose),
            State('playingGame', self.enterPlayingGame, self.exitPlayingGame),
            State('serverUnavailable', self.enterServerUnavailable,
                  self.exitServerUnavailable),
            State('makeAToon', self.enterMakeAToon, self.exitMakeAToon),
            State('submitNewToon', self.enterSubmitNewToon,
                  self.exitSubmitNewToon),
            State('noShards', self.enterNoShards, self.exitNoShards),
            State('waitForSetAvatarResponse',
                  self.enterWaitForSetAvatarResponse,
                  self.exitWaitForSetAvatarResponse),
            State('waitForShardList', self.enterWaitForShardList,
                  self.exitWaitForShardList),
            State('ejected', self.enterEjected, self.exitEjected),
            State('districtReset', self.enterDistrictReset,
                  self.exitDistrictReset),
            State('died', self.enterDied, self.exitDied),
            State('betaInform', self.enterBetaInform, self.exitBetaInform)
        ], 'off', 'off')
        self.loginFSM.enterInitialState()
        self.gameFSM = ClassicFSM('game', [
            State('off', self.enterGameOff, self.exitGameOff),
            State('waitForGameEnterResponse',
                  self.enterWaitForGameEnterResponse,
                  self.exitWaitForGameEnterResponse),
            State('playGame', self.enterPlayGame, self.exitPlayGame),
            State('closeShard', self.enterCloseShard, self.exitCloseShard),
            State('switchShards', self.enterSwitchShards,
                  self.exitSwitchShards)
        ], 'off', 'off')
        self.gameFSM.enterInitialState()
        #self.taskNameAllocator = UniqueIdAllocator(0, 1000000000)
        self.avChooser = AvChooser(self.loginFSM)
        self.playGame = PlayGame(self.gameFSM, "playGameDone")
        self.hoodMgr = HoodMgr()
        self.makeAToon = MakeAToon()
        self.loginToken = os.environ.get("LOGIN_TOKEN")
        self.serverAddress = os.environ.get("GAME_SERVER")
        self.serverURL = URLSpec("http://%s" % self.serverAddress)
        self.parentMgr.registerParent(CIGlobals.SPRender, render)
        self.parentMgr.registerParent(CIGlobals.SPHidden, hidden)
        self.adminAccess = False
        self.localAvChoice = None
        self.SuitsActive = 0
        self.BossActive = 0
        self.accServerTimesNA = 0
        self.maxAccServerTimesNA = 10
        self.setZonesEmulated = 0
        self.old_setzone_interest_handle = None
        self.setZoneQueue = Queue()
        self.accept(self.SetZoneDoneEvent, self._handleEmuSetZoneDone)
        self.handler = None
        self.__currentAvId = 0
        self.myDistrict = None
        self.activeDistricts = {}
        self.shardListHandle = None
        self.uberZoneInterest = None
        self.isShowingPlayerIds = False
        self.doBetaInform = False
        self.dTutorial = None
        self.requestedName = None
        self.whisperNoise = base.loadSfx(
            'phase_3.5/audio/sfx/GUI_whisper_3.ogg')
        self.checkHttp()
        #self.http.addPreapprovedServerCertificateFilename(self.serverURL, Filename('phase_3/etc/gameserver.crt'))
        #self.tournamentMusicChunks = {}
        #self.threadedTaskChain = taskMgr.setupTaskChain("threadedTaskChainForSoundIntervals", numThreads = 2)

        self.attackMgr = base.cl_attackMgr

        base.minigame = None

        self.newToonSlot = None

        base.finalExitCallbacks.insert(0, self.__handleExit)

        self.accountName = os.environ.get('ACCOUNT_NAME', '')
        self.csm = self.generateGlobalObject(DO_ID_CLIENT_SERVICES_MANAGER,
                                             'ClientServicesManager')
        self.friendsManager = self.generateGlobalObject(
            DO_ID_FRIENDS_MANAGER, 'FriendsManager')
        self.uin = self.generateGlobalObject(DO_ID_UNIQUE_INTEREST_NOTIFIER,
                                             'UniqueInterestNotifier')
        self.statsManager = self.generateGlobalObject(DO_ID_STATS_MANAGER,
                                                      'StatsManager')

        self.pingToggle = False
        self.currentPing = None

        self.pingText = OnscreenText("",
                                     align=TextNode.ALeft,
                                     parent=base.a2dBottomLeft,
                                     fg=(1, 1, 1, 1),
                                     shadow=(0, 0, 0, 0.5),
                                     pos=(0.3, 0.09))
        self.pingText.setBin('gsg-popup', 1000)
        self.pingText.hide()

        SpeedHackChecker.startChecking()
        self.loginFSM.request('connect')
        return

    def readerPollUntilEmpty(self, task):
        while self.readerPollOnce():
            pass

        if not metadata.IS_PRODUCTION:
            if ConfigVariableBool('simulated-latency', False).getValue():
                latency = random.uniform(
                    ConfigVariableDouble('simulated-latency-min',
                                         0.125).getValue(),
                    ConfigVariableDouble('simulated-latency-max',
                                         0.15).getValue())
                task.delayTime = latency
                return task.again

        return task.cont

    def togglePing(self):
        self.pingToggle = not self.pingToggle

        if self.pingToggle:
            taskMgr.add(self.__districtPingTask, "CICR.districtPingTask")
            self.showPing()
        else:
            self.hidePing()
            taskMgr.remove("CICR.districtPingTask")

    def showPing(self):
        self.pingText.show()

    def hidePing(self):
        self.pingText.hide()

    def handleNewPing(self):
        if self.currentPing is None:
            display = "?"
        else:
            display = int(round(self.currentPing))

        self.pingText.setText("Ping: {0} ms".format(display))

    def __districtPingTask(self, task):
        if self.myDistrict:
            # Figure out how much network latency there is.
            self.myDistrict.d_ping()

        task.delayTime = 1.0
        return task.again

    def deleteObject(self, doId):
        """
        implementation copied from AstronClientRepository.py

        Brian: modified to also delete owner views

        Removes the object from the client's view of the world.  This
        should normally not be called directly except in the case of
        error recovery, since the server will normally be responsible
        for deleting and disabling objects as they go out of scope.

        After this is called, future updates by server on this object
        will be ignored (with a warning message).  The object will
        become valid again the next time the server sends a generate
        message for this doId.

        This is not a distributed message and does not delete the
        object on the server or on any other client.
        """

        if doId in self.doId2do:
            # If it is in the dictionary, remove it.
            obj = self.doId2do[doId]
            # Remove it from the dictionary
            del self.doId2do[doId]
            # Disable, announce, and delete the object itself...
            # unless delayDelete is on...
            obj.deleteOrDelay()
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif doId in self.doId2ownerView:
            # If it is in the owner dictionary, remove it.
            obj = self.doId2ownerView[doId]
            # Remove it from the dictionary
            del self.doId2ownerView[doId]
            # Disable, announce, and delete the object itself...
            # unless delayDelete is on...
            obj.deleteOrDelay()
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif self.cache.contains(doId):
            # If it is in the cache, remove it.
            self.cache.delete(doId)
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif self.cacheOwner.contains(doId):
            # If it is in the owner cache, remove it.
            self.cacheOwner.delete(doId)
            if self.isLocalId(doId):
                self.freeDoId(doId)
        else:
            # Otherwise, ignore it
            self.notify.warning("Asked to delete non-existent DistObj " +
                                str(doId))

    #def uniqueName(self, idString):
    #	return "%s-%s" % (idString, self.taskNameAllocator.allocate())

    #def removeTask(self, taskName):
    #	div = taskName.split('-')
    #	self.taskNameAllocator.free(div[1])
    #	taskMgr.remove(taskName)

    def __handleExit(self):
        try:
            base.localAvatar.b_setAnimState('teleportOut')
        except:
            pass

        ccoginvasion.CTMusicData.stop_am_update_task()

        self.gameFSM.request('closeShard', ['off'])

    def isChristmas(self):
        return self.holidayManager.getHoliday() == HolidayType.CHRISTMAS

    def showPlayerIds(self):
        print "Showing player ids..."
        self.isShowingPlayerIds = True
        for av in self.doId2do.values():
            if av.__class__.__name__ in [
                    "DistributedPlayerToon", "LocalToon", "DistributedSuit"
            ]:
                av.showAvId()

    def hidePlayerIds(self):
        print "Hiding player ids..."
        self.isShowingPlayerIds = False
        for av in self.doId2do.values():
            if av.__class__.__name__ in [
                    "DistributedPlayerToon", "LocalToon", 'DistributedSuit'
            ]:
                av.showName()

    def sendSetLocation(self, doId, parentId, zoneId):
        dg = PyDatagram()
        dg.addUint16(CLIENT_OBJECT_LOCATION)
        dg.addUint32(doId)
        dg.addUint32(parentId)
        dg.addUint32(zoneId)
        self.send(dg)

    def getNextSetZoneDoneEvent(self):
        return '%s-%s' % (self.EmuSetZoneDoneEvent, self.setZonesEmulated + 1)

    def getLastSetZoneDoneEvent(self):
        return '%s-%s' % (self.EmuSetZoneDoneEvent, self.setZonesEmulated)

    def getQuietZoneLeftEvent(self):
        return 'leftQuietZone-%s' % (id(self), )

    def b_setLocation(self, do, parentId, zoneId):
        self.sendSetLocation(do.doId, parentId, zoneId)
        do.setLocation(parentId, zoneId)

    def sendSetZoneMsg(self, zoneId, visibleZoneList=None):
        event = self.getNextSetZoneDoneEvent()
        self.setZonesEmulated += 1
        parentId = base.localAvatar.defaultShard
        self.sendSetLocation(base.localAvatar.doId, parentId, zoneId)
        localAvatar.setLocation(parentId, zoneId)
        interestZones = zoneId
        if visibleZoneList is not None:
            interestZones = visibleZoneList
        self._addInterestOpToQueue(
            self.SetInterest, [parentId, interestZones, 'OldSetZoneEmulator'],
            event)
        return

    def resetInterestStateForConnectionLoss(self):
        self.old_setzone_interest_handle = None
        self.setZoneQueue.clear()
        return

    def _removeEmulatedSetZone(self, doneEvent):
        self._addInterestOpToQueue(self.ClearInterest, None, doneEvent)
        return

    def _addInterestOpToQueue(self, op, args, event):
        self.setZoneQueue.push([op, args, event])
        if len(self.setZoneQueue) == 1:
            self._sendNextSetZone()

    def _sendNextSetZone(self):
        op, args, event = self.setZoneQueue.top()
        if op == self.SetInterest:
            parentId, interestZones, name = args
            if self.old_setzone_interest_handle is None:
                self.old_setzone_interest_handle = self.addInterest(
                    parentId, interestZones, name, self.SetZoneDoneEvent)
            else:
                self.alterInterest(self.old_setzone_interest_handle, parentId,
                                   interestZones, name, self.SetZoneDoneEvent)
        elif op == self.ClearInterest:
            self.removeInterest(self.old_setzone_interest_handle,
                                self.SetZoneDoneEvent)
            self.old_setzone_interest_handle = None
        else:
            self.notify.error('unknown setZone op: %s' % op)
        return

    def _handleEmuSetZoneDone(self):
        op, args, event = self.setZoneQueue.pop()
        queueIsEmpty = self.setZoneQueue.isEmpty()
        if event is not None:
            messenger.send(event)
        if not queueIsEmpty:
            self._sendNextSetZone()
        return

    def enterSwitchShards(self, shardId, hoodId, zoneId, avId):
        self._switchShardParams = [shardId, hoodId, zoneId, avId]
        self.removeShardInterest(self._handleOldShardGone)

    def _handleOldShardGone(self):
        status = {}
        status['hoodId'] = self._switchShardParams[1]
        status['zoneId'] = self._switchShardParams[2]
        status['avId'] = self._switchShardParams[3]
        self.gameFSM.request('waitForGameEnterResponse',
                             [status, self._switchShardParams[0]])

    def exitSwitchShards(self):
        del self._switchShardParams

    def enterBetaInform(self):
        msg = (
            "Welcome to Cog Invasion Online!\n\nBefore playing, please remember that the game is in Alpha, "
            "and that you may encounter bugs and incomplete features.\n\nIf you happen to encounter any bugs, "
            "please report them to us by using the Contact Us Page at coginvasion.com.\n\nHave fun!"
        )
        self.dialog = GlobalDialog(message=msg,
                                   style=3,
                                   doneEvent="gameEnterChoice")
        self.dialog.show()
        self.acceptOnce("gameEnterChoice", self.handleGameEnterChoice)

    def handleGameEnterChoice(self):
        self.loginFSM.request('avChoose')

    def exitBetaInform(self):
        self.ignore("gameEnterChoice")
        self.dialog.cleanup()
        del self.dialog

    def enterCloseShard(self, nextState='avChoose'):
        self.setNoNewInterests(True)
        self._removeLocalAvFromStateServer(nextState)

    def exitCloseShard(self):
        self.setNoNewInterests(False)
        self.ignore(self.ClearInterestDoneEvent)
        return

    def _removeLocalAvFromStateServer(self, nextState):
        self.sendSetAvatarIdMsg(0)
        self._removeAllOV()
        callback = Functor(self.loginFSM.request, nextState)
        self.removeShardInterest(callback)

    def removeShardInterest(self, callback):
        self._removeCurrentShardInterest(
            Functor(self._removeShardInterestComplete, callback))

    def _removeShardInterestComplete(self, callback):
        self.cache.flush()
        self.doDataCache.flush()

        callback()
        return

    def _removeCurrentShardInterest(self, callback):
        if self.old_setzone_interest_handle is None:
            callback()
            return
        self.acceptOnce(self.ClearInterestDoneEvent,
                        Functor(self._removeCurrentUberZoneInterest, callback))
        self._removeEmulatedSetZone(self.ClearInterestDoneEvent)
        return

    def _removeCurrentUberZoneInterest(self, callback):
        self.acceptOnce(self.ClearInterestDoneEvent,
                        Functor(self._removeShardInterestDone, callback))
        self.removeInterest(self.uberZoneInterest, self.ClearInterestDoneEvent)

    def _removeShardInterestDone(self, callback):
        self.uberZoneInterest = None
        callback()
        return

    def _removeAllOV(self):
        owners = self.doId2ownerView.keys()
        for doId in owners:
            self.disableDoId(doId, ownerView=True)

    def enterDied(self):
        self.deathDialog = GlobalDialog(message=CIGlobals.SuitDefeatMsg,
                                        style=2,
                                        doneEvent="deathChoice")
        self.deathDialog.show()
        self.acceptOnce("deathChoice", self.handleDeathChoice)

    def handleDeathChoice(self):
        value = self.deathDialog.getValue()
        if value:
            self.loginFSM.request('avChoose')
        else:
            sys.exit()

    def exitDied(self):
        self.deathDialog.cleanup()
        del self.deathDialog
        self.ignore("deathChoice")

    def enterConnect(self):
        self.connectingDialog = GlobalDialog(message=CIGlobals.ConnectingMsg)
        self.connectingDialog.show()
        self.connect([self.serverURL],
                     successCallback=self.handleConnected,
                     failureCallback=self.handleConnectFail)

    def handleConnected(self):
        self.notify.info("Sending CLIENT_HELLO...")
        self.acceptOnce("CLIENT_HELLO_RESP", self.handleClientHelloResp)
        self.acceptOnce("CLIENT_EJECT", self.handleEjected)
        self.acceptOnce("LOST_CONNECTION", self.handleLostConnection)
        AstronClientRepository.sendHello(self, self.serverVersion)

    def handleLostConnection(self):
        self.deleteAllObjects()
        self.loginFSM.request('disconnect', [1])

    def deleteAllObjects(self):
        for doId in self.doId2do.keys():
            obj = self.doId2do[doId]

            if not isinstance(obj, DistributedObjectGlobal) and not hasattr(
                    obj, 'isDistrict'):
                if hasattr(base,
                           'localAvatar') and doId != base.localAvatar.doId:
                    self.deleteObject(doId)

    def handleEjected(self, errorCode, reason):
        self.notify.info("OMG I WAS EJECTED!")
        self.ignore("LOST_CONNECTION")
        errorMsg = ErrorCode2ErrorMsg.get(errorCode,
                                          None) or UnknownErrorMsg % errorCode
        self.loginFSM.request('ejected', [errorMsg])

    def handleClientHelloResp(self):
        self.notify.info("Got CLIENT_HELLO_RESP!")
        self.acceptOnce(self.csm.getLoginAcceptedEvent(),
                        self.handleLoginAccepted)
        self.csm.d_requestLogin(self.loginToken, self.accountName)

    def handleLoginAccepted(self):
        self.notify.info("Woo-hoo, I am authenticated!")
        base.cr.holidayManager = self.generateGlobalObject(
            DO_ID_HOLIDAY_MANAGER, 'HolidayManager')
        base.cr.nameServicesManager = self.generateGlobalObject(
            DO_ID_NAME_SERVICES_MANAGER, 'NameServicesManager')
        self.loginFSM.request('waitForShardList')

    def handleConnectFail(self, _, __):
        self.notify.info("Could not connect to gameserver, notifying user.")
        self.connectingDialog.cleanup()
        self.connectingDialog = GlobalDialog(
            message=CIGlobals.NoConnectionMsg % self.serverAddress + " " +
            CIGlobals.TryAgain,
            style=2,
            doneEvent="connectFail")
        self.connectingDialog.show()
        self.acceptOnce("connectFail", self.handleConnectFailButton)

    def handleConnectFailButton(self):
        value = self.connectingDialog.getValue()
        if value:
            self.loginFSM.request('connect')
        else:
            sys.exit()

    def exitConnect(self):
        self.ignore("connectFail")
        self.ignore("CLIENT_HELLO_RESP")
        self.ignore(self.csm.getLoginAcceptedEvent())
        self.connectingDialog.cleanup()
        del self.connectingDialog

    def enterEjected(self, errorMsg):
        self.ejectDialog = GlobalDialog(message=errorMsg,
                                        style=3,
                                        doneEvent='ejectDone')
        self.ejectDialog.show()
        self.acceptOnce('ejectDone', sys.exit)

    def exitEjected(self):
        self.ignore('ejectDone')
        self.ejectDialog.cleanup()
        del self.ejectDialog

    def enterServerUnavailable(self):
        self.notify.info(CIGlobals.ServerUnavailable)
        self.serverNA = GlobalDialog(message=CIGlobals.ServerUnavailable,
                                     style=4,
                                     doneEvent="serverNAEvent")
        self.serverNA.show()
        self.acceptOnce("serverNAEvent", sys.exit)
        self.startServerNAPoll()

    def startServerNAPoll(self):
        self.notify.info("Starting server poll...")
        self.accServerTimesNA = 1
        taskMgr.add(self.serverNAPoll, "serverNAPoll")

    def serverNAPoll(self, task):
        dg = PyDatagram()
        dg.addUint16(ACC_IS_SERVER_UP)
        self.send(dg)
        task.delayTime = 3.0
        return Task.again

    def __handleServerNAResp(self, resp):
        if resp == ACC_SERVER_UP:
            taskMgr.remove("serverNAPoll")
            # Enter the previous state that we were in, which should have
            # been some state where we communicate with the acc server.
            self.loginFSM.request(self.loginFSM.getLastState().getName())
        else:
            self.accServerTimesNA += 1
            if self.accServerTimesNA >= self.maxAccServerTimesNA:
                taskMgr.remove("serverNAPoll")
                self.notify.info(
                    "Giving up on polling account server after %s times." %
                    self.accServerTimesNA)
                self.loginFSM.request("disconnect", enterArgList=[1])
                self.accServerTimesNA = 0

    def exitServerUnavailable(self):
        self.ignore("serverNAEvent")
        self.serverNA.cleanup()
        del self.serverNA

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def playTheme(self):
        base.playMusic(CIGlobals.getThemeSong(), looping=1)

    def enterAvChoose(self, newToonSlot=None):
        ModelPool.garbageCollect()
        TexturePool.garbageCollect()
        self.avChooser.load()
        self.avChooser.enter(newToonSlot)
        if newToonSlot is None:
            self.playTheme()
        self.accept("enterMakeAToon", self.__handleMakeAToonReq)
        self.accept("avChooseDone", self.__handleAvChooseDone)

    def __handleMakeAToonReq(self, slot):
        self.loginFSM.request('makeAToon', [slot])

    def __handleAvChooseDone(self, avChoice):
        print "------- AvChooseDone -------"
        print "Toon name: %s" % avChoice.getName()
        print "Slot:      %s" % avChoice.getSlot()
        print "DNA:       %s" % avChoice.getDNA()
        self.loginFSM.request("waitForSetAvatarResponse", [avChoice])

    def exitAvChoose(self):
        self.avChooser.exit()
        self.avChooser.unload()
        self.ignore("enterMakeAToon")
        self.ignore("avChooseDone")

    def handlePlayGame(self, msgType, di):
        if msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER:
            self.handleGenerateWithRequiredOtherOwner(msgType, di)
        else:
            AstronClientRepository.handleDatagram(self, di)

    def enterPlayingGame(self):
        zoneId = localAvatar.getLastHood()
        hoodId = ZoneUtil.getHoodId(zoneId)
        status = {"hoodId": hoodId, "zoneId": zoneId, "avId": self.localAvId}
        shardId = self.myDistrict.doId
        self.gameFSM.request('waitForGameEnterResponse', [status, shardId])

    def exitPlayingGame(self):
        self.deleteAllObjects()
        self.handler = None
        self.gameFSM.request('off')
        camera.reparentTo(render)
        camera.setPos(0, 0, 0)
        camera.setHpr(0, 0, 0)
        self.localAvChoice = None
        if loader.inBulkBlock:
            loader.endBulkLoad(loader.blockName)

    def enterNoShards(self):
        self.noShardDialog = GlobalDialog(message=CIGlobals.NoShardsMsg + " " +
                                          CIGlobals.TryAgain,
                                          style=2,
                                          doneEvent='noShardsDone')
        self.noShardDialog.show()
        self.acceptOnce('noShardsDone', self.handleNoShardsDone)

    def handleNoShardsDone(self):
        value = self.noShardDialog.getValue()
        if value:
            self.loginFSM.request('waitForShardList')
        else:
            sys.exit()

    def exitNoShards(self):
        self.noShardDialog.cleanup()
        del self.noShardDialog
        self.ignore('noShardsDone')

    def enterWaitForShardList(self):
        self.shardListHandle = self.addTaggedInterest(
            self.GameGlobalsId,
            ZoneUtil.DistrictZone,
            self.ITAG_PERM,
            'localShardList',
            event='shardList_complete')
        self.acceptOnce('shardList_complete', self._handleShardListComplete)

    def _handleShardListComplete(self):
        if self._shardsAreAvailable():
            self.myDistrict = self._chooseAShard()
            if self.doBetaInform:
                self.loginFSM.request('betaInform')
            else:
                self.loginFSM.request('avChoose')
            taskMgr.add(self.monitorDistrict, "monitorMyDistrict")
        else:
            self.loginFSM.request('noShards')

    def monitorDistrict(self, task):
        if self.myDistrict is None and self.isConnected():
            self.loginFSM.request('districtReset')
            return task.done
        return task.cont

    def _shardsAreAvailable(self):
        for shard in self.activeDistricts.values():
            if shard.available:
                return True
        return False

    def _chooseAShard(self):
        choices = []
        for shard in self.activeDistricts.values():
            choices.append(shard)
        return random.choice(choices)

    def exitWaitForShardList(self):
        self.ignore('shardList_complete')

    def enterDistrictReset(self):
        self.districtResetDialog = GlobalDialog(
            message=CIGlobals.DistrictResetMsg,
            style=3,
            doneEvent='distresetdone')
        self.districtResetDialog.show()
        self.acceptOnce('distresetdone', sys.exit)

    def exitDistrictReset(self):
        self.districtResetDialog.cleanup()
        del self.districtResetDialog

    def enterWaitForSetAvatarResponse(self, choice):
        #self.acceptOnce(self.csm.getSetAvatarEvent(), self.__handleSetAvatarResponse)
        self.sendSetAvatarMsg(choice)

    def enterLoadDone(self):
        self.loginFSM.request("playingGame")

    def __handleSetAvatarResponse(self, avId, di):
        print "Entering game..."
        enterLoad = EnterLoad(self.enterLoadDone)
        dclass = self.dclassesByName['DistributedPlayerToon']
        localAvatar = LocalToon.LocalToon(base.cr)
        localAvatar.dclass = dclass
        base.localAvatar = localAvatar
        __builtins__['localAvatar'] = base.localAvatar
        localAvatar.doId = avId
        self.localAvId = avId
        parentId = None
        zoneId = None
        localAvatar.setLocation(parentId, zoneId)
        localAvatar.generateInit()
        localAvatar.generate()
        dclass.receiveUpdateBroadcastRequiredOwner(localAvatar, di)
        localAvatar.announceGenerate()
        localAvatar.postGenerateMessage()
        self.doId2do[avId] = localAvatar

        # TEMPORARY:
        #localAvatar.hoodsDiscovered = [1000, 2000, 3000, 4000, 5000, 9000]
        #localAvatar.teleportAccess = [1000, 2000, 3000, 4000, 5000, 9000]

        enterLoad.load()
        del enterLoad

    def exitWaitForSetAvatarResponse(self):
        self.ignore(self.csm.getSetAvatarEvent())

    def enterWaitForGameEnterResponse(self, status, shardId):
        if shardId is not None:
            district = self.activeDistricts[shardId]
        else:
            district = None
        if not district:
            self.loginFSM.request('noShards')
            return
        else:
            self.myDistrict = district
        self.notify.info("Entering shard %s" % shardId)
        localAvatar.setLocation(shardId, status['zoneId'])
        localAvatar.defaultShard = shardId
        self.handleEnteredShard(status)
        return

    def handleEnteredShard(self, status):
        self.uberZoneInterest = self.addInterest(localAvatar.defaultShard,
                                                 ZoneUtil.UberZone, 'uberZone',
                                                 'uberZoneInterestComplete')
        self.acceptOnce('uberZoneInterestComplete',
                        self.uberZoneInterestComplete, [status])

    def uberZoneInterestComplete(self, status):
        self.__gotTimeSync = 0
        if self.timeManager is None:
            print "No time manager"
            DistributedSmoothNode.globalActivateSmoothing(0, 0)
            self.gotTimeSync(status)
        else:
            print "Time manager found"
            DistributedSmoothNode.globalActivateSmoothing(1, 0)
            #h = HashVal()
            #hashPrcVariables(h)
            #pyc = HashVal()
            #if not __dev__:
            #	self.hashFiles(pyc)
            #self.timeManager.d_setSignature(self.userSignature, h.asBin(), pyc.asBin())
            #self.timeManager.sendCpuInfo()

            self.timeManager.lastAttempt = -self.timeManager.minWait * 2
            if self.timeManager.synchronize('startup'):
                self.accept('gotTimeSync', self.gotTimeSync, [status])
            else:
                self.gotTimeSync(status)
        return

    def getPing(self):
        if self.myDistrict:
            return self.myDistrict.currentPing
        return 0

    def exitWaitForGameEnterResponse(self):
        self.ignore('uberZoneInterestComplete')
        return

    def gotTimeSync(self, status):
        self.notify.info('gotTimeSync')
        self.ignore('gotTimeSync')
        self.__gotTimeSync = 1
        self.prepareToEnter(status)

    def prepareToEnter(self, status):
        if not self.__gotTimeSync:
            self.notify.info("still waiting for time sync")
            return
        self.gameFSM.request('playGame', [status])

    def enterMakeAToon(self, slot):
        base.stopMusic()
        self.makeAToon.setSlot(slot)
        self.makeAToon.loadEnviron()
        self.makeAToon.load()
        self.makeAToon.matFSM.request('genderShop')
        self.acceptOnce("quitCreateAToon", self.__handleMakeAToonQuit)
        self.acceptOnce("createAToonFinished", self.__handleMakeAToonDone)

    def __handleMakeAToonQuit(self):
        self.loginFSM.request("avChoose")

    def __handleMakeAToonDone(self, dnaStrand, slot, name):
        self.loginFSM.request('submitNewToon',
                              enterArgList=[dnaStrand, slot, name])

    def exitMakeAToon(self):
        self.makeAToon.setSlot(-1)
        self.makeAToon.enterExit(None)
        self.ignore("quitCreateAToon")
        self.ignore("createAToonFinished")

    def enterSubmitNewToon(self, dnaStrand, slot, name, skipTutorial=0):
        self.newToonSlot = slot
        self.submittingDialog = GlobalDialog(message=CIGlobals.Submitting)
        self.submittingDialog.show()
        self.acceptOnce(self.csm.getToonCreatedEvent(),
                        self.__handleSubmitNewToonResp)
        self.csm.sendSubmitNewToon(dnaStrand, slot, name, skipTutorial)

    def __handleSubmitNewToonResp(self, avId):
        # Now that our toon exists in the database, we can add send over the name we wanted to NameServicesManagerUD.
        if self.requestedName is not None:
            self.nameServicesManager.d_requestName(self.requestedName, avId)
            self.requestedName = None

        self.loginFSM.request('avChoose', [self.newToonSlot])

    def exitSubmitNewToon(self):
        self.newToonSlot = None
        self.ignore(self.csm.getToonCreatedEvent())
        self.submittingDialog.cleanup()
        del self.submittingDialog

    def enterGameOff(self):
        pass

    def exitGameOff(self):
        pass

    def enterPlayGame(self, status):
        base.stopMusic()
        base.transitions.noFade()
        if self.localAvChoice is None:
            self.notify.error(
                "called enterPlayGame() without self.localAvChoice being set!")
            return
        if localAvatar.getTutorialCompleted() == 1:
            zoneId = status['zoneId']
            hoodId = status['hoodId']
            avId = status['avId']
            self.playGame.load()
            self.playGame.enter(hoodId, zoneId, avId)
        else:
            self.sendQuietZoneRequest()
            localAvatar.sendUpdate('createTutorial')
        self.myDistrict.d_joining()

    def tutorialCreated(self, zoneId):
        # zoneId = the zone the tutorial resides in
        # tutId = the doId of the tutorial
        requestStatus = {'zoneId': zoneId}
        self.tutQuietZoneState = QuietZoneState('tutQuietZoneDone')
        self.tutQuietZoneState.load()
        self.tutQuietZoneState.enter(requestStatus)
        self.acceptOnce('tutQuietZoneDone', self.__handleTutQuietZoneDone)

    def __handleTutQuietZoneDone(self):
        # We've entered the zone that the tutorial is in.
        self.tutQuietZoneState.exit()
        self.tutQuietZoneState.unload()
        del self.tutQuietZoneState

    def exitPlayGame(self):
        self.ignore('tutQuietZoneDone')
        if hasattr(self, 'tutQuietZoneDone'):
            self.tutQuietZoneState.exit()
            self.tutQuietZoneState.unload()
            del self.tutQuietZoneState
        base.stopMusic()
        self.playGame.exit()
        self.playGame.unload()

    def enterDisconnect(self, isPlaying, booted=0, bootReason=None):
        self.notify.info(
            "Disconnect details: isPlaying = %s, booted = %s, bootReason = %s"
            % (isPlaying, booted, bootReason))
        style = 3
        if isPlaying == 1:
            if not booted:
                msg = CIGlobals.DisconnectionMsg
        else:
            if not booted:
                msg = CIGlobals.JoinFailureMsg
        if self.isConnected():
            self.sendDisconnect()
        self.disconnectDialog = GlobalDialog(message=msg,
                                             style=style,
                                             doneEvent="disconnectDone")
        self.disconnectDialog.show()
        if style == 3:
            self.acceptOnce("disconnectDone", sys.exit)
        else:
            self.acceptOnce("disconnectDone", self.handleDisconnectDone)

    def handleDisconnectDone(self):
        value = self.disconnectDialog.getValue()
        if value:
            self.loginFSM.request('connect')
        else:
            sys.exit()

    def exitDisconnect(self):
        self.ignore("disconnectDone")
        self.disconnectDialog.cleanup()
        del self.disconnectDialog

    def renderFrame(self):
        gsg = base.win.getGsg()
        if gsg:
            render2d.prepareScene(gsg)
        base.graphicsEngine.renderFrame()

    def renderFrames(self):
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()

    def handleDatagram(self, di):
        if self.notify.getDebug():
            print "ClientRepository received datagram:"
            #di.getDatagram().dumpHex(ostream)
        msgType = self.getMsgType()
        self.currentSenderId = None
        if self.handler is None:
            self.astronHandle(di)
        else:
            self.handler(msgType, di)
        self.considerHeartbeat()

    def astronHandle(self, di):
        AstronClientRepository.handleDatagram(self, di)

    def handleQuietZoneGenerateWithRequired(self, di):
        doId = di.getUint32()
        parentId = di.getUint32()
        zoneId = di.getUint32()
        classId = di.getUint16()
        dclass = self.dclassesByNumber[classId]
        if dclass.getClassDef().neverDisable:
            dclass.startGenerate()
            distObj = self.generateWithRequiredFields(dclass, doId, di,
                                                      parentId, zoneId)
            dclass.stopGenerate()

    def handleQuietZoneGenerateWithRequiredOther(self, di):
        doId = di.getUint32()
        parentId = di.getUint32()
        zoneId = di.getUint32()
        classId = di.getUint16()
        dclass = self.dclassesByNumber[classId]
        if dclass.getClassDef().neverDisable:
            dclass.startGenerate()
            distObj = self.generateWithRequiredOtherFields(
                dclass, doId, di, parentId, zoneId)
            dclass.stopGenerate()

    def handleQuietZoneUpdateField(self, di):
        di2 = DatagramIterator(di)
        doId = di2.getUint32()
        if doId in self.deferredDoIds:
            args, deferrable, dg0, updates = self.deferredDoIds[doId]
            dclass = args[2]
            if not dclass.getClassDef().neverDisable:
                return
        else:
            do = self.getDo(doId)
            if do:
                if not do.neverDisable:
                    return
        AstronClientRepository.handleUpdateField(self, di)

    def handleDelete(self, di):
        doId = di.getUint32()
        self.deleteObject(doId)

    def _abandonShard(self):
        for doId, obj in self.doId2do.items():
            if obj.parentId == localAvatar.defaultShard and obj is not localAvatar:
                self.deleteObject(doId)

    def handleEnterObjectRequiredOwner(self, di):
        if self.loginFSM.getCurrentState().getName(
        ) == 'waitForSetAvatarResponse':
            doId = di.getUint32()
            parentId = di.getUint32()
            zoneId = di.getUint32()
            dclassId = di.getUint16()
            self.__handleSetAvatarResponse(doId, di)
        else:
            AstronClientRepository.handleEnterObjectRequiredOwner(self, di)

    def addTaggedInterest(self,
                          parentId,
                          zoneId,
                          mainTag,
                          desc,
                          otherTags=[],
                          event=None):
        return self.addInterest(parentId, zoneId, desc, event)

    def sendSetAvatarMsg(self, choice):
        avId = choice.getAvId()
        self.sendSetAvatarIdMsg(avId)
        self.localAvChoice = choice

    def sendSetAvatarIdMsg(self, avId):
        if avId != self.__currentAvId:
            self.__currentAvId = avId
            self.csm.sendSetAvatar(avId)

    def sendQuietZoneRequest(self):
        self.sendSetZoneMsg(ZoneUtil.QuietZone)
示例#57
0
class ToonFPS(DirectObject):
    notify = directNotify.newCategory('ToonFPS')
    WeaponName2DamageData = {'pistol': (36.0, 10.0, 150.0, 0.25),
     'shotgun': (40.0, 15.0, 155.0, 0.5)}

    def __init__(self, mg, weaponName = 'pistol'):
        self.mg = mg
        self.weaponName = weaponName
        self.v_model_root = None
        self.v_model = None
        self.weapon = None
        self.track = None
        self.draw = None
        self.shoot = None
        self.reload = None
        self.empty = None
        self.cockBack = None
        self.cockFwd = None
        self.player_node = None
        self.shooterTrav = None
        self.shooterRay = None
        self.shooterRayNode = None
        self.shooterHandler = None
        self.gui = ToonFPSGui(self)
        self.fsm = ClassicFSM('ToonFPS', [State('off', self.enterOff, self.exitOff), State('alive', self.enterAlive, self.exitAlive), State('dead', self.enterDead, self.exitDead)], 'off', 'off')
        self.aliveFSM = ClassicFSM('alive', [State('off', self.enterOff, self.exitOff),
         State('draw', self.enterDraw, self.exitDraw, ['idle']),
         State('idle', self.enterIdle, self.exitIdle, ['shoot', 'reload']),
         State('shoot', self.enterShoot, self.exitShoot, ['idle']),
         State('reload', self.enterReload, self.exitReload, ['idle'])], 'off', 'off')
        self.fsm.getStateNamed('alive').addChild(self.aliveFSM)
        self.fsm.enterInitialState()
        self.aliveFSM.enterInitialState()
        if self.weaponName == 'pistol':
            self.ammo = 14
        elif self.weaponName == 'shotgun':
            self.ammo = 7
        self.hp = 125
        self.max_hp = 125
        self.firstPerson = FirstPerson()
        return

    def movementTask(self, task):
        if not inputState.isSet('jump') and not base.localAvatar.walkControls.isAirborne and inputState.isSet('forward') or inputState.isSet('reverse') or inputState.isSet('slideLeft') or inputState.isSet('slideRight'):
            if base.localAvatar.getAnimState() != 'run':
                base.localAvatar.setAnimState('run')
                base.localAvatar.playMovementSfx('run')
                self.mg.sendUpdate('runningAvatar', [base.localAvatar.doId])
        elif inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne:
            if base.localAvatar.getAnimState() != 'jump':
                base.localAvatar.setAnimState('jump')
                base.localAvatar.playMovementSfx(None)
                self.mg.sendUpdate('jumpingAvatar', [base.localAvatar.doId])
        elif base.localAvatar.getAnimState() != 'neutral':
            base.localAvatar.setAnimState('neutral')
            base.localAvatar.playMovementSfx(None)
            self.mg.sendUpdate('standingAvatar', [base.localAvatar.doId])
        return Task.cont

    def enterAlive(self):
        if self.mg.fsm.getCurrentState().getName() not in ('gameOver', 'announceGameOver', 'finalScores'):
            base.localAvatar.disableChatInput()
            self.start()
            self.resetHp()
            self.resetAmmo()
            if self.mg.fsm.getCurrentState().getName() == 'play':
                self.reallyStart()

    def exitAlive(self):
        self.end()
        self.v_model.reparentTo(hidden)
        if self.mg.fsm.getCurrentState().getName() != 'play':
            self.reallyEnd()
        base.localAvatar.createChatInput()

    def updatePoints(self):
        self.points = self.kills - self.deaths

    def enterDead(self, killer):
        base.localAvatar.getGeomNode().show()
        self.gui.end()
        base.localAvatar.attachCamera()
        self.freezeCamSfx = base.loadSfx('phase_4/audio/sfx/freeze_cam.wav')
        self.freezeCamImage = None
        self.freezeCamImageFile = None
        base.camera.setZ(base.camera.getZ() + 2.0)
        taskMgr.add(self.cameraLookAtKillerTask, 'lookAtKiller', extraArgs=[killer], appendTask=True)
        taskMgr.doMethodLater(2.0, self.startZoomOnKiller, 'startFreezeCam', extraArgs=[killer], appendTask=True)
        return

    def startZoomOnKiller(self, killer, task):
        taskMgr.add(self.__zoomOnKillerTask, 'zoomOnKiller', extraArgs=[killer], appendTask=True)
        return task.done

    def __zoomOnKillerTask(self, killer, task):
        if base.camera.getDistance(killer) <= 10.0 and self.freezeCamSfx.status() == self.freezeCamSfx.READY:
            base.playSfx(self.freezeCamSfx)
        if base.camera.getDistance(killer) < 7.0:
            self.doFreezeCam()
            return task.done
        base.camera.setY(base.camera, 60 * globalClock.getDt())
        return task.again

    def doFreezeCam(self):
        taskMgr.remove('lookAtKiller')
        self.frameBuffer = PNMImage()
        base.win.getScreenshot(self.frameBuffer)
        self.freezeCamTex = Texture()
        self.freezeCamTex.load(self.frameBuffer)
        self.freezeCamImage = OnscreenImage(image=self.freezeCamTex, parent=render2d)

    def cameraLookAtKillerTask(self, killer, task):
        base.camera.lookAt(killer, 0, 0, 3)
        return task.cont

    def exitDead(self):
        taskMgr.remove('zoomOnKiller')
        taskMgr.remove('lookAtKiller')
        taskMgr.remove('startFreezeCam')
        del self.freezeCamSfx
        if self.freezeCamImage:
            self.freezeCamImage.destroy()
        del self.freezeCamImage
        self.frameBuffer.clear()
        self.freezeCamTex.clear()
        del self.frameBuffer
        del self.freezeCamTex
        base.localAvatar.detachCamera()
        base.localAvatar.getGeomNode().hide()
        self.gui.start()

    def load(self):
        if self.weaponName == 'pistol':
            self.draw = base.loadSfx('phase_4/audio/sfx/draw_secondary.wav')
            self.shoot = base.loadSfx('phase_4/audio/sfx/pistol_shoot.wav')
            self.reload = base.loadSfx('phase_4/audio/sfx/pistol_worldreload.wav')
        elif self.weaponName == 'shotgun':
            self.draw = base.loadSfx('phase_4/audio/sfx/draw_primary.wav')
            self.shoot = base.loadSfx('phase_4/audio/sfx/shotgun_shoot.wav')
            self.cockBack = base.loadSfx('phase_4/audio/sfx/shotgun_cock_back.wav')
            self.cockFwd = base.loadSfx('phase_4/audio/sfx/shotgun_cock_forward.wav')
        self.empty = base.loadSfx('phase_4/audio/sfx/shotgun_empty.wav')
        self.v_model_root = base.camera.attachNewNode('v_model_root')
        self.v_model = Actor('phase_4/models/minigames/v_dgm.egg', {'pidle': 'phase_4/models/minigames/v_dgm-pistol-idle.egg',
         'pshoot': 'phase_4/models/minigames/v_dgm-pistol-shoot.egg',
         'preload': 'phase_4/models/minigames/v_dgm-pistol-reload.egg',
         'pdraw': 'phase_4/models/minigames/v_dgm-pistol-draw.egg',
         'sidle': 'phase_4/models/minigames/v_dgm-shotgun-idle.egg',
         'sshoot': 'phase_4/models/minigames/v_dgm-shotgun-shoot.egg'})
        if self.weaponName == 'pistol':
            self.weapon = loader.loadModel('phase_4/models/props/water-gun.bam')
            self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.011'))
            self.weapon.setX(-0.125)
            self.weapon.setY(0.5)
            self.weapon.setScale(0.65)
        elif self.weaponName == 'shotgun':
            self.weapon = loader.loadModel('phase_4/models/props/shotgun.egg')
            self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.029'))
            self.weapon.setScale(0.75)
            self.weapon.setPos(0.45, -1.03, -1.17)
            self.weapon.setHpr(9.46, 308.19, 75.78)
            color = random.choice([VBase4(1, 0.25, 0.25, 1), VBase4(0.25, 1, 0.25, 1), VBase4(0.25, 0.25, 1, 1)])
            self.weapon.setColorScale(color)
        self.gui.load()
        return

    def start(self):
        base.camLens.setNear(0.1)
        self.shooterTrav = CollisionTraverser('ToonFPS.shooterTrav')
        ray = CollisionRay()
        rayNode = CollisionNode('ToonFPS.rayNode')
        rayNode.addSolid(ray)
        rayNode.setCollideMask(BitMask32(0))
        rayNode.setFromCollideMask(CIGlobals.WallBitmask | CIGlobals.FloorBitmask)
        self.shooterRay = ray
        self.shooterRayNode = base.camera.attachNewNode(rayNode)
        self.shooterHandler = CollisionHandlerQueue()
        self.shooterTrav.addCollider(self.shooterRayNode, self.shooterHandler)
        self.firstPerson.start()
        self.v_model_root.reparentTo(base.camera)
        self.v_model.reparentTo(self.v_model_root)
        if self.weaponName == 'pistol':
            self.v_model_root.setZ(-1.8)
            self.v_model_root.setY(0.3)
            self.v_model_root.setX(-0.1)
            self.v_model_root.setH(2)
        elif self.weaponName == 'shotgun':
            self.v_model_root.setPos(-0.42, -0.81, -1.7)
            self.v_model_root.setHpr(359, 352.87, 0.0)
        self.gui.start()
        self.firstPerson.disableMouse()
        self.aliveFSM.request('draw')

    def reallyStart(self):
        self.firstPerson.reallyStart()
        taskMgr.add(self.movementTask, 'toonBattleMovement')

    def end(self):
        self.aliveFSM.request('off')
        if self.firstPerson:
            self.firstPerson.enableMouse()
            self.firstPerson.end()
        taskMgr.remove('toonBattleMovement')
        if self.mg.fsm.getCurrentState().getName() != 'play':
            self.fsm.request('off')

    def reallyEnd(self):
        if self.shooterRayNode:
            self.shooterRayNode.removeNode()
            self.shooterRayNode = None
        self.shooterRay = None
        self.shooterTrav = None
        self.shooterHandler = None
        if self.firstPerson:
            self.firstPerson.reallyEnd()
        if self.v_model_root:
            self.v_model_root.reparentTo(hidden)
        if self.v_model:
            self.v_model.reparentTo(hidden)
            self.v_model.setPosHpr(0, 0, 0, 0, 0, 0)
        if self.gui:
            self.gui.end()
        base.camLens.setNear(1.0)
        return

    def cleanup(self):
        taskMgr.remove('lookAtKiller')
        taskMgr.remove('toonBattleMovement')
        if self.firstPerson:
            self.firstPerson.cleanup()
            self.firstPerson = None
        self.draw = None
        self.shoot = None
        self.reload = None
        self.empty = None
        self.ammo = None
        self.fsm = None
        self.aliveFSM = None
        self.player_node = None
        self.min_camerap = None
        self.max_camerap = None
        self.hp = None
        self.max_hp = None
        if self.v_model:
            self.v_model.cleanup()
            self.v_model = None
        if self.weapon:
            self.weapon.removeNode()
            self.weapon = None
        if self.weapon:
            self.v_model_root.removeNode()
            self.v_model_root = None
        if self.gui:
            self.gui.cleanup()
        return

    def damageTaken(self, amount, avId):
        if self.hp <= 0.0:
            killer = self.mg.cr.doId2do.get(avId, None)
            self.fsm.request('dead', [killer])
        self.gui.adjustHpMeter()
        return

    def enterDraw(self):
        self.draw.play()
        if self.weaponName == 'pistol':
            self.track = ActorInterval(self.v_model, 'pdraw', playRate=1.6, name='drawTrack')
        elif self.weaponName == 'shotgun':
            self.v_model.pose('sidle', 15)
            self.track = LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut', name='drawTrack')
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle'])
        self.track.start()

    def exitDraw(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        return

    def enterIdle(self):
        if self.weaponName == 'pistol':
            self.v_model.loop('pidle')
        elif self.weaponName == 'shotgun':
            self.track = Sequence(LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 1, 0), startHpr=(0, 0, 0), blendType='easeInOut'), LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 0, 0), startHpr=(0, 1, 0), blendType='easeInOut'))
            self.track.loop()
        self.accept('mouse1', self.requestShoot)
        if self.ammo <= 0:
            self.gui.notifyNoAmmo()
        if self.ammo < 14:
            self.accept('r', self.aliveFSM.request, ['reload'])

    def requestShoot(self):
        if self.mg.fsm.getCurrentState().getName() != 'play':
            return
        if self.ammo > 0:
            self.aliveFSM.request('shoot')
        else:
            self.empty.play()

    def exitIdle(self):
        self.v_model.stop()
        if self.track:
            self.track.finish()
            self.track = None
        self.ignore('mouse1')
        self.ignore('r')
        return

    def enterShoot(self):
        self.shoot.play()
        if self.weaponName == 'pistol':
            self.track = ActorInterval(self.v_model, 'pshoot', playRate=2, name='shootTrack')
        elif self.weaponName == 'shotgun':
            self.track = Parallel(Sequence(LerpQuatInterval(self.v_model, duration=0.05, quat=(0, 3, 0), startHpr=(0, 0, 0)), LerpQuatInterval(self.v_model, duration=0.1, quat=(0, 0, 0), startHpr=(0, 3, 0))), Sequence(LerpPosInterval(self.v_model, duration=0.05, pos=(0, -0.3, 0), startPos=(0, 0, 0)), LerpPosInterval(self.v_model, duration=0.1, pos=(0, 0, 0), startPos=(0, -0.3, 0)), Wait(0.1)))
        self.track.setDoneEvent('shootTrack')
        self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle'])
        self.track.start()
        self.ammo -= 1
        self.gui.adjustAmmoGui()
        self.mg.makeSmokeEffect(self.weapon.find('**/joint_nozzle').getPos(render))
        self.traverse()

    def traverse(self):
        mpos = base.mouseWatcherNode.getMouse()
        self.shooterRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
        self.shooterTrav.traverse(render)

    def calcDamage(self, avatar):
        dmgData = self.WeaponName2DamageData[self.weaponName]
        maxDamage = dmgData[0]
        minDistance = dmgData[1]
        maxDistance = dmgData[2]
        factor = dmgData[3]
        distance = base.localAvatar.getDistance(avatar)
        if distance < minDistance:
            distance = minDistance
        elif distance > maxDistance:
            distance = maxDistance
        damage = maxDamage - (distance - minDistance) * factor
        return damage

    def exitShoot(self):
        self.ignore('shootTrack')
        if self.track:
            self.track.finish()
            self.track = None
        return

    def enterReload(self):
        self.gui.deleteNoAmmoLabel()
        if self.weaponName == 'pistol':
            self.track = Parallel(Sequence(Wait(0.3), Func(self.reload.play), Func(self.resetAmmo)), ActorInterval(self.v_model, 'preload', playRate=1.5), name='reloadTrack')
        elif self.weaponName == 'shotgun':
            self.track = Sequence(Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(70, -50, 0), startHpr=(0, 0, 0), blendType='easeIn'), SoundInterval(self.cockBack), SoundInterval(self.cockFwd), Func(self.resetAmmo), Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut'), name='reloadTrack')
        self.track.setDoneEvent('reloadTrack')
        self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle'])
        self.track.start()

    def exitReload(self):
        self.ignore('reloadTrack')
        if self.track:
            self.track.finish()
            self.track = None
        return

    def resetAmmo(self):
        if self.weaponName == 'pistol':
            self.ammo = 14
        elif self.weaponName == 'shotgun':
            self.ammo = 7
        self.gui.resetAmmo()

    def resetHp(self):
        self.hp = self.max_hp
        self.gui.adjustHpMeter()

    def enterOff(self):
        pass

    def exitOff(self):
        pass
示例#58
0
class DistributedDoor(DistributedObject.DistributedObject):
    notify = directNotify.newCategory("DistributedDoor")
    notify.setInfo(True)
    INT_STANDARD = 0
    EXT_STANDARD = 1
    INT_HQ = 2
    EXT_HQ = 3
    EXT_GAGSHOP = 4
    
    LIT_INTERIOR_COLOR = Vec4(1.0, 236.0 / 255.0, 142.0 / 255.0, 1.0)

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.rightFSM = ClassicFSM(
            'DistributedDoor_right',
            [
                State('off', self.enterOff, self.exitOff),
                State('closed', self.enterRightDoorClosed, self.exitRightDoorClosed, ['opening']),
                State('opening', self.enterRightDoorOpening, self.exitRightDoorOpening, ['open']),
                State('open', self.enterRightDoorOpen, self.exitRightDoorOpen, ['closing']),
                State('closing', self.enterRightDoorClosing, self.exitRightDoorClosing, ['closed'])
            ],
            'off', 'off'
        )
        self.rightFSM.enterInitialState()
        self.leftFSM = ClassicFSM(
            'DistributedDoor_left',
            [
                State('off', self.enterOff, self.exitOff),
                State('closed', self.enterLeftDoorClosed, self.exitLeftDoorClosed, ['opening']),
                State('opening', self.enterLeftDoorOpening, self.exitLeftDoorOpening, ['open']),
                State('open', self.enterLeftDoorOpen, self.exitLeftDoorOpen, ['closing']),
                State('closing', self.enterLeftDoorClosing, self.exitLeftDoorClosing, ['closed'])
            ],
            'off', 'off'
        )
        self.leftFSM.enterInitialState()
        self.avatarTracks = []
        self.leftDoorState = ''
        self.rightDoorState = ''
        self.toZone = 0
        self.block = 0
        self.doorType = 0
        self.doorIndex = 0
        self.leftTrack = None
        self.rightTrack = None
        self.building = None
        self.doorNode = None
        self.leftDoor = None
        self.rightDoor = None
        self.doorOpenSound = None
        self.doorShutSound = None
        self.enterDoorWalkBackNode = None
        self.enterDoorWalkInNode = None
        self.exitDoorWalkFromNode = None
        self.exitDoorWalkToNode = None
        self.ready = False
        self.nodeProblemPolled = False
        self.suitTakingOver = 0

    def setSuitTakingOver(self, flag):
        self.suitTakingOver = flag

    def getSuitTakingOver(self):
        return self.suitTakingOver

    def setDoorIndex(self, index):
        self.doorIndex = index

    def getDoorIndex(self):
        return self.doorIndex

    def getLeftDoorOpenH(self):
        num = 0
        if self.getDoorType() == self.INT_STANDARD or self.getDoorType() == self.INT_HQ:
            num =  70
        elif self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_HQ:
            num = -110
        if (self.getDoorIndex() == 1 and not self.doorType == self.EXT_HQ or
        self.getDoorIndex() == 0 and self.doorType in [self.EXT_HQ, self.EXT_GAGSHOP]):
            return num - 180
        else:
            return num

    def getLeftDoorClosedH(self):
        num = 0
        if self.getDoorType() == self.INT_STANDARD or self.getDoorType() == self.INT_HQ:
            num = 180
        elif self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_HQ:
            num = 0
        if (self.getDoorIndex() == 1 and not self.doorType == self.EXT_HQ or
        self.getDoorIndex() == 0 and self.doorType in [self.EXT_HQ, self.EXT_GAGSHOP]):
            return num - 180
        else:
            return num

    def getRightDoorOpenH(self):
        num = 0
        if self.getDoorType() == self.INT_STANDARD or self.getDoorType() == self.INT_HQ:
            num = -70
        elif self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_HQ or self.getDoorType() == self.EXT_GAGSHOP:
            num = 110
        if (self.getDoorIndex() == 1 and not self.doorType == self.EXT_HQ or
        self.getDoorIndex() == 0 and self.doorType in [self.EXT_HQ, self.EXT_GAGSHOP]):
            return num - 180
        else:
            return num

    def getRightDoorClosedH(self):
        num = 0
        if self.getDoorType() == self.INT_STANDARD or self.getDoorType() == self.INT_HQ:
            num = 180
        elif self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_HQ or self.getDoorType() == self.EXT_GAGSHOP:
            num = 0
        if (self.getDoorIndex() == 1 and not self.doorType == self.EXT_HQ or
        self.getDoorIndex() == 0 and self.doorType in [self.EXT_HQ, self.EXT_GAGSHOP]):
            return num - 180
        else:
            return num

    def enterOff(self, ts = 0):
        pass

    def exitOff(self):
        pass

    def enterRightDoorClosed(self, ts = 0):
        self.rightDoor.setH(self.getRightDoorClosedH())
        self.toggleDoorHole('Right', show = False)

    def exitRightDoorClosed(self):
        pass

    def enterRightDoorOpen(self, ts = 0):
        self.rightDoor.setH(self.getRightDoorOpenH())

    def exitRightDoorOpen(self):
        pass

    def enterRightDoorClosing(self, ts = 0):
        if self.rightTrack:
            self.rightTrack.finish()
            self.rightTrack = None
        self.rightTrack = Sequence(LerpQuatInterval(self.rightDoor, duration = 1.0, quat = (self.getRightDoorClosedH(), 0, 0),
            startHpr = (self.getRightDoorOpenH(), 0, 0), blendType = 'easeIn'),
            Func(base.playSfx, self.doorShutSound, 0, 1, None, 0.0, self.rightDoor))
        self.rightTrack.start()

    def exitRightDoorClosing(self):
        if self.rightTrack:
            self.rightTrack.finish()
            self.rightTrack = None

    def enterRightDoorOpening(self, ts = 0):
        self.toggleDoorHole('Right', show = True)
        self.rightDoor.show()
        if self.rightTrack:
            self.rightTrack.finish()
            self.rightTrack = None
        self.rightTrack = Sequence(Wait(0.5), Parallel(LerpQuatInterval(self.rightDoor, duration = 0.7, quat = (self.getRightDoorOpenH(), 0, 0),
            startHpr = (self.getRightDoorClosedH(), 0, 0), blendType = 'easeInOut'), SoundInterval(self.doorOpenSound, node = self.rightDoor)))
        self.rightTrack.start()

    def exitRightDoorOpening(self):
        if self.rightTrack:
            self.rightTrack.finish()
            self.rightTrack = None

    def enterLeftDoorClosed(self, ts = 0):
        self.leftDoor.setH(self.getLeftDoorClosedH())
        self.toggleDoorHole('Left', show = False)

    def exitLeftDoorClosed(self):
        pass

    def enterLeftDoorOpen(self, ts = 0):
        self.leftDoor.setH(self.getLeftDoorOpenH())

    def exitLeftDoorOpen(self):
        pass

    def enterLeftDoorClosing(self, ts = 0):
        if self.leftTrack:
            self.leftTrack.finish()
            self.leftTrack = None
        self.leftTrack = Sequence(LerpQuatInterval(
            self.leftDoor, duration = 1.0, quat = (self.getLeftDoorClosedH(), 0, 0),
            startHpr = (self.getLeftDoorOpenH(), 0, 0), blendType = 'easeIn'),
            Func(base.playSfx, self.doorShutSound, 0, 1, None, 0.0, self.leftDoor))
        self.leftTrack.start()

    def exitLeftDoorClosing(self):
        if self.leftTrack:
            self.leftTrack.finish()
            self.leftTrack = None

    def enterLeftDoorOpening(self, ts = 0):
        self.toggleDoorHole('Left', show = True)
        self.leftDoor.show()
        if self.leftTrack:
            self.leftTrack.finish()
            self.leftTrack = None
        self.leftTrack = Sequence(Wait(0.5), Parallel(LerpQuatInterval(self.leftDoor, duration = 0.7, quat = (self.getLeftDoorOpenH(), 0, 0),
            startHpr = (self.getLeftDoorClosedH(), 0, 0), blendType = 'easeInOut'), SoundInterval(self.doorOpenSound, node = self.leftDoor)))
        self.leftTrack.start()

    def exitLeftDoorOpening(self):
        if self.leftTrack:
            self.leftTrack.finish()
            self.leftTrack = None

    def setDoorType(self, door):
        self.doorType = door

    def getDoorType(self):
        return self.doorType

    def setBlock(self, block):
        self.block = block

    def getBlock(self):
        return self.block

    def setToZone(self, zone):
        self.toZone = zone

    def getToZone(self):
        return self.toZone

    def setLeftDoorState(self, state, timestamp):
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.leftDoorState = state
        if self.building:
            self.leftFSM.request(state, [ts])

    def getLeftDoorState(self):
        return self.leftDoorState

    def setRightDoorState(self, state, timestamp):
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        self.rightDoorState = state
        if self.building:
            self.rightFSM.request(state, [ts])

    def getRightDoorState(self):
        return self.rightDoorState

    def findBuilding(self):
        bldg = None
        if self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_HQ or self.getDoorType() == self.EXT_GAGSHOP:
            bldg = self.cr.playGame.hood.loader.geom.find('**/??' + str(self.getBlock()) + ':*_landmark_*_DNARoot;+s')
        elif self.getDoorType() == self.INT_STANDARD:
            bldg = render.find('**/leftDoor;+s').getParent()
        elif self.getDoorType() == self.INT_HQ:
            bldg = render.find('**/door_origin_0').getParent()
        return bldg

    def findDoorNodePath(self):
        doorNode = None
        if self.getDoorType() in [self.EXT_STANDARD, self.EXT_GAGSHOP]:
            doorNode = self.building.find('**/*door_origin')
        elif self.getDoorType() == self.EXT_HQ:
            doorNode = self.building.find('**/door_origin_' + str(self.doorIndex))
        elif self.getDoorType() == self.INT_STANDARD:
            doorNode = render.find('**/door_origin')
        elif self.getDoorType() == self.INT_HQ:
            doorNode = render.find('**/door_origin_' + str(self.doorIndex))
        return doorNode

    def findDoorNode(self, string):
        if self.doorType != self.INT_HQ:
            foundNode = self.building.find('**/door_' + str(self.getDoorIndex()) + '/**/' + string + '*;+s+i')
            
            if foundNode.isEmpty():
                foundNode = self.building.find('**/' + string + '*;+s+i')

        else:
            foundNode = render.find('**/door_' + str(self.getDoorIndex()) + '/**/' + string + '*;+s+i')
            if foundNode.isEmpty():
                foundNode = render.find('**/' + string + '*;+s+i')

        return foundNode

    def getTriggerName(self):
        if self.getDoorType() == self.INT_STANDARD or self.getDoorType() == self.EXT_STANDARD or self.getDoorType() == self.EXT_GAGSHOP:
            return 'door_trigger_' + str(self.getBlock())
        elif self.getDoorType() == self.INT_HQ or self.getDoorType() == self.EXT_HQ:
            return 'door_trigger_' + str(self.block) + '0' + str(self.doorIndex)

    def getEnterTriggerEvent(self):
        return 'enter' + self.getTriggerName()

    def getExitTriggerEvent(self):
        return 'exit' + self.getTriggerName()

    def __pollBuilding(self, task):
        try:
            self.building = self.findBuilding()
        except:
            return task.cont
        if self.building.isEmpty():
            return task.cont
        self.generated()
        return task.done

    def _handleTrigger(self, ghostNode):
        if not self.getSuitTakingOver():
            self.cr.playGame.getPlace().fsm.request('stop')
            base.localAvatar.walkControls.setCollisionsActive(0)
            self.sendUpdate('requestEnter', [])

    def getAvatarEnterTrack(self, av):
        track = Sequence(name = av.uniqueName('avatarEnterDoorTrack'))
        track.append(Func(av.setAnimState, 'walkBack'))
        track.append(
            ParallelEndTogether(
                LerpPosInterval(
                    av,
                    duration = 0.5,
                    blendType = 'easeInOut',
                    pos = self.enterWalkBackPos,
                    startPos = av.getPos(render)
                ),
                LerpQuatInterval(
                    av,
                    duration = 0.5,
                    hpr = self.doorNode.getHpr(render),
                    startHpr = av.getHpr(render)
                )
            )
        )
        track.append(Func(av.setPlayRate, 1.0, 'walk'))
        track.append(Func(av.loop, 'neutral'))
        track.append(Wait(1.0))
        track.append(Func(av.loop, 'walk'))
        parallel = Parallel()
        parallel.append(
            LerpPosInterval(
                av,
                duration = 1.0,
                blendType = 'easeInOut',
                pos = self.enterWalkInPos,
                startPos = self.enterWalkBackPos
            )
        )
        if base.localAvatar.doId == av.doId:
            parallel.append(LerpPosHprInterval(nodePath = camera, other = av, duration = 1.0,
                                               pos = (0, -8, av.getHeight()), hpr = (0, 0, 0),
                                               blendType = 'easeInOut'))
            parallel.append(Sequence(Wait(0.5), Func(self.sendGoingIn), Wait(1.0)))
        track.append(parallel)
        if base.localAvatar.doId == av.doId:
            track.append(Func(self.sendWentInDoor))
        track.setDoneEvent(track.getName())
        track.delayDelete = DelayDelete.DelayDelete(av, track.getName())
        self.acceptOnce(track.getDoneEvent(), self.__avatarTrackDone, [track])
        return track

    def sendGoingIn(self):
        messenger.send('DistributedDoor_localAvatarGoingInDoor')
        
    def sendWentInDoor(self):
        messenger.send('DistributedDoor_localAvatarWentInDoor')

    def getAvatarExitTrack(self, av):
        track = Sequence(name = av.uniqueName('avatarExitDoorTrack'))
        track.append(Wait(1.3))
        track.append(Func(av.setAnimState, 'walk'))
        av.setPos(self.exitWalkFromPos)
        av.headsUp(self.exitWalkToPos)
        track.append(
            LerpPosInterval(
                av,
                duration = 1.2,
                blendType = 'easeInOut',
                pos = self.exitWalkToPos,
                startPos = av.getPos(render)
            )
        )
        track.append(Func(av.loop, 'neutral'))
        if base.localAvatar.doId == av.doId:
            track.append(Func(messenger.send, 'DistributedDoor_localAvatarCameOutOfDoor'))
        else:
            track.append(Func(av.startSmooth))
        track.setDoneEvent(track.getName())
        track.delayDelete = DelayDelete.DelayDelete(av, track.getName())
        self.acceptOnce(track.getDoneEvent(), self.__avatarTrackDone, [track])
        return track

    def __avatarTrackDone(self, track):
        if track:
            DelayDelete.cleanupDelayDeletes(track)
            if self.avatarTracks:
                self.avatarTracks.remove(track)

    def enterDoor(self, avatarId, timestamp):
        if not self.building:
            return
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        if avatarId == base.localAvatar.doId:
            self.cr.playGame.getPlace().fsm.request('doorIn', [self])
        av = self.cr.doId2do.get(avatarId)
        if av:
            av.stopSmooth()
            track = self.getAvatarEnterTrack(av)
            self.avatarTracks.append(track)
            track.start()

    def exitDoor(self, avatarId, timestamp):
        if not self.building:
            return
        ts = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
        av = self.cr.doId2do.get(avatarId)
        if av:
            if av.doId != base.localAvatar.doId:
                av.stopSmooth()
            track = self.getAvatarExitTrack(av)
            self.avatarTracks.append(track)
            track.start()

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        try:
            self.building = self.findBuilding()
            self.generated()
        except:
            self.startBuildingPoll()
            return
        if self.building.isEmpty():
            self.startBuildingPoll()
            return

    def startBuildingPoll(self):
        base.taskMgr.add(self.__pollBuilding, self.uniqueName('pollBuilding'))

    def fixHQTrigger(self):
        trig = self.building.find('**/door_' + str(self.doorIndex) + '/**/door_trigger*')
        if not trig.isEmpty():
            trig.node().setName(self.getTriggerName())

    def generated(self):
        self.doorNode = self.findDoorNodePath()
        self.rightDoor = self.findDoorNode('rightDoor')
        self.leftDoor = self.findDoorNode('leftDoor')
        self.toggleDoorHole('Right', show = False)
        self.toggleDoorHole('Left', show = False)
        
        self.enterWalkBackPos = render.getRelativePoint(self.doorNode, Point3(1.6, -5.5, 0.0))
        self.enterWalkInPos = render.getRelativePoint(self.doorNode, Point3(1.6, 3.0, 0.0))
        self.exitWalkFromPos = render.getRelativePoint(self.doorNode, Point3(-1.6, 3.0, 0.0))
        self.exitWalkToPos = render.getRelativePoint(self.doorNode, Point3(-1.6, -5.5, 0.0))

        self.doorOpenSound = base.audio3d.loadSfx('phase_3.5/audio/sfx/Door_Open_1.ogg')
        self.doorShutSound = base.audio3d.loadSfx('phase_3.5/audio/sfx/Door_Close_1.ogg')
        base.audio3d.attachSoundToObject(self.doorOpenSound, self.doorNode)
        base.audio3d.attachSoundToObject(self.doorShutSound, self.doorNode)

        if self.doorType == self.EXT_HQ:
            self.fixHQTrigger()

        self.acceptOnce(self.getEnterTriggerEvent(), self._handleTrigger)

        self.ready = True

    def toggleDoorHole(self, side, show = False):
        side = side.title()
        if self.building:
            isDDL = self.cr.playGame.hood.id == DonaldsDreamland
            isExt = self.getDoorType() in [self.EXT_GAGSHOP, self.EXT_HQ, self.EXT_STANDARD]
            holeColor = self.LIT_INTERIOR_COLOR if (isExt and isDDL) else (0.0, 0.0, 0.0, 1.0)
            
            if self.getDoorType() == self.EXT_HQ:
                hole = self.building.find('**/doorFrameHole%s_%d' % (side, self.doorIndex))
                geom = self.building.find('**/doorFrameHole%sGeom_%d' % (side, self.doorIndex))
                
                if not hole or hole.isEmpty():
                    doorFlats = self.building.findAllMatches('**/door_fla*;+s+i')
                    
                    for doorFlat in doorFlats:
                        if not doorFlat.isEmpty() and int(doorFlat.getName()[len(doorFlat.getName()) - 1]) == self.doorIndex:
                            # Let's reset the material to the default white.
                            doorFlat.setBSPMaterial('phase_14/materials/white.mat', 1)

                            # This is a hacky way to make sure the flat part is behind the door.
                            # This took me like 2 hours to figure out this workaround. Don't question it
                            # with some stupid #setPos() trash, depth write/depth test, or any of that. This works.
                            doorFlat.setSy(0.995)

                            hole = doorFlat
                            break

            elif self.getDoorType() == self.INT_HQ:
                hole = render.find('**/door_' + str(self.doorIndex) + '/**/doorFrameHole%s;+s+i' % side)
                geom = render.find('**/door_' + str(self.doorIndex) + '/**/doorFrameHole%sGeom;+s+i' % side)
            else:
                hole = self.building.find('**/doorFrameHole%s' % side)
                geom = self.building.find('**/doorFrameHole%sGeom' % side)
                
            nodes = [hole, geom]
            
            for node in nodes:
                if node and not node.isEmpty():
                    if show:
                        node.show()
                    else:
                        node.hide()

                    node.setColor(holeColor, 1)

    def printBuildingPos(self):
        self.notify.info(self.building.getPos(render))

    def disable(self):
        self.ignore(self.getEnterTriggerEvent())
        base.taskMgr.remove(self.uniqueName('pollBuilding'))
        for track in self.avatarTracks:
            track.finish()
        self.avatarTracks = None
        self.building = None
        self.doorNode = None
        self.rightDoor = None
        self.leftDoor = None
        self.ready = None
        self.toZone = None
        if self.leftTrack:
            self.leftTrack.finish()
            self.leftTrack = None
        if self.rightTrack:
            self.rightTrack.finish()
            self.rightTrack = None
        if self.enterDoorWalkBackNode:
            self.enterDoorWalkBackNode.removeNode()
            self.enterDoorWalkBackNode = None
        if self.enterDoorWalkInNode:
            self.enterDoorWalkInNode.removeNode()
            self.enterDoorWalkInNode = None
        if self.exitDoorWalkFromNode:
            self.exitDoorWalkFromNode.removeNode()
            self.exitDoorWalkFromNode = None
        if self.exitDoorWalkToNode:
            self.exitDoorWalkToNode.removeNode()
            self.exitDoorWalkToNode = None
        self.doorOpenSound = None
        self.doorShutSound = None

        self.leftDoorState = None
        self.rightDoorState = None
        self.block = None
        self.doorType = None
        self.doorIndex = None
        self.nodeProblemPolled = None
        self.suitTakingOver = None

        DistributedObject.DistributedObject.disable(self)
示例#59
0
class Char(Avatar.Avatar):

    def __init__(self):
        try:
            self.Char_initialized
            return
        except:
            self.Char_initialized = 1

        Avatar.Avatar.__init__(self)
        self.avatarType = CIGlobals.CChar
        self.avatarName = None
        self.currentAnim = None
        self.charType = ''
        self.eyes = loader.loadTexture('phase_3/maps/eyes1.jpg', 'phase_3/maps/eyes1_a.rgb')
        self.closedEyes = loader.loadTexture('phase_3/maps/mickey_eyes_closed.jpg', 'phase_3/maps/mickey_eyes_closed_a.rgb')
        self.animFSM = ClassicFSM('Char', [State('off', self.enterOff, self.exitOff),
         State('neutral', self.enterNeutral, self.exitNeutral),
         State('walk', self.enterWalk, self.exitWalk),
         State('run', self.enterRun, self.exitRun)], 'off', 'off')
        animStateList = self.animFSM.getStates()
        self.animFSM.enterInitialState()
        Avatar.Avatar.initializeBodyCollisions(self, self.avatarType, 3.5, 1)
        return

    def getNametagJoints(self):
        return []

    def stopAnimations(self):
        if hasattr(self, 'animFSM'):
            if not self.animFSM.isInternalStateInFlux():
                self.animFSM.request('off')
            else:
                notify.warning('animFSM in flux, state=%s, not requesting off' % self.animFSM.getCurrentState().getName())
        else:
            notify.warning('animFSM has been deleted')

    def disable(self):
        self.stopBlink()
        self.stopAnimations()
        Avatar.Avatar.disable(self)

    def delete(self):
        try:
            self.Char_deleted
        except:
            self.Char_deleted = 1
            del self.animFSM
            Avatar.Avatar.delete(self)

    def setChat(self, chatString):
        if self.charType == CIGlobals.Mickey:
            self.dial = base.audio3d.loadSfx('phase_3/audio/dial/mickey.ogg')
        else:
            if self.charType == CIGlobals.Minnie:
                self.dial = base.audio3d.loadSfx('phase_3/audio/dial/minnie.ogg')
            else:
                if self.charType == CIGlobals.Goofy:
                    self.dial = base.audio3d.loadSfx('phase_6/audio/dial/goofy.ogg')
        base.audio3d.attachSoundToObject(self.dial, self)
        self.dial.play()
        Avatar.Avatar.setChat(self, chatString)

    def setName(self, nameString, charName=None):
        self.avatarName = nameString
        Avatar.Avatar.setName(self, nameString, avatarType=self.avatarType, charName=charName)

    def setupNameTag(self, tempName=None):
        Avatar.Avatar.setupNameTag(self, tempName)
        self.nametag.setNametagColor(NametagGlobals.NametagColors[NametagGlobals.CCNPC])
        self.nametag.setActive(0)
        self.nametag.updateAll()

    def generateChar(self, charType):
        self.charType = charType
        if charType == CIGlobals.Mickey or charType == CIGlobals.Minnie:
            self.loadModel('phase_3/models/char/' + charType.lower() + '-' + str(CIGlobals.ModelDetail(self.avatarType)) + '.bam')
            self.loadAnims({'neutral': 'phase_3/models/char/' + charType.lower() + '-wait.bam', 'walk': 'phase_3/models/char/' + charType.lower() + '-walk.bam', 
               'run': 'phase_3/models/char/' + charType.lower() + '-run.bam', 
               'left-start': 'phase_3.5/models/char/' + charType.lower() + '-left-start.bam', 
               'left': 'phase_3.5/models/char/' + charType.lower() + '-left.bam', 
               'right-start': 'phase_3.5/models/char/' + charType.lower() + '-right-start.bam', 
               'right': 'phase_3.5/models/char/' + charType.lower() + '-right.bam'})
            if charType == CIGlobals.Mickey:
                self.mickeyEye = self.controlJoint(None, 'modelRoot', 'joint_pupilR')
                self.mickeyEye.setY(0.025)
            for bundle in self.getPartBundleDict().values():
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                earNull.clearNetTransforms()

            for bundle in self.getPartBundleDict().values():
                charNodepath = bundle['modelRoot'].partBundleNP
                bundle = bundle['modelRoot'].getBundle()
                earNull = bundle.findChild('sphere3')
                if not earNull:
                    earNull = bundle.findChild('*sphere3')
                ears = charNodepath.find('**/sphere3')
                if ears.isEmpty():
                    ears = charNodepath.find('**/*sphere3')
                ears.clearEffect(CharacterJointEffect.getClassType())
                earRoot = charNodepath.attachNewNode('earRoot')
                earPitch = earRoot.attachNewNode('earPitch')
                earPitch.setP(40.0)
                ears.reparentTo(earPitch)
                earNull.addNetTransform(earRoot.node())
                ears.clearMat()
                ears.node().setPreserveTransform(ModelNode.PTNone)
                ears.setP(-40.0)
                ears.flattenMedium()
                ears.setBillboardAxis()
                self.startBlink()

        else:
            if charType == CIGlobals.Pluto:
                self.loadModel('phase_6/models/char/pluto-1000.bam')
                self.loadAnims({'walk': 'phase_6/models/char/pluto-walk.bam', 'neutral': 'phase_6/models/char/pluto-neutral.bam', 
                   'sit': 'phase_6/models/char/pluto-sit.bam', 
                   'stand': 'phase_6/models/char/pluto-stand.bam'})
            else:
                if charType == CIGlobals.Goofy:
                    self.loadModel('phase_6/models/char/TT_G-1500.bam')
                    self.loadAnims({'neutral': 'phase_6/models/char/TT_GWait.bam', 'walk': 'phase_6/models/char/TT_GWalk.bam'})
                else:
                    raise StandardError('unknown char %s!' % charType)
        Avatar.Avatar.initShadow(self)
        return

    def initializeLocalCollisions(self, name, radius):
        Avatar.Avatar.initializeLocalCollisions(self, radius, 2, name)

    def startBlink(self):
        randomStart = random.uniform(0.5, 5)
        taskMgr.add(self.blinkTask, 'blinkTask')

    def stopBlink(self):
        taskMgr.remove('blinkTask')
        taskMgr.remove('doBlink')
        taskMgr.remove('openEyes')

    def blinkTask(self, task):
        taskMgr.add(self.doBlink, 'doBlink')
        delay = random.uniform(0.5, 7)
        task.delayTime = delay
        return task.again

    def doBlink(self, task):
        self.closeEyes()
        taskMgr.doMethodLater(0.2, self.openEyes, 'openEyes')
        return task.done

    def closeEyes(self):
        self.find('**/joint_pupilR').hide()
        self.find('**/joint_pupilL').hide()
        if self.charType == CIGlobals.Mickey:
            self.mickeyEye.setY(-0.025)
            self.mickeyEye.hide()
        self.find('**/eyes').setTexture(self.closedEyes, 1)

    def openEyes(self, task):
        self.find('**/joint_pupilR').show()
        self.find('**/joint_pupilL').show()
        if self.charType == CIGlobals.Mickey:
            self.mickeyEye.setY(0.025)
            self.mickeyEye.show()
        self.find('**/eyes').setTexture(self.eyes, 1)
        return task.done

    def enterOff(self):
        self.currentAnim = None
        return

    def exitOff(self):
        pass

    def enterNeutral(self):
        self.loop('neutral')

    def exitNeutral(self):
        self.stop()

    def enterWalk(self):
        self.loop('walk')

    def exitWalk(self):
        self.stop()

    def enterRun(self):
        self.loop('run')

    def exitRun(self):
        self.stop()
示例#60
0
class CameraShyFirstPerson(FirstPerson):
    toonInFocusColor = VBase4(0.25, 1.0, 0.25, 1.0)
    toonOutOfFocusColor = VBase4(1.0, 1.0, 1.0, 1.0)
    fullyChargedState = 5

    def __init__(self, mg):
        self.mg = mg
        self.cameraFocus = None
        self.batteryFrame = None
        self.batteryBg = None
        self.batteryBar = None
        self.rechargeSound = None
        self.fullyChargedSound = None
        self.hasToonInFocus = False
        self.toonToTakePicOf = None
        self.cameraRechargeState = None
        self.cameraRechargingLabel = None
        self.cameraFlashSeq = None
        self.camFSM = ClassicFSM('CameraFSM', [State('off', self.enterOff, self.exitOff), State('ready', self.enterCameraReady, self.exitCameraReady), State('recharge', self.enterCameraRecharge, self.exitCameraRecharge)], 'off', 'off')
        self.camFSM.enterInitialState()
        FirstPerson.__init__(self)
        return

    def movementTask(self, task):
        if not inputState.isSet('jump') and not base.localAvatar.walkControls.isAirborne and inputState.isSet('forward') or inputState.isSet('reverse') or inputState.isSet('slideLeft') or inputState.isSet('slideRight'):
            if base.localAvatar.getAnimState() != 'run':
                base.localAvatar.setAnimState('run')
                base.localAvatar.playMovementSfx('run')
                self.mg.sendUpdate('runningAvatar', [base.localAvatar.doId])
        elif inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne:
            if base.localAvatar.getAnimState() != 'jump':
                base.localAvatar.setAnimState('jump')
                base.localAvatar.playMovementSfx(None)
                self.mg.sendUpdate('jumpingAvatar', [base.localAvatar.doId])
        elif base.localAvatar.getAnimState() != 'neutral':
            base.localAvatar.setAnimState('neutral')
            base.localAvatar.playMovementSfx(None)
            self.mg.sendUpdate('standingAvatar', [base.localAvatar.doId])
        return task.cont

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterCameraReady(self):
        self.acceptOnce('mouse1', self.__mouse1Pressed)

    def stopCameraFlash(self):
        if self.cameraFlashSeq:
            self.cameraFlashSeq.finish()
            self.cameraFlashSeq = None
        return

    def __mouse1Pressed(self):
        self.cameraFlashSeq = Sequence(Func(base.transitions.setFadeColor, 1, 1, 1), Func(base.transitions.fadeOut, 0.1), Wait(0.1), Func(base.transitions.fadeIn, 0.1), Wait(0.1), Func(base.transitions.setFadeColor, 0, 0, 0))
        self.cameraFlashSeq.start()
        self.mg.sendUpdate('remoteAvatarTakePicture', [base.localAvatar.doId])
        self.mg.myRemoteAvatar.takePicture()
        if self.hasToonInFocus and self.toonToTakePicOf:
            self.mg.sendUpdate('tookPictureOfToon', [self.toonToTakePicOf.doId])
        self.camFSM.request('recharge')

    def exitCameraReady(self):
        self.ignore('mouse1')

    def enterCameraRecharge(self):
        self.batteryBar.update(0)
        taskMgr.add(self.__rechargeNextState, 'rechargeCamera')

    def __rechargeNextState(self, task):
        if self.cameraRechargeState == None:
            self.cameraRechargeState = -1
        self.cameraRechargeState += 1
        if self.cameraRechargeState > 0:
            base.playSfx(self.rechargeSound)
        self.batteryBar.update(self.cameraRechargeState)
        if self.cameraRechargeState == self.fullyChargedState:
            base.playSfx(self.fullyChargedSound)
            self.camFSM.request('ready')
            return task.done
        else:
            task.delayTime = 1.0
            return task.again

    def exitCameraRecharge(self):
        taskMgr.remove('rechargeCamera')
        self.cameraRechargeState = None
        return

    def __handleRayInto(self, entry):
        intoNP = entry.getIntoNodePath()
        toonNP = intoNP.getParent()
        for key in base.cr.doId2do.keys():
            obj = base.cr.doId2do[key]
            if obj.__class__.__name__ == 'DistributedToon':
                if obj.getKey() == toonNP.getKey():
                    self.__handleToonInFocus(obj)

    def __handleRayOut(self, entry):
        intoNP = entry.getIntoNodePath()
        toonNP = intoNP.getParent()
        for key in base.cr.doId2do.keys():
            obj = base.cr.doId2do[key]
            if obj.__class__.__name__ == 'DistributedToon':
                if obj.getKey() == toonNP.getKey():
                    self.toonToTakePicOf = None
                    self.hasToonInFocus = False
                    if self.cameraFocus.getColorScale() == self.toonInFocusColor:
                        self.cameraFocus.setColorScale(self.toonOutOfFocusColor)

        return

    def __handleToonInFocus(self, toon):
        if not self.hasToonInFocus or self.toonToTakePicOf is not None or self.toonToTakePicOf.doId != toon.doId:
            self.toonToTakePicOf = toon
            self.hasToonInFocus = True
            self.cameraFocus.setColorScale(self.toonInFocusColor)
        return

    def start(self):
        self.fullyChargedSound = base.loadSfx('phase_4/audio/sfx/MG_pairing_match.mp3')
        self.rechargeSound = base.loadSfx('phase_4/audio/sfx/MG_sfx_travel_game_blue_arrow.mp3')
        self.batteryFrame = DirectFrame(parent=base.a2dBottomRight, pos=(-0.2, 0, 0.1), scale=(0.8, 0, 1))
        self.batteryBg = OnscreenImage(image='phase_4/maps/battery_charge_frame.png', parent=self.batteryFrame)
        self.batteryBg.setTransparency(1)
        self.batteryBg.setX(0.03)
        self.batteryBg.setScale(0.17, 0, 0.05)
        self.batteryBar = DirectWaitBar(value=0, range=5, barColor=(1, 1, 1, 1), relief=None, scale=(0.12, 0.0, 0.3), parent=self.batteryFrame)
        self.cameraFocus = loader.loadModel('phase_4/models/minigames/photo_game_viewfinder.bam')
        self.cameraFocus.reparentTo(base.aspect2d)
        self.focusCollHandler = CollisionHandlerEvent()
        self.focusCollHandler.setInPattern('%fn-into')
        self.focusCollHandler.setOutPattern('%fn-out')
        self.focusCollNode = CollisionNode('mouseRay')
        self.focusCollNP = base.camera.attachNewNode(self.focusCollNode)
        self.focusCollNode.setCollideMask(BitMask32(0))
        self.focusCollNode.setFromCollideMask(CIGlobals.WallBitmask)
        self.focusRay = CollisionRay()
        self.focusRay.setFromLens(base.camNode, 0.0, 0.0)
        self.focusCollNode.addSolid(self.focusRay)
        base.cTrav.addCollider(self.focusCollNP, self.focusCollHandler)
        base.localAvatar.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, 0.0, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)
        FirstPerson.start(self)
        return

    def reallyStart(self):
        self.accept('mouseRay-into', self.__handleRayInto)
        self.accept('mouseRay-out', self.__handleRayOut)
        self.camFSM.request('recharge')
        taskMgr.add(self.movementTask, 'movementTask')
        FirstPerson.reallyStart(self)

    def end(self):
        self.camFSM.request('off')
        taskMgr.remove('movementTask')
        self.ignore('mouseRay-into')
        self.ignore('mouseRay-out')
        FirstPerson.end(self)

    def reallyEnd(self):
        self.batteryBar.destroy()
        self.batteryBar = None
        self.batteryBg.destroy()
        self.batteryBg = None
        self.batteryFrame.destroy()
        self.batteryFrame = None
        self.cameraFocus.removeNode()
        self.cameraFocus = None
        self.focusCollHandler = None
        self.focusCollNode = None
        self.focusCollNP.removeNode()
        self.focusCollNP = None
        self.focusRay = None
        self.hasToonInFocus = None
        self.toonToTakePicOf = None
        self.fullyChargedSound = None
        self.rechargeSound = None
        self.stopCameraFlash()
        FirstPerson.reallyEnd(self)
        base.localAvatar.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, CIGlobals.ToonJumpForce, CIGlobals.ToonReverseSpeed, CIGlobals.ToonRotateSpeed)
        return

    def cleanup(self):
        self.camFSM.requestFinalState()
        self.camFSM = None
        FirstPerson.cleanup(self)
        return