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()
Exemple #2
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
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()
class DistributedSuit(Suit, DistributedAvatar, DistributedSmoothNode,
                      DelayDeletable):
    notify = directNotify.newCategory('DistributedSuit')

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

        self.anim = None
        self._state = SuitState.ALIVE
        self.dept = None
        self.variant = None
        self.suitPlan = None
        self.level = None
        self.moveIval = None
        self.hpFlash = None

        # For PythonCTMusicManager:
        # Are we in range of the localAvatar?
        self.isInRange = False

        self.chaseTarget = 0

        self.suitFSM = ClassicFSM('DistributedSuit', [
            State('off', self.enterSuitOff, self.exitSuitOff),
            State('walking', self.enterWalking, self.exitWalking),
            State('flyingDown', self.enterFlyingDown, self.exitFlyingDown),
            State('flyingUp', self.enterFlyingUp, self.exitFlyingUp),
            State('lured', self.enterLured, self.exitLured)
        ], 'off', 'off')
        self.stateIndex2suitState = {}
        self.suitFSM.enterInitialState()
        self.makeStateDict()

    def setChaseTarget(self, avId):
        if avId != base.localAvatar.doId:
            if self.chaseTarget == base.localAvatar.doId:
                messenger.send(PCTMM.getCogLostTargetEvent())
        else:
            messenger.send(PCTMM.getCogChasingEvent())

        self.chaseTarget = avId

    def setWalkPath(self, path, timestamp):
        elapsedT = globalClockDelta.localElapsedTime(timestamp)
        self.suitFSM.request('walking', [path, elapsedT])

    def showAvId(self):
        self.setDisplayName(self.getName() + "\n" + str(self.doId))

    def showName(self):
        self.setDisplayName(self.getName())

    def setDisplayName(self, name):
        self.setupNameTag(tempName=name)

    def enterWalking(self, path, elapsedT):
        # path: A list of point2s.
        #
        # We will make a sequence of NPCWalkIntervals for each point2 in the path.

        self.clearMoveTrack()
        self.moveIval = getMoveIvalFromPath(self, path, elapsedT, True,
                                            'suitMoveIval')
        self.moveIval.start(elapsedT)

    def clearMoveTrack(self):
        if self.moveIval:
            self.ignore(self.moveIval.getDoneEvent())
            self.moveIval.pause()
            self.moveIval = None
        if not self.isDead():
            self.animFSM.request('neutral')

    def exitWalking(self):
        self.clearMoveTrack()
        if not self.isDead():
            self.animFSM.request('neutral')

    def enterFlyingDown(self, startIndex, endIndex, ts=0.0):
        if self.getHood() != '' and startIndex != -1 and endIndex != -1:
            duration = 3.5
            startPoint = CIGlobals.SuitSpawnPoints[
                self.getHood()].keys()[startIndex]
            startPos = CIGlobals.SuitSpawnPoints[
                self.getHood()][startPoint] + (0, 0, 6.5 * 4.8)
            endPoint = CIGlobals.SuitSpawnPoints[
                self.getHood()].keys()[endIndex]
            endPos = CIGlobals.SuitSpawnPoints[self.getHood()][endPoint]
            self.stopMoving(finish=1)
            groundF = 28
            dur = self.getDuration('land')
            fr = self.getFrameRate('land')
            if fr:
                animTimeInAir = groundF / fr
            else:
                animTimeInAir = groundF
            impactLength = dur - animTimeInAir
            timeTillLanding = 6.5 - impactLength
            self.moveIval = LerpPosInterval(self,
                                            duration=timeTillLanding,
                                            pos=endPos,
                                            startPos=startPos,
                                            fluid=1)
            self.moveIval.start(ts)
        self.animFSM.request('flyDown', [ts])

    def exitFlyingDown(self):
        self.stopMoving(finish=1)
        self.animFSM.request('neutral')

    def enterFlyingUp(self, startIndex, endIndex, ts=0.0):
        if self.getHood() != '':
            duration = 3
            if startIndex > -1:
                startPoint = CIGlobals.SuitSpawnPoints[
                    self.getHood()].keys()[startIndex]
                startPos = CIGlobals.SuitSpawnPoints[
                    self.getHood()][startPoint]
            else:
                startPos = self.getPos(render)
            if endIndex > -1:
                endPoint = CIGlobals.SuitSpawnPoints[
                    self.getHood()].keys()[endIndex]
                endPos = CIGlobals.SuitSpawnPoints[
                    self.getHood()][endPoint] + (0, 0, 6.5 * 4.8)
            else:
                endPos = self.getPos(render) + (0, 0, 6.5 * 4.8)

            self.stopMoving(finish=1)
            groundF = 28
            dur = self.getDuration('land')
            fr = self.getFrameRate('land')
            if fr:
                animTimeInAir = groundF / fr
            else:
                animTimeInAir = groundF
            impactLength = dur - animTimeInAir
            timeTillLanding = 6.5 - impactLength
            self.moveIval = Sequence(
                Wait(impactLength),
                LerpPosInterval(self,
                                duration=timeTillLanding,
                                pos=endPos,
                                startPos=startPos,
                                fluid=1))
            self.moveIval.start(ts)
        self.animFSM.request('flyAway', [ts, 1])

    def exitFlyingUp(self):
        if self.moveIval:
            self.moveIval.finish()
            self.moveIval = None
        self.animFSM.request('neutral')

    def enterLured(self, _, __, ___):
        self.loop('lured')

    def exitLured(self):
        self.stop()

    def enterSuitOff(self, foo1=None, foo2=None, foo3=None):
        pass

    def exitSuitOff(self):
        pass

    def setName(self, name):
        Suit.setName(self, name, self.suitPlan.getName())

    def setLevel(self, level):
        self.level = level
        if self.level == 12:
            self.maxHealth = 200
        elif self.level > 0:
            self.maxHealth = (self.level + 1) * (self.level + 2)
        else:
            self.maxHealth = 1
        self.health = self.maxHealth
        self.updateHealthBar(self.health)

    def getLevel(self):
        return self.level

    def startMoveInterval(self, startX, startY, startZ, endX, endY, endZ,
                          duration):
        self.stopMoving()
        endPos = Point3(endX, endY, endZ)
        self.moveIval = NPCWalkInterval(self,
                                        endPos,
                                        durationFactor=duration,
                                        fluid=1)
        self.moveIval.start()

    def stopMoveInterval(self, andTurnAround=0):
        if self.moveIval:
            self.moveIval.pause()
            self.moveIval = None
        if andTurnAround == 1:
            if self.health > 0:
                self.animFSM.request('neutral')
            self.setH(self.getH() - 180)

    def toggleRay(self, ray=1):
        if ray:
            Suit.initializeRay(self, self.avatarType, 2)
        else:
            Suit.disableRay(self)

    def startProjInterval(self,
                          startX,
                          startY,
                          startZ,
                          endX,
                          endY,
                          endZ,
                          duration,
                          gravityMult,
                          ts=0):
        if isinstance(ts, int) and ts != 0:
            ts = globalClockDelta.localElapsedTime(ts)

        self.disableRay()
        self.stopMoveInterval()
        startPos = Point3(startX, startY, startZ)
        endPos = Point3(endX, endY, endZ)
        oldHpr = self.getHpr(render)
        self.headsUp(endPos)
        newHpr = self.getHpr(render)
        self.setHpr(oldHpr)
        self.moveIval = Parallel(
            LerpHprInterval(self,
                            duration=0.5,
                            hpr=newHpr,
                            startHpr=oldHpr,
                            blendType='easeInOut'),
            Sequence(Func(self.animFSM.request, 'flyAway', [ts]), Wait(3.5),
                     Func(self.animFSM.request, 'flyDown', [1.0])),
            Sequence(
                Wait(2.0), Func(self.headsUp, endPos),
                ProjectileInterval(self,
                                   startPos=startPos,
                                   endPos=endPos,
                                   gravityMult=gravityMult,
                                   duration=duration)))
        self.moveIval.start(ts)

    def startPosInterval(self,
                         startX,
                         startY,
                         startZ,
                         endX,
                         endY,
                         endZ,
                         duration,
                         blendType,
                         ts=0.0):
        if ts != 0.0:
            ts = globalClockDelta.localElapsedTime(ts)
        self.stopMoveInterval()
        startPos = Point3(startX, startY, startZ)
        endPos = Point3(endX, endY, endZ)
        self.moveIval = LerpPosInterval(self,
                                        duration=duration,
                                        pos=endPos,
                                        startPos=startPos,
                                        blendType=blendType)
        self.moveIval.start(ts)

    def stopMoving(self, finish=0):
        if self.moveIval:
            if finish:
                self.moveIval.finish()
            else:
                self.moveIval.pause()
            self.moveIval = None

    def d_disableMovement(self, wantRay=False):
        self.sendUpdate('disableMovement', [])
        self.interruptAttack()
        self.stopMoving()
        if not wantRay:
            Suit.disableRay(self)

    def d_enableMovement(self):
        self.sendUpdate('enableMovement', [])
        Suit.initializeRay(self, self.avatarType, 2)

    def startRay(self):
        Suit.initializeRay(self, self.avatarType, 2)

    def setHealth(self, health):
        if health > self.health:
            # We got an hp boost. Flash green.
            flashColor = VBase4(0, 1, 0, 1)
        elif health < self.health:
            # We got an hp loss. Flash red.
            flashColor = VBase4(1, 0, 0, 1)
        DistributedAvatar.setHealth(self, health)

        def doBossFlash():
            if not self.isEmpty():
                LerpColorScaleInterval(self, 0.2, flashColor).start()

        def clearBossFlash():
            if not self.isEmpty():
                self.clearColorScale()

        if self.isDead():
            self.setChaseTarget(0)
            base.taskMgr.remove(self.uniqueName('monitorLocalAvDistance'))
            if self.isInRange:
                messenger.send(PCTMM.getCogOutOfRangeEvent())
                self.isInRange = False
            self.interruptAttack()

        if self.getLevel() > 12:
            if self.hpFlash:
                self.hpFlash.finish()
                self.hpFlash = None
            self.hpFlash = Sequence(Func(doBossFlash), Wait(0.2),
                                    Func(clearBossFlash))
            self.hpFlash.start()
        self.updateHealthBar(health)

    def announceHealth(self, level, hp):
        DistributedAvatar.announceHealth(self, level, hp)
        if level == 1:
            healthSfx = base.audio3d.loadSfx(SuitGlobals.healedSfx)
            base.audio3d.attachSoundToObject(healthSfx, self)
            SoundInterval(healthSfx, node=self).start()
            del healthSfx

    #
    #    'setSuit' sets the suit type and generates it.
    #    'arg' is an id for a SuitPlan as defined in SuitBank or
    #        an instance of SuitPlan.
    #    'variant' is an optional argument that sets the variant.
    #        It takes an id for the variant or an instance of Variant.
    #        Default is Variant.NORMAL.

    def setSuit(self, arg, variant=0):
        if isinstance(arg, SuitPlan):
            plan = arg
        else:
            plan = SuitBank.getSuitById(arg)

        voice = Voice.NORMAL
        if variant:
            if isinstance(variant, (int, long, float, complex)):
                variant = Variant.getVariantById(variant)

        if plan.getForcedVoice():
            voice = plan.getForcedVoice()

        Suit.generate(self, plan, variant, voice=voice)
        self.suitPlan = plan
        self.variant = Variant.getVariantById(variant)

    def getSuit(self):
        return tuple((self.suitPlan, self.variant))

    def spawn(self, startIndex, endIndex, spawnMode=SpawnMode.FLYDOWN):
        if spawnMode == SpawnMode.FLYDOWN:
            startPoint = CIGlobals.SuitSpawnPoints[
                self.getHood()].keys()[startIndex]
            startPos = CIGlobals.SuitSpawnPoints[
                self.getHood()][startPoint] + (0, 0, 50)
            endPoint = CIGlobals.SuitSpawnPoints[
                self.getHood()].keys()[endIndex]
            endPos = CIGlobals.SuitSpawnPoints[self.getHood()][endPoint]
            if self.moveIval:
                self.moveIval.finish()
                self.moveIval = None
            self.moveIval = LerpPosInterval(self,
                                            duration=3,
                                            pos=endPos,
                                            startPos=startPos,
                                            fluid=1)

    def makeStateDict(self):
        self.stateIndex2suitState = {
            0: self.suitFSM.getStateNamed('off'),
            1: self.suitFSM.getStateNamed('walking'),
            2: self.suitFSM.getStateNamed('flyingDown'),
            3: self.suitFSM.getStateNamed('flyingUp'),
            4: self.suitFSM.getStateNamed('lured')
        }
        self.suitState2stateIndex = {}
        for stateId, state in self.stateIndex2suitState.items():
            self.suitState2stateIndex[state.getName()] = stateId

    def setSuitState(self, index, startPoint, endPoint, timestamp=None):
        if timestamp != None:
            ts = globalClockDelta.localElapsedTime(timestamp)
        else:
            ts = 0.0

        self.suitState = self.stateIndex2suitState[index]
        self.startPoint = startPoint
        self.endPoint = endPoint

        self.suitFSM.request(self.suitState, [startPoint, endPoint, ts])

    def getSuitState(self):
        return self.suitState

    def setAnimState(self, anim, loop=1, timestamp=None):
        prevAnim = self.anim
        self.anim = anim

        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)

        if type(anim) == types.IntType:
            if anim != 44 and anim != 45:
                anim = SuitGlobals.getAnimById(anim)
                animName = anim.getName()
            elif anim == 44:
                animName = 'die'
            elif anim == 45:
                animName = 'flyNeutral'
        elif type(anim) == types.StringType:
            animName = anim

        if self.animFSM.hasStateNamed(animName):
            self.animFSM.request(animName, [ts])
        else:
            if loop:
                self.loop(animName)
            else:
                self.play(animName)
        messenger.send(SuitGlobals.animStateChangeEvent % (self.uniqueName),
                       [anim, prevAnim])

    def doAttack(self, attackId, avId, timestamp=None):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        attackName = SuitAttacks.SuitAttackLengths.keys()[attackId]
        attackTaunt = CIGlobals.SuitAttackTaunts[attackName][random.randint(
            0,
            len(CIGlobals.SuitAttackTaunts[attackName]) - 1)]
        avatar = self.cr.doId2do.get(avId)
        shouldChat = 0
        if self.suitPlan in [SuitBank.VicePresident, SuitBank.LucyCrossbill]:
            shouldChat = random.randint(0, 2)
        if shouldChat == 0:
            self.setChat(attackTaunt)

        self.animFSM.request('attack', [attackName, avatar, 0.0])

    def throwObject(self):
        self.acceptOnce('enter' + self.wsnp.node().getName(),
                        self.__handleWeaponCollision)
        Suit.throwObject(self)

    def __handleWeaponCollision(self, entry):
        self.sendUpdate('toonHitByWeapon',
                        [self.attack, base.localAvatar.doId])
        base.localAvatar.handleHitByWeapon(self.attack, self)
        self.b_handleWeaponTouch()

    def b_handleWeaponTouch(self):
        self.sendUpdate('handleWeaponTouch', [])
        self.handleWeaponTouch()

    def __monitorLocalAvDistance(self, task):
        if self.getDistance(base.localAvatar) <= PCTMM.getCogInRangeDistance(
        ) and not self.isInRange:
            self.isInRange = True
            messenger.send(PCTMM.getCogInRangeEvent())
        elif self.getDistance(base.localAvatar) > PCTMM.getCogInRangeDistance(
        ) and self.isInRange:
            self.isInRange = False
            messenger.send(PCTMM.getCogOutOfRangeEvent())

        return task.cont

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        self.setAnimState('neutral')
        base.taskMgr.add(self.__monitorLocalAvDistance,
                         self.uniqueName('monitorLocalAvDistance'))

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

    def disable(self):
        base.taskMgr.remove(self.uniqueName('monitorLocalAvDistance'))
        self.anim = None
        self._state = None
        self.dept = None
        self.variant = None
        self.suitPlan = None
        if self.hpFlash:
            self.hpFlash.finish()
            self.hpFlash = None
        if self.moveIval:
            self.moveIval.pause()
            self.moveIval = None
        Suit.disable(self)
        DistributedAvatar.disable(self)

    def delete(self):
        Suit.delete(self)
        del self.anim
        del self._state
        del self.dept
        del self.variant
        del self.suitPlan
        del self.moveIval
        DistributedAvatar.delete(self)
        DistributedSmoothNode.delete(self)
Exemple #5
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()
class ToonFPS(DirectObject):
    notify = directNotify.newCategory("ToonFPS")

    WeaponName2DamageData = {"pistol": (30.0, 10.0, 150.0, 0.3),
        "shotgun": (40.0, 15.0, 155.0, 0.5), "sniper": (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

        # blach (02Aug15)
        # Drastically improved the accuracy of bullets... DRASTICALLY
        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.deadFSM = ClassicFSM('dead', [State('off', self.enterOff, self.exitOff),
        #		State('])
        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.getStateNamed('dead').addChild(self.deadFSM)
        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()

    def movementTask(self, task):

        if (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])

        return Task.cont

    def enterAlive(self):
        if not self.mg.fsm.getCurrentState().getName() in ['gameOver', 'announceGameOver', 'finalScores']:
            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()

    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.ogg")
        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
        )

    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):
        try:
            base.camera.lookAt(killer, 0, 0, 3)
        except AssertionError:
            pass
        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.ogg")
            self.shoot = base.loadSfx("phase_4/audio/sfx/pistol_shoot.ogg")
            self.reload = base.loadSfx("phase_4/audio/sfx/pistol_worldreload.ogg")
        elif self.weaponName == "sniper":
            self.draw = base.loadSfx("phase_4/audio/sfx/draw_primary.ogg")
            self.shoot = base.loadSfx("phase_4/audio/sfx/shotgun_shoot.ogg")
            self.cockBack = base.loadSfx("phase_4/audio/sfx/shotgun_cock_back.ogg")
            self.cockFwd = base.loadSfx("phase_4/audio/sfx/shotgun_cock_forward.ogg")
        elif self.weaponName == "shotgun":
            self.draw = base.loadSfx("phase_4/audio/sfx/draw_primary.ogg")
            self.shoot = base.loadSfx("phase_4/audio/sfx/shotgun_shoot.ogg")
            self.cockBack = base.loadSfx("phase_4/audio/sfx/shotgun_cock_back.ogg")
            self.cockFwd = base.loadSfx("phase_4/audio/sfx/shotgun_cock_forward.ogg")
        self.empty = base.loadSfx("phase_4/audio/sfx/shotgun_empty.ogg")
        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 == "sniper":
            self.weapon = loader.loadModel("phase_4/models/props/sniper.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)
        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)
        self.gui.load()

    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 == "sniper":
            self.v_model_root.setPos(-0.42, -0.81, -1.7)
            self.v_model_root.setHpr(359, 352.87, 0.00)
        elif self.weaponName == "shotgun":
            self.v_model_root.setPos(-0.42, -0.81, -1.7)
            self.v_model_root.setHpr(359, 352.87, 0.00)
        self.gui.start()
        self.firstPerson.disableMouse()
        self.aliveFSM.request('draw')

    def reallyStart(self):
        self.firstPerson.reallyStart()
        base.localAvatar.startTrackAnimToSpeed()
        #taskMgr.add(self.movementTask, "toonBattleMovement")

    def end(self):
        if self.aliveFSM.getCurrentState().getName() != 'off':
            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):
        try:
            self.ToonFPS_reallyEnded
            return
        except:
            self.ToonFPS_reallyEnded = 1
        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)

    def cleanup(self):
        try:
            self.ToonFPS_cleanedUp
            return
        except:
            self.ToonFPS_cleanedUp = 1
        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
        try:
            self.aliveFSM.requestFinalState()
            self.fsm.requestFinalState()
        except:
            self.notify.warning('Redundant call to enter the final state.')
        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()

    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()

    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')
        elif self.weaponName == "sniper":
            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):
        #self.draw.stop()
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    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()
        elif self.weaponName == "sniper":
            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')

    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)
                ),
            )
        elif self.weaponName == "sniper":
            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.shoot.stop()
        self.ignore('shootTrack')
        if self.track:
            self.track.finish()
            self.track = None

    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')
        elif self.weaponName == "sniper":
            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.reload.stop()
        self.ignore('reloadTrack')
        if self.track:
            self.track.finish()
            self.track = None

    def resetAmmo(self):
        if self.weaponName == "pistol":
            self.ammo = 14
        elif self.weaponName == "shotgun":
            self.ammo = 7
        elif self.weaponName == "sniper":
            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
Exemple #7
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()