Пример #1
0
class MonsterBlood(DirectObject):
    def __init__(self):
        self.value = 100
        self.lifeBar = DirectWaitBar(text="Monster",
                                     text_fg=(1, 1, 1, 1),
                                     text_pos=(1.2, -0.18, 0),
                                     text_align=TextNode.ARight,
                                     value=self.value,
                                     barColor=(0, 1, 0.25, 1),
                                     barRelief=DGG.RAISED,
                                     barBorderWidth=(0.03, 0.03),
                                     borderWidth=(0.01, 0.01),
                                     relief=DGG.RIDGE,
                                     frameColor=(0.8, 0.05, 0.10, 1),
                                     frameSize=(0, 1.2, 0, -0.1),
                                     pos=(0.2, 0, base.a2dTop - 0.15))
        self.lifeBar.setTransparency(1)
        self.hide()

    def show(self):
        self.lifeBar["value"] = self.value
        self.lifeBar.show()

    def hide(self):
        self.lifeBar.hide()

    def setLifeBarValue(self, newValue):
        self.lifeBar["value"] = newValue
Пример #2
0
class Hud(DirectObject):
    def __init__(self, framework):
        super(Hud, self).__init__()
        self.f = framework

        self.player = DirectWaitBar(
            text="Player",
            text_fg=(1, 1, 1, 1),
            text_pos=(-1.2, -0.15, 0),
            text_align=TextNode.ALeft,
            text_scale=0.075,
            value=100,
            barColor=(0, 1, 0.25, 1),
            barRelief=DGG.FLAT,
            barBorderWidth=(0.03, 0.03),
            borderWidth=(0.01, 0.01),
            relief=DGG.FLAT,
            frameColor=(0.8, 0.05, 0.10, 1),
            frameSize=(-1.2, 0, 0, -0.05),
            pos=(-0.2, 0, self.f.a2dTop - 0.10))
        self.player.set_transparency(1)

        self.bot = DirectWaitBar(
            text="Enemy",
            text_fg=(1, 1, 1, 1),
            text_pos=(1.2, -0.15, 0),
            text_align=TextNode.ARight,
            text_scale=0.075,
            value=100,
            barColor=(0, 1, 0.25, 1),
            barRelief=DGG.FLAT,
            barBorderWidth=(0.03, 0.03),
            borderWidth=(0.01, 0.01),
            relief=DGG.FLAT,
            frameColor=(0.8, 0.05, 0.10, 1),
            frameSize=(0, 1.2, 0, -0.05),
            pos=(0.2, 0, self.f.a2dTop - 0.10))
        self.bot.set_transparency(1)

        self.accept("hud_set_hp", self.set_hp)
        self.hide()

    def show(self):
        self.bot.show()
        self.player.show()

    def hide(self):
        self.bot.hide()
        self.player.hide()

    def set_hp(self, uid, value):
        if uid == "enemy":
            self.bot["value"] = value
        elif uid == "player":
            self.player["value"] = value
Пример #3
0
class Hud(DirectObject):
    def __init__(self):
        self.lifeBar1 = DirectWaitBar(
            text = "Player1",
            text_fg = (1,1,1,1),
            text_pos = (-1.2, -0.18, 0),
            text_align = TextNode.ALeft,
            value = 100,
            barColor = (0, 1, 0.25, 1),
            barRelief = DGG.RAISED,
            barBorderWidth = (0.03, 0.03),
            borderWidth = (0.01, 0.01),
            relief = DGG.RIDGE,
            frameColor = (0.8,0.05,0.10,1),
            frameSize = (-1.2, 0, -0.1, 0),
            pos = (-0.2,0,base.a2dTop-0.15))
        self.lifeBar1.setTransparency(1)

        self.lifeBar2 = DirectWaitBar(
            text = "Player2",
            text_fg = (1,1,1,1),
            text_pos = (1.2, -0.18, 0),
            text_align = TextNode.ARight,
            value = 100,
            barColor = (0, 1, 0.25, 1),
            barRelief = DGG.RAISED,
            barBorderWidth = (0.03, 0.03),
            borderWidth = (0.01, 0.01),
            relief = DGG.RIDGE,
            frameColor = (0.8,0.05,0.10,1),
            frameSize = (0, 1.2, -0.1, 0),
            pos = (0.2,0,base.a2dTop-0.15))
        self.lifeBar2.setTransparency(1)

        self.accept("hud_setLifeBarValue", self.setLifeBarValue)
        self.hide()

    def show(self):
        self.lifeBar1["value"] = 100
        self.lifeBar2["value"] = 100
        self.lifeBar1.show()
        self.lifeBar2.show()

    def hide(self):
        self.lifeBar1.hide()
        self.lifeBar2.hide()

    def setLifeBarValue(self, barNr, newValue):
        if barNr == 0:
            self.lifeBar1["value"] = newValue
        elif barNr == 1:
            self.lifeBar2["value"] = newValue
Пример #4
0
class ControlPointBar(DirectWaitBar):
    def __init__(self, barColor=(255,0,0,1), pos=(1.0,0,0.9)): 
        self.bar = DirectWaitBar(pos = pos, barColor = barColor, text="",
        value=0, range=30, frameSize=(-0.3,0.3,0,0.03), frameColor=(0,0,255,1))

    def setValue(self, value):
        self.bar['value'] = float(value)

    def hide(self):
        self.bar.hide()
    
    def show(self):
        self.bar.show()
Пример #5
0
class ResourceBar(DirectWaitBar):
    def __init__(self, barColor=(200,180,0,1), pos=(0,0,0.9)): 
        self.bar = DirectWaitBar(pos = pos, barColor = barColor, text="",
        value=70, range=100, frameSize=(-0.3,0.3,0,0.03), frameColor=(0,0,0,1))

    def setValue(self, value):
        self.bar['value'] = float(value)

    def hide(self):
        self.bar.hide()
    
    def show(self):
        self.bar.show()
        
Пример #6
0
class Bar(DirectObject.DirectObject):
	def __init__( self):
		self.bar = DirectWaitBar(text = "Loading...", value = 0, pos = (0,.4,.4))
		self.bar.hide()

	def incBar(self, arg):
		self.bar['value'] +=	arg
		#text = str(bar['value'])
		#textObject.setText(text)

	def show(self):
		self.bar.show()

	def hide(self):
		self.bar.hide()
Пример #7
0
class ControlPointBar(DirectWaitBar):
    def __init__(self, barColor=(255, 0, 0, 1), pos=(1.0, 0, 0.9)):
        self.bar = DirectWaitBar(pos=pos,
                                 barColor=barColor,
                                 text="",
                                 value=0,
                                 range=30,
                                 frameSize=(-0.3, 0.3, 0, 0.03),
                                 frameColor=(0, 0, 255, 1))

    def setValue(self, value):
        self.bar['value'] = float(value)

    def hide(self):
        self.bar.hide()

    def show(self):
        self.bar.show()
Пример #8
0
class ResourceBar(DirectWaitBar):
    def __init__(self, barColor=(200, 180, 0, 1), pos=(0, 0, 0.9)):
        self.bar = DirectWaitBar(pos=pos,
                                 barColor=barColor,
                                 text="",
                                 value=70,
                                 range=100,
                                 frameSize=(-0.3, 0.3, 0, 0.03),
                                 frameColor=(0, 0, 0, 1))

    def setValue(self, value):
        self.bar['value'] = float(value)

    def hide(self):
        self.bar.hide()

    def show(self):
        self.bar.show()
Пример #9
0
Файл: hud.py Проект: iPazu/Slimy
class Hud(DirectObject):
    def __init__(self):
        self.lifeBar = DirectWaitBar(value=100,
                                     barColor=(0, 1, 0.20, 1),
                                     barRelief=DGG.RAISED,
                                     relief=DGG.RIDGE,
                                     frameColor=(0.8, 0.05, 0.10, 1),
                                     frameSize=(-1.2, 0, 0, -0.1),
                                     pos=(-0.2, 0, base.a2dTop))
        self.lifeBar.setTransparency(1)

        self.font = loader.loadFont(
            str(MAINDIR) + '/assets/fonts/allerdisplay.ttf')

        self.score_text = OnscreenText(text="Score:",
                                       pos=(-1.6, 0.93),
                                       scale=0.05,
                                       fg=(1, 1, 1, 1),
                                       align=TextNode.ACenter,
                                       font=self.font,
                                       mayChange=False)
        self.score = OnscreenText(text="0",
                                  pos=(-1.6, 0.83),
                                  scale=0.07,
                                  fg=(1, 1, 1, 1),
                                  align=TextNode.ACenter,
                                  font=self.font,
                                  mayChange=True)

        self.accept("hud_setLifeBarValue", self.setLifeBarValue)
        self.hide()

    def show(self):
        self.lifeBar["value"] = 100
        self.lifeBar.show()

    def hide(self):
        self.lifeBar.hide()

    def setScore(self, score):
        self.score.setText(str(score))

    def setLifeBarValue(self, newValue):
        self.lifeBar["value"] = newValue
Пример #10
0
class BossBlood(DirectObject):
    def __init__(self):
        self.value = 100
        frameTex = loader.loadTexture("assets/gui/blood.jpg")
        barTex = loader.loadTexture("assets/gui/btn_click.png")
        self.lifeBar = DirectWaitBar(
            text="Boss",
            text_fg=(1, 1, 1, 1),
            text_pos=(1.0, 0.07, 0),
            text_align=TextNode.ARight,
            value=self.value,
            #0, 1, 0.25, 1   0.8,0.05,0.10,1
            #barTexture = "assets/gui/btn_click.png",
            barColor=(0.8, 0.05, 0.10, 1),
            frameTexture=frameTex,
            barTexture=barTex,
            barRelief=DGG.RIDGE,
            barBorderWidth=(0.01, 0.01),
            borderWidth=(0.01, 0.01),
            relief=DGG.SUNKEN,
            frameSize=(0, 3.2, 0, 0.05),
            pos=(base.a2dLeft, 0, base.a2dBottom))
        self.lifeBar.setTransparency(1)
        self.hide()

    def show(self):
        self.lifeBar["value"] = self.value
        self.lifeBar.show()

    def hide(self):
        self.lifeBar.hide()

    def setLifeBarValue(self, newValue, name='BOSS'):
        self.value = newValue
        self.lifeBar["value"] = self.value * 100 / self.maxVal
        self.lifeBar["text"] = str(self.value) + "/" + str(
            self.maxVal) + ' BOSS'

    def setLifeBarMaxValue(self, newValue, name='BOSS'):
        self.maxVal = newValue
        self.lifeBar["text"] = str(self.value) + "/" + str(
            self.maxVal) + ' BOSS'
        self.lifeBar["value"] = self.value * 100 / self.maxVal
Пример #11
0
class HeroBlood(DirectObject):
    """docstring for Blood"""
    def __init__(self):
        self.value = 100
        self.maxVal = 100
        #text text_pos value frameSize pos
        frameTex = loader.loadTexture("assets/gui/blood.jpg")
        barTex = loader.loadTexture("assets/gui/btn_click.png")
        self.lifeBar = DirectWaitBar(text=str(self.value),
                                     text_fg=(1, 1, 1, 0.6),
                                     text_pos=(0.8, 1.92, 0),
                                     text_align=TextNode.ALeft,
                                     value=self.value,
                                     barColor=(0, 0.95, 0.25, 1),
                                     frameTexture=frameTex,
                                     barTexture=barTex,
                                     barRelief=DGG.RIDGE,
                                     barBorderWidth=(0.01, 0.01),
                                     borderWidth=(0.01, 0.01),
                                     relief=DGG.SUNKEN,
                                     frameSize=(0.25, 0.8, 1.92, 1.97),
                                     pos=(base.a2dLeft, 0, base.a2dBottom))
        self.lifeBar.setTransparency(1)
        self.hide()

    def show(self):
        self.lifeBar.show()

    def hide(self):
        self.lifeBar.hide()

    def setLifeBarValue(self, newValue, name='Player'):
        self.value = newValue
        self.lifeBar["text"] = str(self.value) + "/" + str(
            self.maxVal) + ' ' + name
        self.lifeBar["value"] = self.value * 100 / self.maxVal

    def setLifeBarMaxValue(self, newValue, name='Player'):
        self.maxVal = newValue
        self.lifeBar["text"] = str(self.value) + "/" + str(
            self.maxVal) + ' ' + name
        self.lifeBar["value"] = self.value * 100 / self.maxVal
Пример #12
0
class ProgressBar(object):
    '''        
    '''
    def __init__(self):
        '''        
        '''
        self.__wait_bar = DirectWaitBar( text = "Carregando...",
                                         value = 0,
                                         pos = (0, 0, -.95),
                                         text_scale = 0.05,
                                         text_pos = (0, 0.025),
                                         frameSize = (-1.3, 1.3, 0, 0.08) )
        
        self.hide()
        
    def finish(self):
        self.__wait_bar['barColor'] = (0, 1, 0, 1)
        self.__wait_bar.setBarColor()
        self.__wait_bar.finish()
        self.hide()
    
    def hide(self):
        self.__wait_bar.hide()
        
    def show(self):
        self.__wait_bar.show()
        
    def update(self, value):
        
        if value < 25:
            self.__wait_bar['barColor'] = (1, 0, 0, 1)
        elif value > 25 and value < 75:
            self.__wait_bar['barColor'] = (1, 1, 0, 1)
        elif value > 75:
            self.__wait_bar['barColor'] = (0, 1, 0, 1)
            
            
        self.__wait_bar.setBarColor()
        
        self.__wait_bar.update(value)
        
        
Пример #13
0
class ControlPointBar(DirectWaitBar):
    def __init__(self, barColor=(255,0,0,1), pos=(1.0,0,0.9)): 
        self.bar = DirectWaitBar(pos = pos, barColor = barColor, text="",
        value=70, range=100, frameSize=(-0.3,0.3,0,0.03), frameColor=(0,0,255,1))
        

    def setValue(self, value):
        self.bar['value'] = float(value)
        self.setPos((0,0,0))

    def hide(self):
        self.bar.hide()
    
    # to make inherited setPos available for this object
    def show(self):
        self.bar.show()
    
    # to make inherited setPos available for this object
    def setPos(self, pos):
        self.bar.setPos(pos)
Пример #14
0
class ToonFPSGui:

    def __init__(self, base):
        self.base = base
        self.noAmmoLabel = None
        self.ammo_gui = None
        self.hp_meter = None
        self.crosshair = None
        self.stats_container = None
        self.stats_bg = None
        self.stats_lbl = None
        self.kills_lbl = None
        self.deaths_lbl = None
        self.points_lbl = None
        return

    def load(self):
        self.ammo_gui = loader.loadModel('phase_4/models/minigames/gun_ammo_gui.egg')
        self.ammo_gui.setScale(0.15)
        self.ammo_gui.setPos(0.38, 0, 0.1)
        self.hp_meter = DirectWaitBar(text=str(self.base.hp), text_roll=-90, text_scale=0.2, text_pos=(-0.025,
                                                                                                       0), relief=DGG.RAISED, barColor=(1,
                                                                                                                                        0,
                                                                                                                                        0,
                                                                                                                                        1), range=self.base.max_hp, value=self.base.hp, parent=base.a2dBottomRight, scale=0.4, pos=(-0.12,
                                                                                                                                                                                                                                    0,
                                                                                                                                                                                                                                    0.2), frameSize=(-0.4,
                                                                                                                                                                                                                                                     0.4,
                                                                                                                                                                                                                                                     -0.2,
                                                                                                                                                                                                                                                     0.2))
        self.hp_meter.setR(-90)
        self.hp_meter.hide()
        self.crosshair = getCrosshair()
        font = CIGlobals.getToonFont()
        box = DGG.getDefaultDialogGeom()
        if self.base.__class__.__name__ == 'GunGameToonFPS':
            self.stats_container = DirectFrame(parent=base.a2dTopLeft, pos=(0.3, 0.2,
                                                                            -0.185))
            self.stats_bg = OnscreenImage(image=box, color=(1, 1, 0.75, 1), scale=(0.5,
                                                                                   0.3,
                                                                                   0.3), parent=self.stats_container)
            self.stats_lbl = OnscreenText(font=font, text='Stats', pos=(-0.01, 0.08,
                                                                        0), parent=self.stats_container)
            self.kills_lbl = OnscreenText(font=font, text='Kills: ' + str(self.base.kills), pos=(-0.235,
                                                                                                 0.025,
                                                                                                 0), scale=0.055, parent=self.stats_container, align=TextNode.ALeft)
            self.deaths_lbl = OnscreenText(font=font, text='Deaths: ' + str(self.base.deaths), pos=(-0.235,
                                                                                                    -0.04,
                                                                                                    0), scale=0.055, parent=self.stats_container, align=TextNode.ALeft)
            self.points_lbl = OnscreenText(font=font, text='Points: ' + str(self.base.points), pos=(-0.235,
                                                                                                    -0.105,
                                                                                                    0), scale=0.055, parent=self.stats_container, align=TextNode.ALeft)
            self.stats_container.hide()
            del font
            del box

    def start(self):
        self.ammo_gui.reparentTo(base.a2dBottomLeft)
        self.crosshair.show()
        self.hp_meter.show()
        if self.base.__class__.__name__ == 'GunGameToonFPS':
            self.stats_container.show()

    def end(self):
        self.ammo_gui.reparentTo(hidden)
        if self.base.__class__.__name__ == 'GunGameToonFPS':
            self.stats_container.hide()
        self.crosshair.hide()
        self.hp_meter.hide()

    def cleanup(self):
        self.ammo_gui.removeNode()
        self.ammo_gui = None
        self.hp_meter.destroy()
        self.hp_meter = None
        self.crosshair.destroy()
        self.crosshair = None
        self.deleteNoAmmoLabel()
        self.deleteStatsGui()
        return

    def deleteStatsGui(self):
        if self.stats_container:
            self.stats_container.destroy()
            self.stats_container = None
        if self.stats_bg:
            self.stats_bg.destroy()
            self.stats_bg = None
        if self.stats_lbl:
            self.stats_lbl.destroy()
            self.stats_lbl = None
        if self.kills_lbl:
            self.kills_lbl.destroy()
            self.kills_lbl = None
        if self.deaths_lbl:
            self.deaths_lbl.destroy()
            self.deaths_lbl = None
        if self.points_lbl:
            self.points_lbl.destroy()
            self.points_lbl = None
        return

    def updateStats(self):
        self.kills_lbl['text'] = 'Kills: ' + str(self.base.kills)
        self.deaths_lbl['text'] = 'Deaths: ' + str(self.base.deaths)
        self.points_lbl['text'] = 'Points: ' + str(self.base.points)

    def deleteNoAmmoLabel(self):
        if self.noAmmoLabel:
            self.noAmmoLabel.destroy()
            self.noAmmoLabel = None
        return

    def adjustAmmoGui(self):
        self.ammo_gui.find('**/bar_' + str(self.base.ammo + 1)).hide()

    def adjustHpMeter(self):
        self.hp_meter['text'] = str(self.base.hp)
        self.hp_meter['value'] = self.base.hp
        if self.base.hp <= 40:
            self.hp_meter['barColor'] = (1, 0, 0, 1)
        else:
            self.hp_meter['barColor'] = (1, 1, 1, 1)

    def resetAmmo(self):
        for bar in self.ammo_gui.findAllMatches('**/bar_*'):
            bar.show()

    def notifyNoAmmo(self):
        self.deleteNoAmmoLabel()
        self.noAmmoLabel = DirectLabel(text='Press R to reload!', relief=None, text_scale=0.1, text_pos=(0,
                                                                                                         0.5,
                                                                                                         0), text_fg=(1,
                                                                                                                      1,
                                                                                                                      1,
                                                                                                                      1), text_shadow=(0,
                                                                                                                                       0,
                                                                                                                                       0,
                                                                                                                                       1))
        return
class QuestNote(DirectFrame):
    notify = directNotify.newCategory("QuestNote")

    spots = [(-0.45, 0, 0.3), (0.45, 0, 0.3), (0.45, 0, -0.25),
             (-0.45, 0, -0.25)]
    RewardTextPos = (0, -0.4)
    RewardTextScale = 0.06
    ProgressTextScale = 0.07
    ProgressBarPos = (0, 0, -0.19)
    ProgressTextPos = (0, -0.19)
    TaskInfoTextPos = (0, 0.05)
    NonHeadingTextScale = 0.08
    HeadingTextPos = (0, 0.23)
    HeadingTextScale = 0.1

    def __init__(self, index):
        DirectFrame.__init__(self, scale=0.5)
        stickergui = loader.loadModel(
            'phase_3.5/models/gui/stickerbook_gui.bam')
        self['image'] = stickergui.find('**/paper_note')
        self['image_scale'] = (1.3, 1, 1)
        self.setPos(self.spots[index])
        self.useProgressBar = False
        self.headingText = OnscreenText(parent=self,
                                        text="",
                                        font=CIGlobals.getToonFont(),
                                        pos=self.HeadingTextPos,
                                        scale=self.HeadingTextScale)
        self.taskInfoText = OnscreenText(parent=self,
                                         text="",
                                         font=CIGlobals.getToonFont(),
                                         pos=self.TaskInfoTextPos,
                                         scale=self.NonHeadingTextScale)
        self.progressText = OnscreenText(parent=self,
                                         text="",
                                         font=CIGlobals.getToonFont(),
                                         pos=self.ProgressTextPos,
                                         scale=self.ProgressTextScale)
        self.progressBar = DirectWaitBar(
            parent=self,
            relief=DGG.SUNKEN,
            frameSize=(-0.95, 0.95, -0.1, 0.12),
            borderWidth=(0.025, 0.025),
            scale=0.4,
            frameColor=(251.0 / 255, 252.0 / 255, 176.0 / 255, 1.0),
            barColor=(0.5, 0.7, 0.5, 1),
            text='0/0',
            text_font=CIGlobals.getToonFont(),
            text_scale=0.19,
            text_fg=(0.05, 0.14, 0.4, 1),
            text_align=TextNode.ACenter,
            text_pos=(0, -0.05),  #-0.02
            pos=self.ProgressBarPos)
        self.progressBar.hide()
        self.rewardText = OnscreenText(parent=self,
                                       text="",
                                       font=CIGlobals.getToonFont(),
                                       pos=self.RewardTextPos,
                                       scale=self.RewardTextScale,
                                       fg=(1, 0.1, 0.1, 1.0))
        self.hide()

    def setHeading(self, text):
        self.headingText.setText(text)

    def setTaskInfo(self, text):
        self.taskInfoText.setText(text)

    def setProgress(self, text, range=0, value=0):
        if self.useProgressBar:
            self.progressBar.show()
            self.progressBar['text'] = text
            self.progressBar['range'] = range
            self.progressBar['value'] = value
        else:
            self.progressText['text'] = text

    def setReward(self, text):
        self.rewardText.setText(text)

    def setCompleted(self, value):
        if value:
            self.progressBar.hide()
            self['image_color'] = QuestGlobals.LIGHT_GREEN
class DistributedMazeGame(DistributedMinigame):
    notify = directNotify.newCategory('DistributedMazeGame')
    CAMERA_TASK = 'MazeGameCameraTask'
    UPDATE_SUITS_TASK = 'MazeGameUpdateSuitsTask'
    TREASURE_GRAB_EVENT_NAME = 'MazeTreasureGrabbed'

    def __init__(self, cr):
        DistributedMinigame.__init__(self, cr)
        self.gameFSM = ClassicFSM.ClassicFSM('DistributedMazeGame', [
            State.State('off', self.enterOff, self.exitOff, ['play']),
            State.State('play', self.enterPlay, self.exitPlay,
                        ['cleanup', 'showScores']),
            State.State('showScores', self.enterShowScores,
                        self.exitShowScores, ['cleanup']),
            State.State('cleanup', self.enterCleanup, self.exitCleanup, [])
        ], 'off', 'cleanup')
        self.addChildGameFSM(self.gameFSM)
        self.usesLookAround = 1

    def getTitle(self):
        return TTLocalizer.MazeGameTitle

    def getInstructions(self):
        return TTLocalizer.MazeGameInstructions

    def getMaxDuration(self):
        return MazeGameGlobals.GAME_DURATION

    def __defineConstants(self):
        self.TOON_SPEED = 8.0
        self.TOON_Z = 0
        self.MinSuitSpeedRange = [0.8 * self.TOON_SPEED, 0.6 * self.TOON_SPEED]
        self.MaxSuitSpeedRange = [1.1 * self.TOON_SPEED, 2.0 * self.TOON_SPEED]
        self.FASTER_SUIT_CURVE = 1
        self.SLOWER_SUIT_CURVE = self.getDifficulty() < 0.5
        self.slowerSuitPeriods = {
            2000: {
                4: [128, 76],
                8: [128, 99, 81, 68],
                12: [128, 108, 93, 82, 74, 67],
                16: [128, 112, 101, 91, 83, 76, 71, 66]
            },
            1000: {
                4: [110, 69],
                8: [110, 88, 73, 62],
                12: [110, 95, 83, 74, 67, 61],
                16: [110, 98, 89, 81, 75, 69, 64, 60]
            },
            5000: {
                4: [96, 63],
                8: [96, 79, 66, 57],
                12: [96, 84, 75, 67, 61, 56],
                16: [96, 87, 80, 73, 68, 63, 59, 55]
            },
            4000: {
                4: [86, 58],
                8: [86, 71, 61, 53],
                12: [86, 76, 68, 62, 56, 52],
                16: [86, 78, 72, 67, 62, 58, 54, 51]
            },
            3000: {
                4: [78, 54],
                8: [78, 65, 56, 49],
                12: [78, 69, 62, 57, 52, 48],
                16: [78, 71, 66, 61, 57, 54, 51, 48]
            },
            9000: {
                4: [71, 50],
                8: [71, 60, 52, 46],
                12: [71, 64, 58, 53, 49, 45],
                16: [71, 65, 61, 57, 53, 50, 47, 45]
            }
        }
        self.slowerSuitPeriodsCurve = {
            2000: {
                4: [128, 65],
                8: [128, 78, 66, 64],
                12: [128, 88, 73, 67, 64, 64],
                16: [128, 94, 79, 71, 67, 65, 64, 64]
            },
            1000: {
                4: [110, 59],
                8: [110, 70, 60, 58],
                12: [110, 78, 66, 61, 59, 58],
                16: [110, 84, 72, 65, 61, 59, 58, 58]
            },
            5000: {
                4: [96, 55],
                8: [96, 64, 56, 54],
                12: [96, 71, 61, 56, 54, 54],
                16: [96, 76, 65, 59, 56, 55, 54, 54]
            },
            4000: {
                4: [86, 51],
                8: [86, 59, 52, 50],
                12: [86, 65, 56, 52, 50, 50],
                16: [86, 69, 60, 55, 52, 51, 50, 50]
            },
            3000: {
                4: [78, 47],
                8: [78, 55, 48, 47],
                12: [78, 60, 52, 48, 47, 47],
                16: [78, 63, 55, 51, 49, 47, 47, 47]
            },
            9000: {
                4: [71, 44],
                8: [71, 51, 45, 44],
                12: [71, 55, 48, 45, 44, 44],
                16: [71, 58, 51, 48, 45, 44, 44, 44]
            }
        }
        self.fasterSuitPeriods = {
            2000: {
                4: [54, 42],
                8: [59, 52, 47, 42],
                12: [61, 56, 52, 48, 45, 42],
                16: [61, 58, 54, 51, 49, 46, 44, 42]
            },
            1000: {
                4: [50, 40],
                8: [55, 48, 44, 40],
                12: [56, 52, 48, 45, 42, 40],
                16: [56, 53, 50, 48, 45, 43, 41, 40]
            },
            5000: {
                4: [47, 37],
                8: [51, 45, 41, 37],
                12: [52, 48, 45, 42, 39, 37],
                16: [52, 49, 47, 44, 42, 40, 39, 37]
            },
            4000: {
                4: [44, 35],
                8: [47, 42, 38, 35],
                12: [48, 45, 42, 39, 37, 35],
                16: [49, 46, 44, 42, 40, 38, 37, 35]
            },
            3000: {
                4: [41, 33],
                8: [44, 40, 36, 33],
                12: [45, 42, 39, 37, 35, 33],
                16: [45, 43, 41, 39, 38, 36, 35, 33]
            },
            9000: {
                4: [39, 32],
                8: [41, 37, 34, 32],
                12: [42, 40, 37, 35, 33, 32],
                16: [43, 41, 39, 37, 35, 34, 33, 32]
            }
        }
        self.fasterSuitPeriodsCurve = {
            2000: {
                4: [62, 42],
                8: [63, 61, 54, 42],
                12: [63, 63, 61, 56, 50, 42],
                16: [63, 63, 62, 60, 57, 53, 48, 42]
            },
            1000: {
                4: [57, 40],
                8: [58, 56, 50, 40],
                12: [58, 58, 56, 52, 46, 40],
                16: [58, 58, 57, 56, 53, 49, 45, 40]
            },
            5000: {
                4: [53, 37],
                8: [54, 52, 46, 37],
                12: [54, 53, 52, 48, 43, 37],
                16: [54, 54, 53, 51, 49, 46, 42, 37]
            },
            4000: {
                4: [49, 35],
                8: [50, 48, 43, 35],
                12: [50, 49, 48, 45, 41, 35],
                16: [50, 50, 49, 48, 46, 43, 39, 35]
            },
            3000: {
                4: [46, 33],
                8: [47, 45, 41, 33],
                12: [47, 46, 45, 42, 38, 33],
                16: [47, 46, 46, 45, 43, 40, 37, 33]
            },
            9000: {
                4: [43, 32],
                8: [44, 42, 38, 32],
                12: [44, 43, 42, 40, 36, 32],
                16: [44, 44, 43, 42, 40, 38, 35, 32]
            }
        }
        self.CELL_WIDTH = MazeData.CELL_WIDTH
        self.MAX_FRAME_MOVE = self.CELL_WIDTH / 2
        startOffset = 3
        self.startPosHTable = [[Point3(0, startOffset, self.TOON_Z), 0],
                               [Point3(0, -startOffset, self.TOON_Z), 180],
                               [Point3(startOffset, 0, self.TOON_Z), 270],
                               [Point3(-startOffset, 0, self.TOON_Z), 90]]
        self.camOffset = Vec3(0, -19, 45)

    def load(self):
        self.notify.debug('load')
        DistributedMinigame.load(self)
        self.__defineConstants()
        mazeName = MazeGameGlobals.getMazeName(self.doId, self.numPlayers,
                                               MazeData.mazeNames)
        self.maze = Maze.Maze(mazeName)
        model = loader.loadModel('phase_3.5/models/props/mickeySZ')
        self.treasureModel = model.find('**/mickeySZ')
        model.removeNode()
        self.treasureModel.setScale(1.6)
        self.treasureModel.setP(-90)
        self.music = base.loader.loadMusic('phase_4/audio/bgm/MG_toontag.ogg')
        self.toonHitTracks = {}
        self.scorePanels = []

    def unload(self):
        self.notify.debug('unload')
        DistributedMinigame.unload(self)
        del self.toonHitTracks
        self.maze.destroy()
        del self.maze
        self.treasureModel.removeNode()
        del self.treasureModel
        del self.music
        self.removeChildGameFSM(self.gameFSM)
        del self.gameFSM

    def onstage(self):
        self.notify.debug('onstage')
        DistributedMinigame.onstage(self)
        self.maze.onstage()
        self.randomNumGen.shuffle(self.startPosHTable)
        lt = base.localAvatar
        lt.reparentTo(render)
        lt.hideName()
        self.__placeToon(self.localAvId)
        lt.setAnimState('Happy', 1.0)
        lt.setSpeed(0, 0)
        self.camParent = render.attachNewNode('mazeGameCamParent')
        self.camParent.reparentTo(base.localAvatar)
        self.camParent.setPos(0, 0, 0)
        self.camParent.setHpr(render, 0, 0, 0)
        camera.reparentTo(self.camParent)
        camera.setPos(self.camOffset)
        self.__spawnCameraTask()
        self.toonRNGs = []
        for i in range(self.numPlayers):
            self.toonRNGs.append(RandomNumGen.RandomNumGen(self.randomNumGen))

        self.treasures = []
        for i in range(self.maze.numTreasures):
            self.treasures.append(
                MazeTreasure.MazeTreasure(self.treasureModel,
                                          self.maze.treasurePosList[i], i,
                                          self.doId))

        self.__loadSuits()
        for suit in self.suits:
            suit.onstage()

        self.sndTable = {
            'hitBySuit': [None] * self.numPlayers,
            'falling': [None] * self.numPlayers
        }
        for i in range(self.numPlayers):
            self.sndTable['hitBySuit'][i] = base.loader.loadSfx(
                'phase_4/audio/sfx/MG_Tag_C.ogg')
            self.sndTable['falling'][i] = base.loader.loadSfx(
                'phase_4/audio/sfx/MG_cannon_whizz.ogg')

        self.grabSounds = []
        for i in range(5):
            self.grabSounds.append(
                base.loader.loadSfx('phase_4/audio/sfx/MG_maze_pickup.ogg'))

        self.grabSoundIndex = 0
        for avId in self.avIdList:
            self.toonHitTracks[avId] = Wait(0.1)

        self.scores = [0] * self.numPlayers
        self.goalBar = DirectWaitBar(parent=render2d,
                                     relief=DGG.SUNKEN,
                                     frameSize=(-0.35, 0.35, -0.15, 0.15),
                                     borderWidth=(0.02, 0.02),
                                     scale=0.42,
                                     pos=(0.84, 0,
                                          0.5 - 0.28 * self.numPlayers + 0.05),
                                     barColor=(0, 0.7, 0, 1))
        self.goalBar.setBin('unsorted', 0)
        self.goalBar.hide()
        self.introTrack = self.getIntroTrack()
        self.introTrack.start()
        return

    def offstage(self):
        self.notify.debug('offstage')
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        del self.introTrack
        for avId in list(self.toonHitTracks.keys()):
            track = self.toonHitTracks[avId]
            if track.isPlaying():
                track.finish()

        self.__killCameraTask()
        camera.wrtReparentTo(render)
        self.camParent.removeNode()
        del self.camParent
        for panel in self.scorePanels:
            panel.cleanup()

        self.scorePanels = []
        self.goalBar.destroy()
        del self.goalBar
        base.setCellsAvailable(base.rightCells, 1)
        for suit in self.suits:
            suit.offstage()

        self.__unloadSuits()
        for treasure in self.treasures:
            treasure.destroy()

        del self.treasures
        del self.sndTable
        del self.grabSounds
        del self.toonRNGs
        self.maze.offstage()
        base.localAvatar.showName()
        DistributedMinigame.offstage(self)

    def __placeToon(self, avId):
        toon = self.getAvatar(avId)
        if self.numPlayers == 1:
            toon.setPos(0, 0, self.TOON_Z)
            toon.setHpr(180, 0, 0)
        else:
            posIndex = self.avIdList.index(avId)
            toon.setPos(self.startPosHTable[posIndex][0])
            toon.setHpr(self.startPosHTable[posIndex][1], 0, 0)

    def setGameReady(self):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameReady')
        if DistributedMinigame.setGameReady(self):
            return
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.reparentTo(render)
                self.__placeToon(avId)
                toon.setAnimState('Happy', 1.0)
                toon.startSmooth()
                toon.startLookAround()

    def setGameStart(self, timestamp):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameStart')
        DistributedMinigame.setGameStart(self, timestamp)
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.stopLookAround()

        self.gameFSM.request('play')

    def handleDisabledAvatar(self, avId):
        hitTrack = self.toonHitTracks[avId]
        if hitTrack.isPlaying():
            hitTrack.finish()
        DistributedMinigame.handleDisabledAvatar(self, avId)

    def enterOff(self):
        self.notify.debug('enterOff')

    def exitOff(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')
        for i in range(self.numPlayers):
            avId = self.avIdList[i]
            avName = self.getAvatarName(avId)
            scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(
                avId, avName)
            scorePanel.setPos(1.12, 0.0, 0.5 - 0.28 * i)
            self.scorePanels.append(scorePanel)

        self.goalBar.show()
        self.goalBar['value'] = 0.0
        base.setCellsAvailable(base.rightCells, 0)
        self.__spawnUpdateSuitsTask()
        orthoDrive = OrthoDrive(
            self.TOON_SPEED,
            maxFrameMove=self.MAX_FRAME_MOVE,
            customCollisionCallback=self.__doMazeCollisions,
            priority=1)
        self.orthoWalk = OrthoWalk(orthoDrive,
                                   broadcast=not self.isSinglePlayer())
        self.orthoWalk.start()
        self.accept(MazeSuit.COLLISION_EVENT_NAME, self.__hitBySuit)
        self.accept(self.TREASURE_GRAB_EVENT_NAME, self.__treasureGrabbed)
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.posInTopRightCorner()
        self.timer.setTime(MazeGameGlobals.GAME_DURATION)
        self.timer.countdown(MazeGameGlobals.GAME_DURATION, self.timerExpired)
        self.accept('resetClock', self.__resetClock)
        base.playMusic(self.music, looping=0, volume=0.8)

    def exitPlay(self):
        self.notify.debug('exitPlay')
        self.ignore('resetClock')
        self.ignore(MazeSuit.COLLISION_EVENT_NAME)
        self.ignore(self.TREASURE_GRAB_EVENT_NAME)
        self.orthoWalk.stop()
        self.orthoWalk.destroy()
        del self.orthoWalk
        self.__killUpdateSuitsTask()
        self.timer.stop()
        self.timer.destroy()
        del self.timer
        for avId in self.avIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.loop('neutral')

    def __resetClock(self, tOffset):
        self.notify.debug('resetClock')
        self.gameStartTime += tOffset
        self.timer.countdown(self.timer.currentTime + tOffset,
                             self.timerExpired)

    def __treasureGrabbed(self, treasureNum):
        self.treasures[treasureNum].showGrab()
        self.grabSounds[self.grabSoundIndex].play()
        self.grabSoundIndex = (self.grabSoundIndex + 1) % len(self.grabSounds)
        self.sendUpdate('claimTreasure', [treasureNum])

    def setTreasureGrabbed(self, avId, treasureNum):
        if not self.hasLocalToon:
            return
        if avId != self.localAvId:
            self.treasures[treasureNum].showGrab()
        i = self.avIdList.index(avId)
        self.scores[i] += 1
        self.scorePanels[i].setScore(self.scores[i])
        total = 0
        for score in self.scores:
            total += score

        self.goalBar['value'] = 100.0 * (float(total) /
                                         float(self.maze.numTreasures))

    def __hitBySuit(self, suitNum):
        self.notify.debug('hitBySuit')
        timestamp = globalClockDelta.localToNetworkTime(
            globalClock.getFrameTime())
        self.sendUpdate('hitBySuit', [self.localAvId, timestamp])
        self.__showToonHitBySuit(self.localAvId, timestamp)

    def hitBySuit(self, avId, timestamp):
        if not self.hasLocalToon:
            return
        if self.gameFSM.getCurrentState().getName() not in [
                'play', 'showScores'
        ]:
            self.notify.warning('ignoring msg: av %s hit by suit' % avId)
            return
        self.notify.debug('avatar ' + repr(avId) + ' hit by a suit')
        if avId != self.localAvId:
            self.__showToonHitBySuit(avId, timestamp)

    def __showToonHitBySuit(self, avId, timestamp):
        toon = self.getAvatar(avId)
        if toon == None:
            return
        rng = self.toonRNGs[self.avIdList.index(avId)]
        curPos = toon.getPos(render)
        oldTrack = self.toonHitTracks[avId]
        if oldTrack.isPlaying():
            oldTrack.finish()
        toon.setPos(curPos)
        toon.setZ(self.TOON_Z)
        parentNode = render.attachNewNode('mazeFlyToonParent-' + repr(avId))
        parentNode.setPos(toon.getPos())
        toon.reparentTo(parentNode)
        toon.setPos(0, 0, 0)
        startPos = parentNode.getPos()
        dropShadow = toon.dropShadow.copyTo(parentNode)
        dropShadow.setScale(toon.dropShadow.getScale(render))
        trajectory = Trajectory.Trajectory(0,
                                           Point3(0, 0, 0),
                                           Point3(0, 0, 50),
                                           gravMult=1.0)
        flyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        while 1:
            endTile = [
                rng.randint(2, self.maze.width - 1),
                rng.randint(2, self.maze.height - 1)
            ]
            if self.maze.isWalkable(endTile[0], endTile[1]):
                break
        endWorldCoords = self.maze.tile2world(endTile[0], endTile[1])
        endPos = Point3(endWorldCoords[0], endWorldCoords[1], startPos[2])

        def flyFunc(t,
                    trajectory,
                    startPos=startPos,
                    endPos=endPos,
                    dur=flyDur,
                    moveNode=parentNode,
                    flyNode=toon):
            u = t / dur
            moveNode.setX(startPos[0] + u * (endPos[0] - startPos[0]))
            moveNode.setY(startPos[1] + u * (endPos[1] - startPos[1]))
            flyNode.setPos(trajectory.getPos(t))

        flyTrack = Sequence(LerpFunctionInterval(flyFunc,
                                                 fromData=0.0,
                                                 toData=flyDur,
                                                 duration=flyDur,
                                                 extraArgs=[trajectory]),
                            name=toon.uniqueName('hitBySuit-fly'))
        if avId != self.localAvId:
            cameraTrack = Sequence()
        else:
            self.camParent.reparentTo(parentNode)
            startCamPos = camera.getPos()
            destCamPos = camera.getPos()
            zenith = trajectory.getPos(flyDur / 2.0)[2]
            destCamPos.setZ(zenith * 1.3)
            destCamPos.setY(destCamPos[1] * 0.3)

            def camTask(task,
                        zenith=zenith,
                        flyNode=toon,
                        startCamPos=startCamPos,
                        camOffset=destCamPos - startCamPos):
                u = flyNode.getZ() / zenith
                camera.setPos(startCamPos + camOffset * u)
                camera.lookAt(toon)
                return Task.cont

            camTaskName = 'mazeToonFlyCam-' + repr(avId)
            taskMgr.add(camTask, camTaskName, priority=20)

            def cleanupCamTask(self=self,
                               toon=toon,
                               camTaskName=camTaskName,
                               startCamPos=startCamPos):
                taskMgr.remove(camTaskName)
                self.camParent.reparentTo(toon)
                camera.setPos(startCamPos)
                camera.lookAt(toon)

            cameraTrack = Sequence(Wait(flyDur),
                                   Func(cleanupCamTask),
                                   name='hitBySuit-cameraLerp')

        geomNode = toon.getGeomNode()
        startHpr = geomNode.getHpr()
        destHpr = Point3(startHpr)
        hRot = rng.randrange(1, 8)
        if rng.choice([0, 1]):
            hRot = -hRot
        destHpr.setX(destHpr[0] + hRot * 360)
        spinHTrack = Sequence(LerpHprInterval(geomNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(geomNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinH'))
        parent = geomNode.getParent()
        rotNode = parent.attachNewNode('rotNode')
        geomNode.reparentTo(rotNode)
        rotNode.setZ(toon.getHeight() / 2.0)
        oldGeomNodeZ = geomNode.getZ()
        geomNode.setZ(-toon.getHeight() / 2.0)
        startHpr = rotNode.getHpr()
        destHpr = Point3(startHpr)
        pRot = rng.randrange(1, 3)
        if rng.choice([0, 1]):
            pRot = -pRot
        destHpr.setY(destHpr[1] + pRot * 360)
        spinPTrack = Sequence(LerpHprInterval(rotNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(rotNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinP'))
        i = self.avIdList.index(avId)
        soundTrack = Sequence(Func(base.playSfx,
                                   self.sndTable['hitBySuit'][i]),
                              Wait(flyDur * (2.0 / 3.0)),
                              SoundInterval(self.sndTable['falling'][i],
                                            duration=flyDur * (1.0 / 3.0)),
                              name=toon.uniqueName('hitBySuit-soundTrack'))

        def preFunc(self=self, avId=avId, toon=toon, dropShadow=dropShadow):
            forwardSpeed = toon.forwardSpeed
            rotateSpeed = toon.rotateSpeed
            if avId == self.localAvId:
                self.orthoWalk.stop()
            else:
                toon.stopSmooth()
            if forwardSpeed or rotateSpeed:
                toon.setSpeed(forwardSpeed, rotateSpeed)
            toon.dropShadow.hide()

        def postFunc(self=self,
                     avId=avId,
                     oldGeomNodeZ=oldGeomNodeZ,
                     dropShadow=dropShadow,
                     parentNode=parentNode):
            if avId == self.localAvId:
                base.localAvatar.setPos(endPos)
                if hasattr(self, 'orthoWalk'):
                    if self.gameFSM.getCurrentState().getName() == 'play':
                        self.orthoWalk.start()
            dropShadow.removeNode()
            del dropShadow
            toon.dropShadow.show()
            geomNode = toon.getGeomNode()
            rotNode = geomNode.getParent()
            baseNode = rotNode.getParent()
            geomNode.reparentTo(baseNode)
            rotNode.removeNode()
            del rotNode
            geomNode.setZ(oldGeomNodeZ)
            toon.reparentTo(render)
            toon.setPos(endPos)
            parentNode.removeNode()
            del parentNode
            if avId != self.localAvId:
                toon.startSmooth()

        preFunc()

        hitTrack = Sequence(Parallel(flyTrack, cameraTrack, spinHTrack,
                                     spinPTrack, soundTrack),
                            Func(postFunc),
                            name=toon.uniqueName('hitBySuit'))

        self.toonHitTracks[avId] = hitTrack

        hitTrack.start(globalClockDelta.localElapsedTime(timestamp))

    def allTreasuresTaken(self):
        if not self.hasLocalToon:
            return
        self.notify.debug('all treasures taken')
        if not MazeGameGlobals.ENDLESS_GAME:
            self.gameFSM.request('showScores')

    def timerExpired(self):
        self.notify.debug('local timer expired')
        if not MazeGameGlobals.ENDLESS_GAME:
            self.gameFSM.request('showScores')

    def __doMazeCollisions(self, oldPos, newPos):
        offset = newPos - oldPos
        WALL_OFFSET = 1.0
        curX = oldPos[0]
        curY = oldPos[1]
        curTX, curTY = self.maze.world2tile(curX, curY)

        def calcFlushCoord(curTile, newTile, centerTile):
            EPSILON = 0.01
            if newTile > curTile:
                return (newTile -
                        centerTile) * self.CELL_WIDTH - EPSILON - WALL_OFFSET
            else:
                return (curTile - centerTile) * self.CELL_WIDTH + WALL_OFFSET

        offsetX = offset[0]
        offsetY = offset[1]
        WALL_OFFSET_X = WALL_OFFSET
        if offsetX < 0:
            WALL_OFFSET_X = -WALL_OFFSET_X
        WALL_OFFSET_Y = WALL_OFFSET
        if offsetY < 0:
            WALL_OFFSET_Y = -WALL_OFFSET_Y
        newX = curX + offsetX + WALL_OFFSET_X
        newY = curY
        newTX, newTY = self.maze.world2tile(newX, newY)
        if newTX != curTX:
            if self.maze.collisionTable[newTY][newTX]:
                offset.setX(
                    calcFlushCoord(curTX, newTX, self.maze.originTX) - curX)
        newX = curX
        newY = curY + offsetY + WALL_OFFSET_Y
        newTX, newTY = self.maze.world2tile(newX, newY)
        if newTY != curTY:
            if self.maze.collisionTable[newTY][newTX]:
                offset.setY(
                    calcFlushCoord(curTY, newTY, self.maze.originTY) - curY)
        offsetX = offset[0]
        offsetY = offset[1]
        newX = curX + offsetX + WALL_OFFSET_X
        newY = curY + offsetY + WALL_OFFSET_Y
        newTX, newTY = self.maze.world2tile(newX, newY)
        if self.maze.collisionTable[newTY][newTX]:
            cX = calcFlushCoord(curTX, newTX, self.maze.originTX)
            cY = calcFlushCoord(curTY, newTY, self.maze.originTY)
            if abs(cX - curX) < abs(cY - curY):
                offset.setX(cX - curX)
            else:
                offset.setY(cY - curY)
        return oldPos + offset

    def __spawnCameraTask(self):
        self.notify.debug('spawnCameraTask')
        camera.lookAt(base.localAvatar)
        taskMgr.remove(self.CAMERA_TASK)
        taskMgr.add(self.__cameraTask, self.CAMERA_TASK, priority=45)

    def __killCameraTask(self):
        self.notify.debug('killCameraTask')
        taskMgr.remove(self.CAMERA_TASK)

    def __cameraTask(self, task):
        self.camParent.setHpr(render, 0, 0, 0)
        return Task.cont

    def __loadSuits(self):
        self.notify.debug('loadSuits')
        self.suits = []
        self.numSuits = 4 * self.numPlayers
        safeZone = self.getSafezoneId()
        slowerTable = self.slowerSuitPeriods
        if self.SLOWER_SUIT_CURVE:
            slowerTable = self.slowerSuitPeriodsCurve
        slowerPeriods = slowerTable[safeZone][self.numSuits]
        fasterTable = self.fasterSuitPeriods
        if self.FASTER_SUIT_CURVE:
            fasterTable = self.fasterSuitPeriodsCurve
        fasterPeriods = fasterTable[safeZone][self.numSuits]
        suitPeriods = slowerPeriods + fasterPeriods
        self.notify.debug('suit periods: ' + repr(suitPeriods))
        self.randomNumGen.shuffle(suitPeriods)
        for i in range(self.numSuits):
            self.suits.append(
                MazeSuit(i, self.maze, self.randomNumGen, suitPeriods[i],
                         self.getDifficulty()))

    def __unloadSuits(self):
        self.notify.debug('unloadSuits')
        for suit in self.suits:
            suit.destroy()

        del self.suits

    def __spawnUpdateSuitsTask(self):
        self.notify.debug('spawnUpdateSuitsTask')
        for suit in self.suits:
            suit.gameStart(self.gameStartTime)

        taskMgr.remove(self.UPDATE_SUITS_TASK)
        taskMgr.add(self.__updateSuitsTask, self.UPDATE_SUITS_TASK)

    def __killUpdateSuitsTask(self):
        self.notify.debug('killUpdateSuitsTask')
        taskMgr.remove(self.UPDATE_SUITS_TASK)
        for suit in self.suits:
            suit.gameEnd()

    def __updateSuitsTask(self, task):
        curT = globalClock.getFrameTime() - self.gameStartTime
        curTic = int(curT * float(MazeGameGlobals.SUIT_TIC_FREQ))
        suitUpdates = []
        for i in range(len(self.suits)):
            updateTics = self.suits[i].getThinkTimestampTics(curTic)
            suitUpdates.extend(list(zip(updateTics, [i] * len(updateTics))))

        suitUpdates.sort(key=functools.cmp_to_key(lambda a, b: a[0] - b[0]))
        if len(suitUpdates) > 0:
            curTic = 0
            for i in range(len(suitUpdates)):
                update = suitUpdates[i]
                tic = update[0]
                suitIndex = update[1]
                suit = self.suits[suitIndex]
                if tic > curTic:
                    curTic = tic
                    j = i + 1
                    while j < len(suitUpdates):
                        if suitUpdates[j][0] > tic:
                            break
                        self.suits[suitUpdates[j][1]].prepareToThink()
                        j += 1

                unwalkables = []
                for si in range(suitIndex):
                    unwalkables.extend(self.suits[si].occupiedTiles)

                for si in range(suitIndex + 1, len(self.suits)):
                    unwalkables.extend(self.suits[si].occupiedTiles)

                suit.think(curTic, curT, unwalkables)

        return Task.cont

    def enterShowScores(self):
        self.notify.debug('enterShowScores')
        lerpTrack = Parallel()
        lerpDur = 0.5
        lerpTrack.append(
            Parallel(
                LerpPosInterval(self.goalBar,
                                lerpDur,
                                Point3(0, 0, -.6),
                                blendType='easeInOut'),
                LerpScaleInterval(self.goalBar,
                                  lerpDur,
                                  Vec3(self.goalBar.getScale()) * 2.0,
                                  blendType='easeInOut')))
        tY = 0.6
        bY = -.05
        lX = -.5
        cX = 0
        rX = 0.5
        scorePanelLocs = (((cX, bY), ), ((lX, bY), (rX, bY)),
                          ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY),
                                                           (lX, bY), (rX, bY)))
        scorePanelLocs = scorePanelLocs[self.numPlayers - 1]
        for i in range(self.numPlayers):
            panel = self.scorePanels[i]
            pos = scorePanelLocs[i]
            lerpTrack.append(
                Parallel(
                    LerpPosInterval(panel,
                                    lerpDur,
                                    Point3(pos[0], 0, pos[1]),
                                    blendType='easeInOut'),
                    LerpScaleInterval(panel,
                                      lerpDur,
                                      Vec3(panel.getScale()) * 2.0,
                                      blendType='easeInOut')))

        self.showScoreTrack = Parallel(
            lerpTrack,
            Sequence(Wait(MazeGameGlobals.SHOWSCORES_DURATION),
                     Func(self.gameOver)))
        self.showScoreTrack.start()

    def exitShowScores(self):
        self.showScoreTrack.pause()
        del self.showScoreTrack

    def enterCleanup(self):
        self.notify.debug('enterCleanup')

    def exitCleanup(self):
        pass

    def getIntroTrack(self):
        self.__cameraTask(None)
        origCamParent = camera.getParent()
        origCamPos = camera.getPos()
        origCamHpr = camera.getHpr()
        iCamParent = base.localAvatar.attachNewNode('iCamParent')
        iCamParent.setH(180)
        camera.reparentTo(iCamParent)
        toonHeight = base.localAvatar.getHeight()
        camera.setPos(0, -15, toonHeight * 3)
        camera.lookAt(0, 0, toonHeight / 2.0)
        iCamParent.wrtReparentTo(origCamParent)
        waitDur = 5.0
        lerpDur = 4.5
        lerpTrack = Parallel()
        startHpr = iCamParent.getHpr()
        startHpr.setX(PythonUtil.reduceAngle(startHpr[0]))
        lerpTrack.append(
            LerpPosHprInterval(iCamParent,
                               lerpDur,
                               pos=Point3(0, 0, 0),
                               hpr=Point3(0, 0, 0),
                               startHpr=startHpr,
                               name=self.uniqueName('introLerpParent')))
        lerpTrack.append(
            LerpPosHprInterval(camera,
                               lerpDur,
                               pos=origCamPos,
                               hpr=origCamHpr,
                               blendType='easeInOut',
                               name=self.uniqueName('introLerpCameraPos')))
        base.localAvatar.startLookAround()

        def cleanup(origCamParent=origCamParent,
                    origCamPos=origCamPos,
                    origCamHpr=origCamHpr,
                    iCamParent=iCamParent):
            camera.reparentTo(origCamParent)
            camera.setPos(origCamPos)
            camera.setHpr(origCamHpr)
            iCamParent.removeNode()
            del iCamParent
            base.localAvatar.stopLookAround()

        return Sequence(Wait(waitDur), lerpTrack, Func(cleanup))
class PartyCogActivityGui(DirectObject):
    notify = directNotify.newCategory('PartyCogActivityGui')

    def __init__(self):
        DirectObject.__init__(self)
        self._piePowerMeter = None
        self._victoryBalanceBar = None
        self._scoreLabel = None
        self._cogTracker = None
        self._piePowerTitle = None
        self._victoryBalanceTitle = None
        self._scoreTitle = None
        self._spamWarning = None
        self._spamWarningIvalName = 'PartyCogActivityGui-SpamWarning'

    def load(self):
        self._initPiePowerMeter()
        self._initScore()
        self._initCogTracker()
        self._initSpamWarning()
        self._initControlGui()
        self._initVictoryBalanceBar()

    def unload(self):
        if self._cogTracker is not None:
            self._cogTracker.destory()
            self._cogTracker = None
        if self._piePowerMeter is not None:
            self._piePowerMeter.destroy()
            self._piePowerMeter = None
        if self._piePowerTitle is not None:
            self._piePowerTitle.destroy()
            self._piePowerTitle = None
        if self._scoreLabel is not None:
            self._scoreLabel.destroy()
            self._scoreLabel = None
        if self._scoreTitle is not None:
            self._scoreTitle.destroy()
            self._scoreTitle = None
        taskMgr.remove(self._spamWarningIvalName)
        if self._spamWarning:
            self._spamWarning.destroy()
            self._spamWarning = None
        if hasattr(self, '_attackKeys'):
            self._attackKeys.detachNode()
            del self._attackKeys
        if hasattr(self, '_moveKeys'):
            self._moveKeys.detachNode()
            del self._moveKeys
        if self._victoryBalanceBar:
            self._victoryBalanceBar.detachNode()
            self._victoryBalanceBar = None
        if self._victoryBalanceBarOrange:
            self._victoryBalanceBarOrange.detachNode()
            self._victoryBalanceBarOrange = None
        if self._victoryBalanceBarPie:
            self._victoryBalanceBarPie.detachNode()
            self._victoryBalanceBarPie = None
        if self._victoryBalanceBarArrow:
            self._victoryBalanceBarArrow.detachNode()
            self._victoryBalanceBarArrow = None

    def _initVictoryBalanceBar(self):
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
        victoryBalanceBar = loader.loadModel('phase_13/models/parties/tt_m_gui_pty_pieToss_balanceBar')
        self._victoryBalanceBar = victoryBalanceBar.find('**/*tt_t_gui_pty_pieToss_balanceBarBG')
        self._victoryBalanceBar.reparentTo(aspect2d)
        self._victoryBalanceBar.setBin('fixed', 0)
        self._victoryBalanceBar.setPos(PartyGlobals.CogActivityVictoryBarPos)
        self._victoryBalanceBar.setScale(1)
        self._victoryBalanceBarOrange = victoryBalanceBar.find('**/*tt_t_gui_pty_pieToss_balanceBarOrange')
        self._victoryBalanceBarOrange.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarOrange.setBin('fixed', 1)
        self._victoryBalanceBarOrange.setPos(PartyGlobals.CogActivityVictoryBarOrangePos)
        self._victoryBalanceBarOrange.setScale(PartyGlobals.CogActivityBarStartScale, 1.0, 1.0)
        self._victoryBalanceBarPie = victoryBalanceBar.find('**/*tt_t_gui_pty_pieToss_balanceBarPie')
        self._victoryBalanceBarPie.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarPie.setBin('fixed', 2)
        self._victoryBalanceBarPie.setX(PartyGlobals.CogActivityVictoryBarPiePos[0])
        self._victoryBalanceBarPie.setY(PartyGlobals.CogActivityVictoryBarPiePos[1])
        self._victoryBalanceBarPie.setZ(PartyGlobals.CogActivityVictoryBarPiePos[2])
        self._victoryBalanceBarPie.setScale(PartyGlobals.CogActivityBarPieScale)
        self._victoryBalanceBarArrow = victoryBalanceBar.find('**/*tt_t_gui_pty_pieToss_balanceArrow')
        self._victoryBalanceBarArrow.reparentTo(self._victoryBalanceBarPie)
        self._victoryBalanceBarArrow.setBin('fixed', 2)
        self._victoryBalanceBarArrow.setPos(PartyGlobals.CogActivityVictoryBarArrow)
        self._victoryBalanceBarArrow.setScale(1 / PartyGlobals.CogActivityBarPieScale)

    def _initControlGui(self):
        self._attackIvalName = 'PartyCogActivityGui-attackKeys'
        self._moveIvalName = 'PartyCogActivityGui-moveKeys'
        pieTossControls = loader.loadModel('phase_13/models/parties/tt_m_gui_pty_pieToss_controls')
        self._attackKeys = pieTossControls.find('**/*control*')
        self._moveKeys = pieTossControls.find('**/*arrow*')
        self._moveKeys.reparentTo(aspect2d)
        self._moveKeys.setPos(1.0, 0.0, -0.435)
        self._moveKeys.setScale(0.15)
        self._attackKeys.reparentTo(aspect2d)
        self._attackKeys.setPos(0.85, 0.0, -0.45)
        self._attackKeys.setScale(0.15)
        self._moveKeys.hide()
        self._attackKeys.hide()

    def _initPiePowerMeter(self):
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
        self._piePowerMeter = DirectWaitBar(frameSize=(-h,
         h,
         -w,
         w), relief=DGG.GROOVE, frameColor=(0.9, 0.9, 0.9, 1.0), borderWidth=(0.01, 0.01), barColor=PartyGlobals.CogActivityColors[0], pos=PartyGlobals.CogActivityPowerMeterPos, hpr=(0.0, 0.0, -90.0))
        self._piePowerMeter.setBin('fixed', 0)
        self._piePowerTitle = OnscreenText(text=TTLocalizer.PartyCogGuiPowerLabel, pos=PartyGlobals.CogActivityPowerMeterTextPos, scale=0.05, fg=(1.0, 1.0, 1.0, 1.0), align=TextNode.ACenter)
        self._piePowerTitle.setBin('fixed', 0)
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()

    def _initScore(self):
        self._scoreLabel = OnscreenText(text='0', pos=PartyGlobals.CogActivityScorePos, scale=PartyGlobals.TugOfWarTextWordScale, fg=(1.0, 1.0, 0.0, 1.0), align=TextNode.ARight, font=ToontownGlobals.getSignFont(), mayChange=True)
        self._scoreTitle = OnscreenText(text=TTLocalizer.PartyCogGuiScoreLabel, pos=PartyGlobals.CogActivityScoreTitle, scale=0.05, fg=(1.0, 1.0, 1.0, 1.0), align=TextNode.ARight)
        self._scoreLabel.hide()
        self._scoreTitle.hide()

    def _initCogTracker(self):
        self._cogTracker = PartyCogTrackerGui()

    def _initSpamWarning(self):
        self._spamWarning = OnscreenText(text=TTLocalizer.PartyCogGuiSpamWarning, scale=0.15, fg=(1.0, 1.0, 0, 1.0), shadow=(0, 0, 0, 0.62), mayChange=False, pos=(0, 0.33))
        self._spamWarning.hide()

    def showScore(self):
        self._scoreLabel.show()
        self._scoreTitle.show()

    def hideScore(self):
        self._scoreLabel.hide()
        self._scoreTitle.hide()

    def setScore(self, score = 0):
        self._scoreLabel['text'] = str(score)

    def resetPiePowerMeter(self):
        self._piePowerMeter['value'] = 0

    def showPiePowerMeter(self):
        self._piePowerMeter.show()
        self._piePowerTitle.show()

    def hidePiePowerMeter(self):
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()

    def updatePiePowerMeter(self, value):
        self._piePowerMeter['value'] = value

    def getPiePowerMeterValue(self):
        return self._piePowerMeter['value']

    def hideSpamWarning(self):
        taskMgr.remove(self._spamWarningIvalName)
        if self._spamWarning:
            self._spamWarning.hide()

    def showSpamWarning(self):
        if self._spamWarning.isHidden():
            self._spamWarning.show()
            taskMgr.remove(self._spamWarningIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(self._spamWarning, ''), Wait(PartyGlobals.CogActivitySpamWarningShowTime), Func(self.hideSpamWarning), name=self._spamWarningIvalName, autoFinish=1).start()

    def hide(self):
        self.hidePiePowerMeter()
        self.hideScore()
        self.hideSpamWarning()
        self.hideControls()

    def disableToontownHUD(self):
        base.localAvatar.hideName()
        base.localAvatar.laffMeter.hide()
        base.setCellsAvailable(base.bottomCells + [base.rightCells[1]], False)

    def enableToontownHUD(self):
        base.localAvatar.showName()
        base.localAvatar.laffMeter.show()
        base.setCellsAvailable(base.bottomCells + [base.rightCells[1]], True)

    def setTeam(self, team):
        self.team = team
        if team == 0:
            self._cogTracker.frame.setR(180)
        self._piePowerMeter['barColor'] = PartyGlobals.CogActivityColors[team]

    def startTrackingCogs(self, cogs):
        self.cogs = cogs
        taskMgr.add(self.trackCogs, 'trackCogs')

    def trackCogs(self, task):
        if self.cogs is None:
            return
        self._updateVictoryBar()
        for i, cog in enumerate(self.cogs):
            self._cogTracker.updateCog(i, cog, self.team)

        return task.cont

    def _updateVictoryBar(self):
        if not (hasattr(self, '_victoryBalanceBar') and self._victoryBalanceBar):
            return
        netDistance = 0
        for cog in self.cogs:
            netDistance = netDistance + cog.targetDistance

        teamDistance = netDistance / 6.0
        self._victoryBalanceBarOrange.setScale(PartyGlobals.CogActivityBarStartScale + teamDistance * 10 * PartyGlobals.CogActivityBarUnitScale, 1.0, 1.0)
        self._victoryBalanceBarPie.setX(PartyGlobals.CogActivityVictoryBarPiePos[0] + teamDistance * 10 * PartyGlobals.CogActivityBarPieUnitMove)
        self._victoryBalanceBarPie.setY(PartyGlobals.CogActivityVictoryBarPiePos[1])
        self._victoryBalanceBarPie.setZ(PartyGlobals.CogActivityVictoryBarPiePos[2])
        if teamDistance > 0.0:
            self._victoryBalanceBarArrow.setColor(PartyGlobals.CogActivityColors[1])
        elif teamDistance < 0.0:
            self._victoryBalanceBarArrow.setColor(PartyGlobals.CogActivityColors[0])
        else:
            self._victoryBalanceBarArrow.setColor(VBase4(1.0, 1.0, 1.0, 1.0))

    def stopTrackingCogs(self):
        taskMgr.remove('trackCogs')

    def showAttackControls(self):
        if self._attackKeys.isHidden():
            self._attackKeys.show()
            taskMgr.remove(self._attackIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(self._attackKeys, '', scale=0.15), Wait(PartyGlobals.CogActivityControlsShowTime), Func(self.hideAttackControls), name=self._attackIvalName, autoFinish=1).start()

    def showMoveControls(self):
        if self._moveKeys.isHidden() and not self._attackKeys.isHidden():
            self._moveKeys.show()
            taskMgr.remove(self._moveIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(self._moveKeys, '', scale=0.15), Wait(PartyGlobals.CogActivityControlsShowTime), Func(self.hideMoveControls), name=self._moveIvalName, autoFinish=1).start()

    def hideAttackControls(self):
        taskMgr.remove(self._attackIvalName)
        if hasattr(self, '_attackKeys') and self._attackKeys:
            self._attackKeys.hide()

    def hideMoveControls(self):
        taskMgr.remove(self._moveIvalName)
        if hasattr(self, '_moveKeys') and self._moveKeys:
            self._moveKeys.hide()

    def hideControls(self):
        self.hideMoveControls()
        self.hideAttackControls()
Пример #18
0
class CharacterGUI:
    """Widget with the selected character info."""

    def __init__(self):
        self.char = None  # the chosen character
        self.rest_list_shown = False
        self._status_lab = None
        self._rest_buttons = {}
        self._char_desc_wids = []
        self._char_desc_shown = False

        self._fr = DirectFrame(
            parent=base.a2dTopLeft,  # noqa: F821
            frameSize=(-0.31, 0.31, -0.1, 0.115),
            pos=(0.31, 0, -1.9),
            frameTexture=GUI_PIC + "metal1.png",
            state=DGG.NORMAL,
        )
        self._fr.setTransparency(TransparencyAttrib.MAlpha)

        # a "?" button to open a detailed description of the character
        self._char_desc_but = DirectButton(
            parent=self._fr,
            pos=(0.27, 0, 0.0675),
            command=self._show_char_desc,
            clickSound=base.main_menu.click_snd,  # noqa: F821
            **ABOUT_BUT_PARAMS,
        )
        DirectLabel(  # Name:
            parent=self._fr,
            text=base.labels.CHARACTERS[0],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.22, 0, 0.07),
        )
        self._char_name = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=SILVER_COL,
            pos=(-0.09, 0, 0.069),
        )
        self._traits = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=(0.028, 0.028),
            text_fg=SILVER_COL,
            text_font=base.main_font,  # noqa: F821
            pos=(0, 0, 0.025),
        )
        DirectLabel(  # Class:
            parent=self._fr,
            text=base.labels.CHARACTERS[1],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(0.05, 0, 0.07),
        )
        self._char_class = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=SILVER_COL,
            pos=(0.17, 0, 0.068),
        )
        DirectLabel(  # Health
            parent=self._fr,
            text=base.labels.CHARACTERS[2],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.22, 0, -0.015),
        )
        self._char_health = DirectWaitBar(
            parent=self._fr,
            frameSize=(-0.17, 0.17, -0.002, 0.002),
            frameColor=(0.35, 0.35, 0.35, 1),
            value=0,
            barColor=(0.85, 0.2, 0.28, 1),
            pos=(0.07, 0, -0.008),
        )
        DirectLabel(  # Energy
            parent=self._fr,
            text=base.labels.CHARACTERS[3],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.216, 0, -0.06),
        )
        self._char_energy = DirectWaitBar(
            parent=self._fr,
            frameSize=(-0.17, 0.17, -0.002, 0.002),
            frameColor=(0.35, 0.35, 0.35, 1),
            value=0,
            barColor=(0.46, 0.61, 0.53, 1),
            pos=(0.07, 0, -0.053),
        )
        self._tip = OnscreenText(
            parent=base.render2d,  # noqa: F821
            text="",
            font=base.main_font,  # noqa: F821
            scale=(0.021, 0.027),
            fg=SILVER_COL,
            bg=(0, 0, 0, 0.4),
        )
        self._tip.hide()

        self._disease = DirectFrame(
            parent=self._fr,
            frameSize=(-0.02, 0.02, -0.02, 0.02),
            pos=(0.27, 0, -0.008),
            frameTexture=GUI_PIC + "disease.png",
        )
        self._disease.setTransparency(TransparencyAttrib.MAlpha)

        self.clear_char_info()

    def _update_char_info(self, task):
        """Track the chosen character parameters in the GUI."""
        if self.char.is_dead:
            self.clear_char_info()
            return task.done

        self._char_health["value"] = self.char.health
        self._char_energy["value"] = self.char.energy
        self._traits["text"] = ", ".join(self.char.traits)

        if self.char.is_diseased:
            self._disease.show()
        else:
            self._disease.hide()

        if self._char_desc_shown:
            self._update_desc()

        return task.again

    def _update_desc(self):
        """Update the chosen character description."""
        to_del = []
        for wid in self._char_desc_wids:
            if wid["text"] not in (
                # Traits
                base.labels.CHARACTERS[5],  # noqa: F821
                # Status
                base.labels.CHARACTERS[4],  # noqa: F821
                "",
            ):
                wid.destroy()
                to_del.append(wid)

        for del_wid in to_del:
            self._char_desc_wids.remove(del_wid)

        self._fill_status(self._fill_traits(0.64))

    def _fill_traits(self, shift):
        """Fill the chosen character traits.

        Args:
            shift (float): Z-coor for the new widgets.

        Returns:
            float: Z-coor including the new widgets shift.
        """
        shift -= 0.03
        for trait in self.char.traits + self.char.disabled_traits:
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=trait,
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.03,
                    text_font=base.main_font,  # noqa: F821
                    text_fg=SILVER_COL
                    if trait in self.char.traits
                    else (0.3, 0.3, 0.3, 1),
                    pos=(0, 0, shift),
                )
            )
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=base.labels.TRAIT_DESC[trait],  # noqa: F821
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.029,
                    text_fg=SILVER_COL
                    if trait in self.char.traits
                    else (0.3, 0.3, 0.3, 1),
                    pos=(0, 0, shift - 0.045),
                )
            )
            shift -= 0.1
        return shift

    def _fill_status(self, shift):
        """Fill the chosen character status.

        Args:
            shift (float): Z-coor for the new widgets.
        """
        shift -= 0.04
        for status in self.char.statuses:
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=status,
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.029,
                    text_fg=SILVER_COL,
                    pos=(0, 0, shift),
                )
            )
            shift -= 0.045

    def _show_char_desc(self):
        """Show detailed character description.

        Includes description of every character's
        trait and their current status.
        """
        if self._char_desc_shown:
            self._fr["frameSize"] = (-0.31, 0.31, -0.1, 0.115)
            clear_wids(self._char_desc_wids)
            self._status_lab = None
        else:
            shift = 0.7
            self._fr["frameSize"] = (-0.31, 0.31, -0.1, shift)
            shift -= 0.06
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    # Traits
                    text=base.labels.CHARACTERS[5],  # noqa: F821,
                    text_font=base.main_font,  # noqa: F821,
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.03,
                    text_fg=RUST_COL,
                    pos=(-0.225, 0, shift),
                )
            )
            if self.char.id in base.team.chars.keys():  # noqa: F821
                traits_but = DirectButton(
                    parent=self._fr,
                    text="",
                    frameSize=(-0.025, 0.025, -0.025, 0.025),
                    frameTexture=GUI_PIC + "like.png",
                    relief="flat",
                    pos=(0.265, 0, shift + 0.013),
                    command=base.traits_gui.show,  # noqa: F821
                )
                traits_but.bind(
                    DGG.ENTER, self._highlight_traits_but, extraArgs=[traits_but]
                )
                traits_but.bind(
                    DGG.EXIT, self._dehighlight_traits_but, extraArgs=[traits_but]
                )

                self._char_desc_wids.append(traits_but)

            shift = self._fill_traits(shift)

            self._status_lab = DirectLabel(  # Status
                parent=self._fr,
                # Status
                text=base.labels.CHARACTERS[4],  # noqa: F821
                text_font=base.main_font,  # noqa: F821
                frameSize=(0.1, 0.1, 0.1, 0.1),
                text_scale=0.03,
                text_fg=RUST_COL,
                pos=(-0.221, 0, shift),
            )
            self._char_desc_wids.append(self._status_lab)
            self._fill_status(shift)

        self._char_desc_shown = not self._char_desc_shown

    def _dehighlight_traits_but(self, button, _):
        """Dehighlight traits tweaking button.

        Args:
            button (panda3d.gui.DirectGui.DirectButton):
                Button to dehighlight.
        """
        button["frameTexture"] = GUI_PIC + "like.png"

    def _highlight_traits_but(self, button, _):
        """Hightlight traits tweaking button.

        Args:
            button (panda3d.gui.DirectGui.DirectButton):
                Button to highlight.
        """
        button["frameTexture"] = GUI_PIC + "hover_like.png"

    def clear_char_info(self, clear_resting=True):
        """Clear the character GUI.

        Args:
            clear_resting (bool):
                Optional. A flag indicating if the list of the
                resting characters should also be closed.
        """
        for wid in (
            self._char_name,
            self._char_class,
            self._char_health,
            self._char_energy,
            self._traits,
            self._char_desc_but,
            self._disease,
        ):
            wid.hide()

        if self._char_desc_shown:
            self._show_char_desc()

        taskMgr.remove("track_char_info")  # noqa: F821
        self.char = None

        if clear_resting:
            for but in self._rest_buttons.values():
                but.destroy()

        self.rest_list_shown = False

    def destroy_char_button(self, char_id):
        """Hide the given character button from the resting characters list.

        Args:
            char_id (str): Character id.
        """
        if char_id in self._rest_buttons.keys():
            self._rest_buttons[char_id].destroy()
            self._rest_buttons.pop(char_id)

    def hide_tip(self):
        """Hide the tooltip."""
        self._tip.hide()

    def show_char_info(self, char):
        """Show the given character status.

        Args:
            char (units.crew.character.Character):
                The chosen character object.
        """
        self._char_name["text"] = char.name
        self._char_class["text"] = char.class_.capitalize()
        self._traits["text"] = ", ".join(char.traits)

        self._char_health["range"] = char.class_data["health"]
        self._char_health["value"] = char.health
        self._char_energy["value"] = char.energy

        if char.is_diseased:
            self._disease.show()
        else:
            self._disease.hide()

        self.char = char
        self._char_name.show()
        self._char_class.show()
        self._char_health.show()
        self._char_energy.show()
        self._traits.show()
        self._char_desc_but.show()

        if self._char_desc_shown:
            self._show_char_desc()
            self._show_char_desc()

        taskMgr.doMethodLater(  # noqa: F821
            0.5, self._update_char_info, "track_char_info"
        )

    def show_tooltip(self, text):
        """Show tooltip with the given text.

        Args:
            text (str): Text to show in the tooltip.
        """
        if not base.mouseWatcherNode.hasMouse():  # noqa: F821
            return

        if self.rest_list_shown and text == "Rest zone":
            return

        self._tip.setText(text)
        self._tip.setX(base.mouseWatcherNode.getMouseX())  # noqa: F821
        self._tip.setY(base.mouseWatcherNode.getMouseY())  # noqa: F821
        self._tip.show()

    def show_resting_chars(self, part):
        """Show a list of the characters resting in this part.

        Args:
            part (Train.RestPart): Rest part of the Train.
        """
        if self.rest_list_shown:
            return

        self._tip.hide()
        self.rest_list_shown = True

        x = base.mouseWatcherNode.getMouseX()  # noqa: F821
        z = base.mouseWatcherNode.getMouseY()  # noqa: F821

        self._rest_buttons["title"] = DirectButton(
            pos=(x, 0, z),
            text=base.labels.TIPS[0],  # noqa: F821
            text_fg=RUST_COL,
            text_font=base.main_font,  # noqa: F821
            frameColor=(0, 0, 0, 0.6),
            scale=(0.04, 0, 0.03),
        )
        shift = -0.039
        for char in part.chars:
            if char.is_dead:
                continue

            self._rest_buttons[char.id] = DirectButton(
                pos=(x, 0, z + shift),
                text=char.name,
                text_fg=SILVER_COL,
                frameColor=(0, 0, 0, 0.6),
                command=base.common_ctrl.choose_char,  # noqa: F821
                extraArgs=[char.id],
                scale=(0.04, 0, 0.03),
            )
            shift -= 0.033

    def move_status_label(self, place):
        """Move the status label widget.

        Args:
            place (int): Place to shift the widget.
        """
        if self._status_lab is not None:
            self._status_lab.setZ(self._status_lab.getZ() + place / 10)

    def update_resting_chars(self, part):
        """Update the list of the resting characters.

        Args:
            part (train.part.TrainPart): Rest train part.
        """
        for key, but in self._rest_buttons.items():
            if key != "title":
                but.destroy()
                self._rest_buttons[key] = None

        x, _, z = self._rest_buttons["title"].getPos()

        shift = -0.039
        for char in part.chars:
            self._rest_buttons[char.id] = DirectButton(
                pos=(x, 0, z + shift),
                text=char.name,
                text_fg=SILVER_COL,
                frameColor=(0, 0, 0, 0.6),
                command=base.common_ctrl.choose_char,  # noqa: F821
                extraArgs=[char.id],
                scale=(0.04, 0, 0.03),
            )
            shift -= 0.033
class DistributedMazeGame(DistributedMinigame):
    notify = directNotify.newCategory('DistributedMazeGame')
    CAMERA_TASK = 'MazeGameCameraTask'
    UPDATE_SUITS_TASK = 'MazeGameUpdateSuitsTask'
    TREASURE_GRAB_EVENT_NAME = 'MazeTreasureGrabbed'

    def __init__(self, cr):
        DistributedMinigame.__init__(self, cr)
        self.gameFSM = ClassicFSM.ClassicFSM('DistributedMazeGame', [State.State('off', self.enterOff, self.exitOff, ['play']),
         State.State('play', self.enterPlay, self.exitPlay, ['cleanup', 'showScores']),
         State.State('showScores', self.enterShowScores, self.exitShowScores, ['cleanup']),
         State.State('cleanup', self.enterCleanup, self.exitCleanup, [])], 'off', 'cleanup')
        self.addChildGameFSM(self.gameFSM)
        self.usesLookAround = 1

    def getTitle(self):
        return TTLocalizer.MazeGameTitle

    def getInstructions(self):
        return TTLocalizer.MazeGameInstructions

    def getMaxDuration(self):
        return MazeGameGlobals.GAME_DURATION

    def __defineConstants(self):
        self.TOON_SPEED = 8.0
        self.TOON_Z = 0
        self.MinSuitSpeedRange = [0.8 * self.TOON_SPEED, 0.6 * self.TOON_SPEED]
        self.MaxSuitSpeedRange = [1.1 * self.TOON_SPEED, 2.0 * self.TOON_SPEED]
        self.FASTER_SUIT_CURVE = 1
        self.SLOWER_SUIT_CURVE = self.getDifficulty() < 0.5
        self.slowerSuitPeriods = {2000: {4: [128, 76],
                8: [128,
                    99,
                    81,
                    68],
                12: [128,
                     108,
                     93,
                     82,
                     74,
                     67],
                16: [128,
                     112,
                     101,
                     91,
                     83,
                     76,
                     71,
                     66]},
         1000: {4: [110, 69],
                8: [110,
                    88,
                    73,
                    62],
                12: [110,
                     95,
                     83,
                     74,
                     67,
                     61],
                16: [110,
                     98,
                     89,
                     81,
                     75,
                     69,
                     64,
                     60]},
         5000: {4: [96, 63],
                8: [96,
                    79,
                    66,
                    57],
                12: [96,
                     84,
                     75,
                     67,
                     61,
                     56],
                16: [96,
                     87,
                     80,
                     73,
                     68,
                     63,
                     59,
                     55]},
         4000: {4: [86, 58],
                8: [86,
                    71,
                    61,
                    53],
                12: [86,
                     76,
                     68,
                     62,
                     56,
                     52],
                16: [86,
                     78,
                     72,
                     67,
                     62,
                     58,
                     54,
                     51]},
         3000: {4: [78, 54],
                8: [78,
                    65,
                    56,
                    49],
                12: [78,
                     69,
                     62,
                     57,
                     52,
                     48],
                16: [78,
                     71,
                     66,
                     61,
                     57,
                     54,
                     51,
                     48]},
         9000: {4: [71, 50],
                8: [71,
                    60,
                    52,
                    46],
                12: [71,
                     64,
                     58,
                     53,
                     49,
                     45],
                16: [71,
                     65,
                     61,
                     57,
                     53,
                     50,
                     47,
                     45]}}
        self.slowerSuitPeriodsCurve = {2000: {4: [128, 65],
                8: [128,
                    78,
                    66,
                    64],
                12: [128,
                     88,
                     73,
                     67,
                     64,
                     64],
                16: [128,
                     94,
                     79,
                     71,
                     67,
                     65,
                     64,
                     64]},
         1000: {4: [110, 59],
                8: [110,
                    70,
                    60,
                    58],
                12: [110,
                     78,
                     66,
                     61,
                     59,
                     58],
                16: [110,
                     84,
                     72,
                     65,
                     61,
                     59,
                     58,
                     58]},
         5000: {4: [96, 55],
                8: [96,
                    64,
                    56,
                    54],
                12: [96,
                     71,
                     61,
                     56,
                     54,
                     54],
                16: [96,
                     76,
                     65,
                     59,
                     56,
                     55,
                     54,
                     54]},
         4000: {4: [86, 51],
                8: [86,
                    59,
                    52,
                    50],
                12: [86,
                     65,
                     56,
                     52,
                     50,
                     50],
                16: [86,
                     69,
                     60,
                     55,
                     52,
                     51,
                     50,
                     50]},
         3000: {4: [78, 47],
                8: [78,
                    55,
                    48,
                    47],
                12: [78,
                     60,
                     52,
                     48,
                     47,
                     47],
                16: [78,
                     63,
                     55,
                     51,
                     49,
                     47,
                     47,
                     47]},
         9000: {4: [71, 44],
                8: [71,
                    51,
                    45,
                    44],
                12: [71,
                     55,
                     48,
                     45,
                     44,
                     44],
                16: [71,
                     58,
                     51,
                     48,
                     45,
                     44,
                     44,
                     44]}}
        self.fasterSuitPeriods = {2000: {4: [54, 42],
                8: [59,
                    52,
                    47,
                    42],
                12: [61,
                     56,
                     52,
                     48,
                     45,
                     42],
                16: [61,
                     58,
                     54,
                     51,
                     49,
                     46,
                     44,
                     42]},
         1000: {4: [50, 40],
                8: [55,
                    48,
                    44,
                    40],
                12: [56,
                     52,
                     48,
                     45,
                     42,
                     40],
                16: [56,
                     53,
                     50,
                     48,
                     45,
                     43,
                     41,
                     40]},
         5000: {4: [47, 37],
                8: [51,
                    45,
                    41,
                    37],
                12: [52,
                     48,
                     45,
                     42,
                     39,
                     37],
                16: [52,
                     49,
                     47,
                     44,
                     42,
                     40,
                     39,
                     37]},
         4000: {4: [44, 35],
                8: [47,
                    42,
                    38,
                    35],
                12: [48,
                     45,
                     42,
                     39,
                     37,
                     35],
                16: [49,
                     46,
                     44,
                     42,
                     40,
                     38,
                     37,
                     35]},
         3000: {4: [41, 33],
                8: [44,
                    40,
                    36,
                    33],
                12: [45,
                     42,
                     39,
                     37,
                     35,
                     33],
                16: [45,
                     43,
                     41,
                     39,
                     38,
                     36,
                     35,
                     33]},
         9000: {4: [39, 32],
                8: [41,
                    37,
                    34,
                    32],
                12: [42,
                     40,
                     37,
                     35,
                     33,
                     32],
                16: [43,
                     41,
                     39,
                     37,
                     35,
                     34,
                     33,
                     32]}}
        self.fasterSuitPeriodsCurve = {2000: {4: [62, 42],
                8: [63,
                    61,
                    54,
                    42],
                12: [63,
                     63,
                     61,
                     56,
                     50,
                     42],
                16: [63,
                     63,
                     62,
                     60,
                     57,
                     53,
                     48,
                     42]},
         1000: {4: [57, 40],
                8: [58,
                    56,
                    50,
                    40],
                12: [58,
                     58,
                     56,
                     52,
                     46,
                     40],
                16: [58,
                     58,
                     57,
                     56,
                     53,
                     49,
                     45,
                     40]},
         5000: {4: [53, 37],
                8: [54,
                    52,
                    46,
                    37],
                12: [54,
                     53,
                     52,
                     48,
                     43,
                     37],
                16: [54,
                     54,
                     53,
                     51,
                     49,
                     46,
                     42,
                     37]},
         4000: {4: [49, 35],
                8: [50,
                    48,
                    43,
                    35],
                12: [50,
                     49,
                     48,
                     45,
                     41,
                     35],
                16: [50,
                     50,
                     49,
                     48,
                     46,
                     43,
                     39,
                     35]},
         3000: {4: [46, 33],
                8: [47,
                    45,
                    41,
                    33],
                12: [47,
                     46,
                     45,
                     42,
                     38,
                     33],
                16: [47,
                     46,
                     46,
                     45,
                     43,
                     40,
                     37,
                     33]},
         9000: {4: [43, 32],
                8: [44,
                    42,
                    38,
                    32],
                12: [44,
                     43,
                     42,
                     40,
                     36,
                     32],
                16: [44,
                     44,
                     43,
                     42,
                     40,
                     38,
                     35,
                     32]}}
        self.CELL_WIDTH = MazeData.CELL_WIDTH
        self.MAX_FRAME_MOVE = self.CELL_WIDTH / 2
        startOffset = 3
        self.startPosHTable = [[Point3(0, startOffset, self.TOON_Z), 0],
         [Point3(0, -startOffset, self.TOON_Z), 180],
         [Point3(startOffset, 0, self.TOON_Z), 270],
         [Point3(-startOffset, 0, self.TOON_Z), 90]]
        self.camOffset = Vec3(0, -19, 45)

    def load(self):
        self.notify.debug('load')
        DistributedMinigame.load(self)
        self.__defineConstants()
        mazeName = MazeGameGlobals.getMazeName(self.doId, self.numPlayers, MazeData.mazeNames)
        self.maze = Maze.Maze(mazeName)
        model = loader.loadModel('phase_3.5/models/props/mickeySZ')
        self.treasureModel = model.find('**/mickeySZ')
        model.removeNode()
        self.treasureModel.setScale(1.6)
        self.treasureModel.setP(-90)
        self.music = base.loadMusic('phase_4/audio/bgm/MG_toontag.ogg')
        self.toonHitTracks = {}
        self.scorePanels = []

    def unload(self):
        self.notify.debug('unload')
        DistributedMinigame.unload(self)
        del self.toonHitTracks
        self.maze.destroy()
        del self.maze
        self.treasureModel.removeNode()
        del self.treasureModel
        del self.music
        self.removeChildGameFSM(self.gameFSM)
        del self.gameFSM

    def onstage(self):
        self.notify.debug('onstage')
        DistributedMinigame.onstage(self)
        self.maze.onstage()
        self.randomNumGen.shuffle(self.startPosHTable)
        lt = base.localAvatar
        lt.reparentTo(render)
        lt.hideName()
        self.__placeToon(self.localAvId)
        lt.setAnimState('Happy', 1.0)
        lt.setSpeed(0, 0)
        self.camParent = render.attachNewNode('mazeGameCamParent')
        self.camParent.reparentTo(base.localAvatar)
        self.camParent.setPos(0, 0, 0)
        self.camParent.setHpr(render, 0, 0, 0)
        camera.reparentTo(self.camParent)
        camera.setPos(self.camOffset)
        self.__spawnCameraTask()
        self.toonRNGs = []
        for i in xrange(self.numPlayers):
            self.toonRNGs.append(RandomNumGen.RandomNumGen(self.randomNumGen))

        self.treasures = []
        for i in xrange(self.maze.numTreasures):
            self.treasures.append(MazeTreasure.MazeTreasure(self.treasureModel, self.maze.treasurePosList[i], i, self.doId))

        self.__loadSuits()
        for suit in self.suits:
            suit.onstage()

        self.sndTable = {'hitBySuit': [None] * self.numPlayers,
         'falling': [None] * self.numPlayers}
        for i in xrange(self.numPlayers):
            self.sndTable['hitBySuit'][i] = base.loadSfx('phase_4/audio/sfx/MG_Tag_C.ogg')
            self.sndTable['falling'][i] = base.loadSfx('phase_4/audio/sfx/MG_cannon_whizz.ogg')

        self.grabSounds = []
        for i in xrange(5):
            self.grabSounds.append(base.loadSfx('phase_4/audio/sfx/MG_maze_pickup.ogg'))

        self.grabSoundIndex = 0
        for avId in self.avIdList:
            self.toonHitTracks[avId] = Wait(0.1)

        self.scores = [0] * self.numPlayers
        self.goalBar = DirectWaitBar(parent=render2d, relief=DGG.SUNKEN, frameSize=(-0.35,
         0.35,
         -0.15,
         0.15), borderWidth=(0.02, 0.02), scale=0.42, pos=(0.84, 0, 0.5 - 0.28 * self.numPlayers + 0.05), barColor=(0, 0.7, 0, 1))
        self.goalBar.setBin('unsorted', 0)
        self.goalBar.hide()
        self.introTrack = self.getIntroTrack()
        self.introTrack.start()
        return

    def offstage(self):
        self.notify.debug('offstage')
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        del self.introTrack
        for avId in self.toonHitTracks.keys():
            track = self.toonHitTracks[avId]
            if track.isPlaying():
                track.finish()

        self.__killCameraTask()
        camera.wrtReparentTo(render)
        self.camParent.removeNode()
        del self.camParent
        for panel in self.scorePanels:
            panel.cleanup()

        self.scorePanels = []
        self.goalBar.destroy()
        del self.goalBar
        base.setCellsAvailable(base.rightCells, 1)
        for suit in self.suits:
            suit.offstage()

        self.__unloadSuits()
        for treasure in self.treasures:
            treasure.destroy()

        del self.treasures
        del self.sndTable
        del self.grabSounds
        del self.toonRNGs
        self.maze.offstage()
        base.localAvatar.showName()
        DistributedMinigame.offstage(self)

    def __placeToon(self, avId):
        toon = self.getAvatar(avId)
        if self.numPlayers == 1:
            toon.setPos(0, 0, self.TOON_Z)
            toon.setHpr(180, 0, 0)
        else:
            posIndex = self.avIdList.index(avId)
            toon.setPos(self.startPosHTable[posIndex][0])
            toon.setHpr(self.startPosHTable[posIndex][1], 0, 0)

    def setGameReady(self):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameReady')
        if DistributedMinigame.setGameReady(self):
            return
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.reparentTo(render)
                self.__placeToon(avId)
                toon.setAnimState('Happy', 1.0)
                toon.startSmooth()
                toon.startLookAround()

    def setGameStart(self, timestamp):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameStart')
        DistributedMinigame.setGameStart(self, timestamp)
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.stopLookAround()

        self.gameFSM.request('play')

    def handleDisabledAvatar(self, avId):
        hitTrack = self.toonHitTracks[avId]
        if hitTrack.isPlaying():
            hitTrack.finish()
        DistributedMinigame.handleDisabledAvatar(self, avId)

    def enterOff(self):
        self.notify.debug('enterOff')

    def exitOff(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')
        for i in xrange(self.numPlayers):
            avId = self.avIdList[i]
            avName = self.getAvatarName(avId)
            scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(avId, avName)
            scorePanel.reparentTo(base.a2dTopRight)
            scorePanel.setPos(-0.213, 0.0, -0.5 - 0.28 * i)
            self.scorePanels.append(scorePanel)

        self.goalBar.show()
        self.goalBar['value'] = 0.0
        base.setCellsAvailable(base.rightCells, 0)
        self.__spawnUpdateSuitsTask()
        orthoDrive = OrthoDrive(self.TOON_SPEED, maxFrameMove=self.MAX_FRAME_MOVE, customCollisionCallback=self.__doMazeCollisions, priority=1)
        self.orthoWalk = OrthoWalk(orthoDrive, broadcast=not self.isSinglePlayer())
        self.orthoWalk.start()
        self.accept(MazeSuit.COLLISION_EVENT_NAME, self.__hitBySuit)
        self.accept(self.TREASURE_GRAB_EVENT_NAME, self.__treasureGrabbed)
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.posInTopRightCorner()
        self.timer.setTime(MazeGameGlobals.GAME_DURATION)
        self.timer.countdown(MazeGameGlobals.GAME_DURATION, self.timerExpired)
        self.accept('resetClock', self.__resetClock)
        base.playMusic(self.music, looping=0, volume=0.8)

    def exitPlay(self):
        self.notify.debug('exitPlay')
        self.ignore('resetClock')
        self.ignore(MazeSuit.COLLISION_EVENT_NAME)
        self.ignore(self.TREASURE_GRAB_EVENT_NAME)
        self.orthoWalk.stop()
        self.orthoWalk.destroy()
        del self.orthoWalk
        self.__killUpdateSuitsTask()
        self.timer.stop()
        self.timer.destroy()
        del self.timer
        for avId in self.avIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.loop('neutral')

    def __resetClock(self, tOffset):
        self.notify.debug('resetClock')
        self.gameStartTime += tOffset
        self.timer.countdown(self.timer.currentTime + tOffset, self.timerExpired)

    def __treasureGrabbed(self, treasureNum):
        self.treasures[treasureNum].showGrab()
        self.grabSounds[self.grabSoundIndex].play()
        self.grabSoundIndex = (self.grabSoundIndex + 1) % len(self.grabSounds)
        self.sendUpdate('claimTreasure', [treasureNum])

    def setTreasureGrabbed(self, avId, treasureNum):
        if not self.hasLocalToon:
            return
        if avId != self.localAvId:
            self.treasures[treasureNum].showGrab()
        i = self.avIdList.index(avId)
        self.scores[i] += 1
        self.scorePanels[i].setScore(self.scores[i])
        total = 0
        for score in self.scores:
            total += score

        self.goalBar['value'] = 100.0 * (float(total) / float(self.maze.numTreasures))

    def __hitBySuit(self, suitNum):
        self.notify.debug('hitBySuit')
        timestamp = globalClockDelta.localToNetworkTime(globalClock.getFrameTime())
        self.sendUpdate('hitBySuit', [self.localAvId, timestamp])
        self.__showToonHitBySuit(self.localAvId, timestamp)

    def hitBySuit(self, avId, timestamp):
        if not self.hasLocalToon:
            return
        if self.gameFSM.getCurrentState().getName() not in ['play', 'showScores']:
            self.notify.warning('ignoring msg: av %s hit by suit' % avId)
            return
        self.notify.debug('avatar ' + `avId` + ' hit by a suit')
        if avId != self.localAvId:
            self.__showToonHitBySuit(avId, timestamp)

    def __showToonHitBySuit(self, avId, timestamp):
        toon = self.getAvatar(avId)
        if toon == None:
            return
        rng = self.toonRNGs[self.avIdList.index(avId)]
        curPos = toon.getPos(render)
        oldTrack = self.toonHitTracks[avId]
        if oldTrack.isPlaying():
            oldTrack.finish()
        toon.setPos(curPos)
        toon.setZ(self.TOON_Z)
        parentNode = render.attachNewNode('mazeFlyToonParent-' + `avId`)
        parentNode.setPos(toon.getPos())
        toon.reparentTo(parentNode)
        toon.setPos(0,0,0)
        startPos = parentNode.getPos()
        dropShadow = toon.dropShadow.copyTo(parentNode)
        dropShadow.setScale(toon.dropShadow.getScale(render))
        trajectory = Trajectory.Trajectory(
            0,
            Point3(0,0,0),
            Point3(0,0,50),
            gravMult=1.0)
        flyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        while 1:
            endTile = [rng.randint(2, self.maze.width-1), rng.randint(2, self.maze.height-1)]
            if self.maze.isWalkable(endTile[0], endTile[1]):
                break
        endWorldCoords = self.maze.tile2world(endTile[0], endTile[1])
        endPos = Point3(endWorldCoords[0], endWorldCoords[1], startPos[2])
        def flyFunc(t, trajectory, startPos = startPos, endPos = endPos, dur = flyDur, moveNode = parentNode, flyNode = toon):
            u = t/dur
            moveNode.setX(startPos[0] + u * (endPos[0]-startPos[0]))
            moveNode.setY(startPos[1] + u * (endPos[1]-startPos[1]))
            flyNode.setPos(trajectory.getPos(t))
        flyTrack = Sequence(
            LerpFunctionInterval(flyFunc, fromData=0.0, toData=flyDur, duration=flyDur, extraArgs=[trajectory]),
            name=toon.uniqueName('hitBySuit-fly'))
        if avId != self.localAvId:
            cameraTrack = Sequence()
        else:
            self.camParent.reparentTo(parentNode)
            startCamPos = camera.getPos()
            destCamPos = camera.getPos()
            zenith = trajectory.getPos(flyDur/2.0)[2]
            destCamPos.setZ(zenith*1.3)
            destCamPos.setY(destCamPos[1]*0.3)
            def camTask(task, zenith = zenith, flyNode = toon, startCamPos = startCamPos, camOffset = destCamPos - startCamPos):
                u = flyNode.getZ()/zenith
                camera.setPos(startCamPos + camOffset*u)
                camera.lookAt(toon)
                return Task.cont
            camTaskName = 'mazeToonFlyCam-' + `avId`
            taskMgr.add(camTask, camTaskName, priority=20)
            def cleanupCamTask(self = self, toon = toon, camTaskName = camTaskName, startCamPos = startCamPos):
                taskMgr.remove(camTaskName)
                self.camParent.reparentTo(toon)
                camera.setPos(startCamPos)
                camera.lookAt(toon)

            cameraTrack = Sequence(
                Wait(flyDur),
                Func(cleanupCamTask),
                name='hitBySuit-cameraLerp')

        geomNode = toon.getGeomNode()
        startHpr = geomNode.getHpr()
        destHpr = Point3(startHpr)
        hRot = rng.randrange(1, 8)
        if rng.choice([0, 1]):
            hRot = -hRot
        destHpr.setX(destHpr[0] + hRot*360)
        spinHTrack = Sequence(
            LerpHprInterval(geomNode, flyDur, destHpr, startHpr=startHpr),
            Func(geomNode.setHpr, startHpr),
            name=toon.uniqueName('hitBySuit-spinH'))
        parent = geomNode.getParent()
        rotNode = parent.attachNewNode('rotNode')
        geomNode.reparentTo(rotNode)
        rotNode.setZ(toon.getHeight()/2.0)
        oldGeomNodeZ = geomNode.getZ()
        geomNode.setZ(-toon.getHeight()/2.0)
        startHpr = rotNode.getHpr()
        destHpr = Point3(startHpr)
        pRot = rng.randrange(1,3)
        if rng.choice([0, 1]):
            pRot = -pRot
        destHpr.setY(destHpr[1] + pRot*360)
        spinPTrack = Sequence(
            LerpHprInterval(rotNode, flyDur, destHpr, startHpr=startHpr),
            Func(rotNode.setHpr, startHpr),
            name=toon.uniqueName('hitBySuit-spinP'))
        i = self.avIdList.index(avId)
        soundTrack = Sequence(
            Func(base.playSfx, self.sndTable['hitBySuit'][i]),
            Wait(flyDur * (2.0/3.0)),
            SoundInterval(self.sndTable['falling'][i],
                          duration=flyDur * (1.0/3.0)),
            name=toon.uniqueName('hitBySuit-soundTrack'))

        def preFunc(self = self, avId = avId, toon = toon, dropShadow = dropShadow):
            forwardSpeed = toon.forwardSpeed
            rotateSpeed = toon.rotateSpeed
            if avId == self.localAvId:
                self.orthoWalk.stop()
            else:
                toon.stopSmooth()
            if forwardSpeed or rotateSpeed:
                toon.setSpeed(forwardSpeed, rotateSpeed)
            toon.dropShadow.hide()

        def postFunc(self = self, avId = avId, oldGeomNodeZ = oldGeomNodeZ, dropShadow = dropShadow, parentNode = parentNode):
            if avId == self.localAvId:
                base.localAvatar.setPos(endPos)
                if hasattr(self, 'orthoWalk'):
                    if self.gameFSM.getCurrentState().getName() == 'play':
                        self.orthoWalk.start()
            dropShadow.removeNode()
            del dropShadow
            toon.dropShadow.show()
            geomNode = toon.getGeomNode()
            rotNode = geomNode.getParent()
            baseNode = rotNode.getParent()
            geomNode.reparentTo(baseNode)
            rotNode.removeNode()
            del rotNode
            geomNode.setZ(oldGeomNodeZ)
            toon.reparentTo(render)
            toon.setPos(endPos)
            parentNode.removeNode()
            del parentNode
            if avId != self.localAvId:
                toon.startSmooth()

        preFunc()

        hitTrack = Sequence(Parallel(flyTrack, cameraTrack,
                                     spinHTrack, spinPTrack, soundTrack),
                            Func(postFunc),
                            name=toon.uniqueName('hitBySuit'))

        self.toonHitTracks[avId] = hitTrack

        hitTrack.start(globalClockDelta.localElapsedTime(timestamp))

    def allTreasuresTaken(self):
        if not self.hasLocalToon:
            return
        self.notify.debug('all treasures taken')
        if not MazeGameGlobals.ENDLESS_GAME:
            self.gameFSM.request('showScores')

    def timerExpired(self):
        self.notify.debug('local timer expired')
        if not MazeGameGlobals.ENDLESS_GAME:
            self.gameFSM.request('showScores')

    def __doMazeCollisions(self, oldPos, newPos):
        offset = newPos - oldPos
        WALL_OFFSET = 1.0
        curX = oldPos[0]
        curY = oldPos[1]
        curTX, curTY = self.maze.world2tile(curX, curY)

        def calcFlushCoord(curTile, newTile, centerTile):
            EPSILON = 0.01
            if newTile > curTile:
                return (newTile - centerTile) * self.CELL_WIDTH - EPSILON - WALL_OFFSET
            else:
                return (curTile - centerTile) * self.CELL_WIDTH + WALL_OFFSET

        offsetX = offset[0]
        offsetY = offset[1]
        WALL_OFFSET_X = WALL_OFFSET
        if offsetX < 0:
            WALL_OFFSET_X = -WALL_OFFSET_X
        WALL_OFFSET_Y = WALL_OFFSET
        if offsetY < 0:
            WALL_OFFSET_Y = -WALL_OFFSET_Y
        newX = curX + offsetX + WALL_OFFSET_X
        newY = curY
        newTX, newTY = self.maze.world2tile(newX, newY)
        if newTX != curTX:
            if self.maze.collisionTable[newTY][newTX]:
                offset.setX(calcFlushCoord(curTX, newTX, self.maze.originTX) - curX)
        newX = curX
        newY = curY + offsetY + WALL_OFFSET_Y
        newTX, newTY = self.maze.world2tile(newX, newY)
        if newTY != curTY:
            if self.maze.collisionTable[newTY][newTX]:
                offset.setY(calcFlushCoord(curTY, newTY, self.maze.originTY) - curY)
        offsetX = offset[0]
        offsetY = offset[1]
        newX = curX + offsetX + WALL_OFFSET_X
        newY = curY + offsetY + WALL_OFFSET_Y
        newTX, newTY = self.maze.world2tile(newX, newY)
        if self.maze.collisionTable[newTY][newTX]:
            cX = calcFlushCoord(curTX, newTX, self.maze.originTX)
            cY = calcFlushCoord(curTY, newTY, self.maze.originTY)
            if abs(cX - curX) < abs(cY - curY):
                offset.setX(cX - curX)
            else:
                offset.setY(cY - curY)
        return oldPos + offset

    def __spawnCameraTask(self):
        self.notify.debug('spawnCameraTask')
        camera.lookAt(base.localAvatar)
        taskMgr.remove(self.CAMERA_TASK)
        taskMgr.add(self.__cameraTask, self.CAMERA_TASK, priority=45)

    def __killCameraTask(self):
        self.notify.debug('killCameraTask')
        taskMgr.remove(self.CAMERA_TASK)

    def __cameraTask(self, task):
        self.camParent.setHpr(render, 0, 0, 0)
        return Task.cont

    def __loadSuits(self):
        self.notify.debug('loadSuits')
        self.suits = []
        self.numSuits = 4 * self.numPlayers
        safeZone = self.getSafezoneId()
        slowerTable = self.slowerSuitPeriods
        if self.SLOWER_SUIT_CURVE:
            slowerTable = self.slowerSuitPeriodsCurve
        slowerPeriods = slowerTable[safeZone][self.numSuits]
        fasterTable = self.fasterSuitPeriods
        if self.FASTER_SUIT_CURVE:
            fasterTable = self.fasterSuitPeriodsCurve
        fasterPeriods = fasterTable[safeZone][self.numSuits]
        suitPeriods = slowerPeriods + fasterPeriods
        self.notify.debug('suit periods: ' + `suitPeriods`)
        self.randomNumGen.shuffle(suitPeriods)
        for i in xrange(self.numSuits):
            self.suits.append(MazeSuit(i, self.maze, self.randomNumGen, suitPeriods[i], self.getDifficulty()))

    def __unloadSuits(self):
        self.notify.debug('unloadSuits')
        for suit in self.suits:
            suit.destroy()

        self.suits = []

    def __spawnUpdateSuitsTask(self):
        self.notify.debug('spawnUpdateSuitsTask')
        for suit in self.suits:
            suit.gameStart(self.gameStartTime)

        taskMgr.remove(self.UPDATE_SUITS_TASK)
        taskMgr.add(self.__updateSuitsTask, self.UPDATE_SUITS_TASK)

    def __killUpdateSuitsTask(self):
        self.notify.debug('killUpdateSuitsTask')
        taskMgr.remove(self.UPDATE_SUITS_TASK)
        for suit in self.suits:
            suit.gameEnd()

    def __updateSuitsTask(self, task):
        curT = globalClock.getFrameTime() - self.gameStartTime
        curTic = int(curT * float(MazeGameGlobals.SUIT_TIC_FREQ))
        suitUpdates = []
        for i in xrange(len(self.suits)):
            updateTics = self.suits[i].getThinkTimestampTics(curTic)
            suitUpdates.extend(zip(updateTics, [i] * len(updateTics)))

        suitUpdates.sort(lambda a, b: a[0] - b[0])
        if len(suitUpdates) > 0:
            curTic = 0
            for i in xrange(len(suitUpdates)):
                update = suitUpdates[i]
                tic = update[0]
                suitIndex = update[1]
                suit = self.suits[suitIndex]
                if tic > curTic:
                    curTic = tic
                    j = i + 1
                    while j < len(suitUpdates):
                        if suitUpdates[j][0] > tic:
                            break
                        self.suits[suitUpdates[j][1]].prepareToThink()
                        j += 1

                unwalkables = []
                for si in xrange(suitIndex):
                    unwalkables.extend(self.suits[si].occupiedTiles)

                for si in xrange(suitIndex + 1, len(self.suits)):
                    unwalkables.extend(self.suits[si].occupiedTiles)

                suit.think(curTic, curT, unwalkables)

        return Task.cont

    def enterShowScores(self):
        self.notify.debug('enterShowScores')
        lerpTrack = Parallel()
        lerpDur = 0.5
        lerpTrack.append(Parallel(LerpPosInterval(self.goalBar, lerpDur, Point3(0, 0, -.6), blendType='easeInOut'), LerpScaleInterval(self.goalBar, lerpDur, Vec3(self.goalBar.getScale()) * 2.0, blendType='easeInOut')))
        tY = 0.6
        bY = -.05
        lX = -.5
        cX = 0
        rX = 0.5
        scorePanelLocs = (((cX, bY),),
         ((lX, bY), (rX, bY)),
         ((cX, tY), (lX, bY), (rX, bY)),
         ((lX, tY),
          (rX, tY),
          (lX, bY),
          (rX, bY)))
        scorePanelLocs = scorePanelLocs[self.numPlayers - 1]
        for i in xrange(self.numPlayers):
            panel = self.scorePanels[i]
            pos = scorePanelLocs[i]
            panel.wrtReparentTo(aspect2d)
            lerpTrack.append(Parallel(LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType='easeInOut'), LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType='easeInOut')))

        self.showScoreTrack = Parallel(lerpTrack, Sequence(Wait(MazeGameGlobals.SHOWSCORES_DURATION), Func(self.gameOver)))
        self.showScoreTrack.start()

        #For the Alpha Blueprint ARG
        if config.GetBool('want-blueprint4-ARG', False):
            MinigameGlobals.generateDebugARGPhrase()

    def exitShowScores(self):
        self.showScoreTrack.pause()
        del self.showScoreTrack

    def enterCleanup(self):
        self.notify.debug('enterCleanup')

    def exitCleanup(self):
        pass

    def getIntroTrack(self):
        self.__cameraTask(None)
        origCamParent = camera.getParent()
        origCamPos = camera.getPos()
        origCamHpr = camera.getHpr()
        iCamParent = base.localAvatar.attachNewNode('iCamParent')
        iCamParent.setH(180)
        camera.reparentTo(iCamParent)
        toonHeight = base.localAvatar.getHeight()
        camera.setPos(0, -15, toonHeight * 3)
        camera.lookAt(0, 0, toonHeight / 2.0)
        iCamParent.wrtReparentTo(origCamParent)
        waitDur = 5.0
        lerpDur = 4.5
        lerpTrack = Parallel()
        startHpr = iCamParent.getHpr()
        startHpr.setX(PythonUtil.reduceAngle(startHpr[0]))
        lerpTrack.append(LerpPosHprInterval(iCamParent, lerpDur, pos=Point3(0, 0, 0), hpr=Point3(0, 0, 0), startHpr=startHpr, name=self.uniqueName('introLerpParent')))
        lerpTrack.append(LerpPosHprInterval(camera, lerpDur, pos=origCamPos, hpr=origCamHpr, blendType='easeInOut', name=self.uniqueName('introLerpCameraPos')))
        base.localAvatar.startLookAround()

        def cleanup(origCamParent = origCamParent, origCamPos = origCamPos, origCamHpr = origCamHpr, iCamParent = iCamParent):
            camera.reparentTo(origCamParent)
            camera.setPos(origCamPos)
            camera.setHpr(origCamHpr)
            iCamParent.removeNode()
            del iCamParent
            base.localAvatar.stopLookAround()

        return Sequence(Wait(waitDur),
                        lerpTrack,
                        Func(cleanup))
Пример #20
0
class PartyCogActivityGui(DirectObject):
    notify = directNotify.newCategory('PartyCogActivityGui')

    def __init__(self):
        DirectObject.__init__(self)
        self._piePowerMeter = None
        self._victoryBalanceBar = None
        self._scoreLabel = None
        self._cogTracker = None
        self._piePowerTitle = None
        self._victoryBalanceTitle = None
        self._scoreTitle = None
        self._spamWarning = None
        self._spamWarningIvalName = 'PartyCogActivityGui-SpamWarning'
        return

    def load(self):
        self._initPiePowerMeter()
        self._initScore()
        self._initCogTracker()
        self._initSpamWarning()
        self._initControlGui()
        self._initVictoryBalanceBar()

    def unload(self):
        if self._cogTracker is not None:
            self._cogTracker.destory()
            self._cogTracker = None
        if self._piePowerMeter is not None:
            self._piePowerMeter.destroy()
            self._piePowerMeter = None
        if self._piePowerTitle is not None:
            self._piePowerTitle.destroy()
            self._piePowerTitle = None
        if self._scoreLabel is not None:
            self._scoreLabel.destroy()
            self._scoreLabel = None
        if self._scoreTitle is not None:
            self._scoreTitle.destroy()
            self._scoreTitle = None
        taskMgr.remove(self._spamWarningIvalName)
        if self._spamWarning:
            self._spamWarning.destroy()
            self._spamWarning = None
        if hasattr(self, '_attackKeys'):
            self._attackKeys.detachNode()
            del self._attackKeys
        if hasattr(self, '_moveKeys'):
            self._moveKeys.detachNode()
            del self._moveKeys
        if self._victoryBalanceBar:
            self._victoryBalanceBar.detachNode()
            self._victoryBalanceBar = None
        if self._victoryBalanceBarOrange:
            self._victoryBalanceBarOrange.detachNode()
            self._victoryBalanceBarOrange = None
        if self._victoryBalanceBarPie:
            self._victoryBalanceBarPie.detachNode()
            self._victoryBalanceBarPie = None
        if self._victoryBalanceBarArrow:
            self._victoryBalanceBarArrow.detachNode()
            self._victoryBalanceBarArrow = None
        return

    def _initVictoryBalanceBar(self):
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
        victoryBalanceBar = loader.loadModel(
            'phase_13/models/parties/tt_m_gui_pty_pieToss_balanceBar')
        self._victoryBalanceBar = victoryBalanceBar.find(
            '**/*tt_t_gui_pty_pieToss_balanceBarBG')
        self._victoryBalanceBar.reparentTo(aspect2d)
        self._victoryBalanceBar.setBin('fixed', 0)
        self._victoryBalanceBar.setPos(PartyGlobals.CogActivityVictoryBarPos)
        self._victoryBalanceBar.setScale(1)
        self._victoryBalanceBarOrange = victoryBalanceBar.find(
            '**/*tt_t_gui_pty_pieToss_balanceBarOrange')
        self._victoryBalanceBarOrange.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarOrange.setBin('fixed', 1)
        self._victoryBalanceBarOrange.setPos(
            PartyGlobals.CogActivityVictoryBarOrangePos)
        self._victoryBalanceBarOrange.setScale(
            PartyGlobals.CogActivityBarStartScale, 1.0, 1.0)
        self._victoryBalanceBarPie = victoryBalanceBar.find(
            '**/*tt_t_gui_pty_pieToss_balanceBarPie')
        self._victoryBalanceBarPie.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarPie.setBin('fixed', 2)
        self._victoryBalanceBarPie.setX(
            PartyGlobals.CogActivityVictoryBarPiePos[0])
        self._victoryBalanceBarPie.setY(
            PartyGlobals.CogActivityVictoryBarPiePos[1])
        self._victoryBalanceBarPie.setZ(
            PartyGlobals.CogActivityVictoryBarPiePos[2])
        self._victoryBalanceBarPie.setScale(
            PartyGlobals.CogActivityBarPieScale)
        self._victoryBalanceBarArrow = victoryBalanceBar.find(
            '**/*tt_t_gui_pty_pieToss_balanceArrow')
        self._victoryBalanceBarArrow.reparentTo(self._victoryBalanceBarPie)
        self._victoryBalanceBarArrow.setBin('fixed', 2)
        self._victoryBalanceBarArrow.setPos(
            PartyGlobals.CogActivityVictoryBarArrow)
        self._victoryBalanceBarArrow.setScale(
            1 / PartyGlobals.CogActivityBarPieScale)

    def _initControlGui(self):
        self._attackIvalName = 'PartyCogActivityGui-attackKeys'
        self._moveIvalName = 'PartyCogActivityGui-moveKeys'
        pieTossControls = loader.loadModel(
            'phase_13/models/parties/tt_m_gui_pty_pieToss_controls')
        self._attackKeys = pieTossControls.find('**/*control*')
        self._moveKeys = pieTossControls.find('**/*arrow*')
        self._moveKeys.reparentTo(aspect2d)
        self._moveKeys.setPos(1.0, 0.0, -0.435)
        self._moveKeys.setScale(0.15)
        self._attackKeys.reparentTo(aspect2d)
        self._attackKeys.setPos(0.85, 0.0, -0.45)
        self._attackKeys.setScale(0.15)
        self._moveKeys.hide()
        self._attackKeys.hide()

    def _initPiePowerMeter(self):
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
        self._piePowerMeter = DirectWaitBar(
            frameSize=(-h, h, -w, w),
            relief=DGG.GROOVE,
            frameColor=(0.9, 0.9, 0.9, 1.0),
            borderWidth=(0.01, 0.01),
            barColor=PartyGlobals.CogActivityColors[0],
            pos=PartyGlobals.CogActivityPowerMeterPos,
            hpr=(0.0, 0.0, -90.0))
        self._piePowerMeter.setBin('fixed', 0)
        self._piePowerTitle = OnscreenText(
            text=TTLocalizer.PartyCogGuiPowerLabel,
            pos=PartyGlobals.CogActivityPowerMeterTextPos,
            scale=0.05,
            fg=(1.0, 1.0, 1.0, 1.0),
            align=TextNode.ACenter)
        self._piePowerTitle.setBin('fixed', 0)
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()

    def _initScore(self):
        self._scoreLabel = OnscreenText(
            text='0',
            pos=PartyGlobals.CogActivityScorePos,
            scale=PartyGlobals.TugOfWarTextWordScale,
            fg=(1.0, 1.0, 0.0, 1.0),
            align=TextNode.ARight,
            font=ToontownGlobals.getSignFont(),
            mayChange=True)
        self._scoreTitle = OnscreenText(text=TTLocalizer.PartyCogGuiScoreLabel,
                                        pos=PartyGlobals.CogActivityScoreTitle,
                                        scale=0.05,
                                        fg=(1.0, 1.0, 1.0, 1.0),
                                        align=TextNode.ARight)
        self._scoreLabel.hide()
        self._scoreTitle.hide()

    def _initCogTracker(self):
        self._cogTracker = PartyCogTrackerGui()

    def _initSpamWarning(self):
        self._spamWarning = OnscreenText(
            text=TTLocalizer.PartyCogGuiSpamWarning,
            scale=0.15,
            fg=(1.0, 1.0, 0, 1.0),
            shadow=(0, 0, 0, 0.62),
            mayChange=False,
            pos=(0, 0.33))
        self._spamWarning.hide()

    def showScore(self):
        self._scoreLabel.show()
        self._scoreTitle.show()

    def hideScore(self):
        self._scoreLabel.hide()
        self._scoreTitle.hide()

    def setScore(self, score=0):
        self._scoreLabel['text'] = str(score)

    def resetPiePowerMeter(self):
        self._piePowerMeter['value'] = 0

    def showPiePowerMeter(self):
        self._piePowerMeter.show()
        self._piePowerTitle.show()

    def hidePiePowerMeter(self):
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()

    def updatePiePowerMeter(self, value):
        self._piePowerMeter['value'] = value

    def getPiePowerMeterValue(self):
        return self._piePowerMeter['value']

    def hideSpamWarning(self):
        taskMgr.remove(self._spamWarningIvalName)
        if self._spamWarning:
            self._spamWarning.hide()

    def showSpamWarning(self):
        if self._spamWarning.isHidden():
            self._spamWarning.show()
            taskMgr.remove(self._spamWarningIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(
                self._spamWarning, ''),
                     Wait(PartyGlobals.CogActivitySpamWarningShowTime),
                     Func(self.hideSpamWarning),
                     name=self._spamWarningIvalName,
                     autoFinish=1).start()

    def hide(self):
        self.hidePiePowerMeter()
        self.hideScore()
        self.hideSpamWarning()
        self.hideControls()

    def disableToontownHUD(self):
        base.localAvatar.hideName()
        base.localAvatar.laffMeter.hide()
        base.setCellsActive(base.bottomCells + [base.rightCells[1]], False)

    def enableToontownHUD(self):
        base.localAvatar.showName()
        base.localAvatar.laffMeter.show()
        base.setCellsActive(base.bottomCells + [base.rightCells[1]], True)

    def setTeam(self, team):
        self.team = team
        if team == 0:
            self._cogTracker.frame.setR(180)
        self._piePowerMeter['barColor'] = PartyGlobals.CogActivityColors[team]

    def startTrackingCogs(self, cogs):
        self.cogs = cogs
        taskMgr.add(self.trackCogs, 'trackCogs')

    def trackCogs(self, task):
        if self.cogs is None:
            return
        self._updateVictoryBar()
        for i, cog in enumerate(self.cogs):
            self._cogTracker.updateCog(i, cog, self.team)

        return task.cont

    def _updateVictoryBar(self):
        if not (hasattr(self, '_victoryBalanceBar')
                and self._victoryBalanceBar):
            return
        netDistance = 0
        for cog in self.cogs:
            netDistance = netDistance + cog.targetDistance

        teamDistance = netDistance / 6.0
        self._victoryBalanceBarOrange.setScale(
            PartyGlobals.CogActivityBarStartScale +
            teamDistance * 10 * PartyGlobals.CogActivityBarUnitScale, 1.0, 1.0)
        self._victoryBalanceBarPie.setX(
            PartyGlobals.CogActivityVictoryBarPiePos[0] +
            teamDistance * 10 * PartyGlobals.CogActivityBarPieUnitMove)
        self._victoryBalanceBarPie.setY(
            PartyGlobals.CogActivityVictoryBarPiePos[1])
        self._victoryBalanceBarPie.setZ(
            PartyGlobals.CogActivityVictoryBarPiePos[2])
        if teamDistance > 0.0:
            self._victoryBalanceBarArrow.setColor(
                PartyGlobals.CogActivityColors[1])
        elif teamDistance < 0.0:
            self._victoryBalanceBarArrow.setColor(
                PartyGlobals.CogActivityColors[0])
        else:
            self._victoryBalanceBarArrow.setColor(VBase4(1.0, 1.0, 1.0, 1.0))

    def stopTrackingCogs(self):
        taskMgr.remove('trackCogs')

    def showAttackControls(self):
        if self._attackKeys.isHidden():
            self._attackKeys.show()
            taskMgr.remove(self._attackIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(self._attackKeys,
                                                          '',
                                                          scale=0.15),
                     Wait(PartyGlobals.CogActivityControlsShowTime),
                     Func(self.hideAttackControls),
                     name=self._attackIvalName,
                     autoFinish=1).start()

    def showMoveControls(self):
        if self._moveKeys.isHidden() and not self._attackKeys.isHidden():
            self._moveKeys.show()
            taskMgr.remove(self._moveIvalName)
            Sequence(ToontownIntervals.getPulseLargerIval(self._moveKeys,
                                                          '',
                                                          scale=0.15),
                     Wait(PartyGlobals.CogActivityControlsShowTime),
                     Func(self.hideMoveControls),
                     name=self._moveIvalName,
                     autoFinish=1).start()

    def hideAttackControls(self):
        taskMgr.remove(self._attackIvalName)
        if hasattr(self, '_attackKeys') and self._attackKeys:
            self._attackKeys.hide()

    def hideMoveControls(self):
        taskMgr.remove(self._moveIvalName)
        if hasattr(self, '_moveKeys') and self._moveKeys:
            self._moveKeys.hide()

    def hideControls(self):
        self.hideMoveControls()
        self.hideAttackControls()
class QuestPoster(DirectFrame):
    notify = directNotify.newCategory('QuestPoster')

    def __init__(self, quest, parent = aspect2d, **kw):
        self.quest = quest

        # Let's begin building the quest poster.
        bookModel = loader.loadModel('phase_3.5/models/gui/stickerbook_gui.bam')
        questCard = bookModel.find('**/questCard')
        optiondefs = (('relief', None, None),
         ('image', questCard, None),
         ('image_scale', (0.8, 1.0, 0.58), None),
         ('state', DGG.NORMAL, None))
        self.defineoptions(kw, optiondefs)
        DirectFrame.__init__(self, relief = None)
        self.initialiseoptions(QuestPoster)

        self.questFrame = DirectFrame(parent = self, relief = None)

        # Quest title text
        self.headline = DirectLabel(parent = self.questFrame, relief = None,
            text = self.quest.getName(),
            text_font = CIGlobals.getMinnieFont(),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = 0.05,
            text_align = TextNode.ACenter,
            text_wordwrap = 25.0, textMayChange = 1,
        pos = (0, 0, 0.23))

        # Quest information
        self.questInfo = DirectLabel(parent = self.questFrame, relief = None,
            text = '',
            text_font = CIGlobals.getToonFont(),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = 0.04,
            text_align = TextNode.ACenter,
            text_wordwrap = TEXT_WORDWRAP,
            textMayChange = 1,
        pos = (QuestGlobals.DEFAULT_INFO_POS))
        self.questInfo.hide()

        self.questInfo02 = DirectLabel(parent = self.questFrame, relief = None,
            text = '',
            text_font = CIGlobals.getToonFont(),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = 0.04,
            text_align = TextNode.ACenter,
            text_wordwrap = TEXT_WORDWRAP,
            textMayChange = 1,
        pos = (QuestGlobals.DEFAULT_INFO2_POS))
        self.questInfo02.hide()

        self.locationInfo = DirectLabel(parent = self.questFrame, relief = None,
            text = 'N/A',
            text_font = CIGlobals.getToonFont(),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = TEXT_SCALE,
            text_align = TextNode.ACenter,
            text_wordwrap = TEXT_WORDWRAP,
            textMayChange = 1,
        pos = (0, 0, -0.115))
        self.locationInfo.hide()

        # C'mon Brian this one is obvious
        self.rewardText = DirectLabel(parent = self.questFrame, relief = None,
            text = '',
            text_fg = QuestGlobals.REWARD_RED,
            text_scale = 0.0425,
            text_align = TextNode.ALeft,
            text_wordwrap = 17.0,
            textMayChange = 1,
        pos = (-0.36, 0, -0.26))
        self.rewardText.hide()

        self.lPictureFrame = DirectFrame(parent = self.questFrame, relief = None,
            image = bookModel.find('**/questPictureFrame'),
            image_scale = QuestGlobals.IMAGE_SCALE_SMALL,
            text = '',
            text_pos = (0, -0.11),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = TEXT_SCALE,
            text_align = TextNode.ACenter,
            text_wordwrap = 11.0,
            pos = (QuestGlobals.DEFAULT_LEFT_PICTURE_POS),
        textMayChange = 1)
        self.lPictureFrame.hide()

        self.rPictureFrame = DirectFrame(parent = self.questFrame, relief = None,
            image = bookModel.find('**/questPictureFrame'),
            image_scale = QuestGlobals.IMAGE_SCALE_SMALL,
            text = '', text_pos = (0, -0.11),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = TEXT_SCALE,
            text_align = TextNode.ACenter,
            text_wordwrap = 11.0,
            textMayChange = 1,
        pos = (QuestGlobals.DEFAULT_RIGHT_PICTURE_POS))
        self.rPictureFrame['image_color'] = Vec4(*QuestGlobals.GREEN)
        self.rPictureFrame.hide()

        self.lQuestIcon = DirectFrame(parent = self.lPictureFrame, relief = None,
            text = ' ', text_font = CIGlobals.getSuitFont(),
            text_pos = (0, -0.03),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = 0.13,
            text_align = TextNode.ACenter,
            text_wordwrap = 13.0,
        textMayChange = 1)
        self.lQuestIcon.setColorOff(-1)

        self.rQuestIcon = DirectFrame(parent = self.rPictureFrame, relief = None,
            text = ' ',
            text_font = CIGlobals.getSuitFont(),
            text_pos = (0, -0.03),
            text_fg = QuestGlobals.TEXT_COLOR,
            text_scale = 0.13,
            text_align = TextNode.ACenter,
            text_wordwrap = 13.0,
        textMayChange = 1)
        self.rQuestIcon.setColorOff(-1)

        head = SuitBank.PennyPincher.getHead().generate()
        head.setDepthTest(True)
        head.setDepthWrite(True)
        head.setScale(0.25)
        for part in head.getChildren():
            part.setDepthTest(True)
            part.setDepthWrite(True)
        self.fitGeometry(head, fFlip = 1)
        self.rQuestIcon['geom'] = head
        self.rQuestIcon['geom_scale'] = QuestGlobals.IMAGE_SCALE_SMALL
        self.rQuestIcon['geom_pos'] = Point3(0, 10, -0.05)
        self.rQuestIcon['geom_hpr'] = Point3(180, 0, 0)
        self.rQuestIcon.initialiseoptions(DirectFrame)

        self.auxText = DirectLabel(parent = self.questFrame, relief = None,
            text = 'Recover',
            text_font = CIGlobals.getToonFont(),
            text_scale = QuestGlobals.QPauxText,
            text_fg = QuestGlobals.TEXT_COLOR,
            text_align = TextNode.ACenter,
            pos = (QuestGlobals.DEFAULT_AUX_POS),
        textMayChange=1)
        self.auxText.hide()

        self.middleText = DirectLabel(parent = self.questFrame, relief = None,
            text = 'from:',
            text_font = CIGlobals.getToonFont(),
            text_scale = QuestGlobals.QPauxText,
            text_fg = QuestGlobals.TEXT_COLOR,
            text_align = TextNode.ACenter,
            pos = (QuestGlobals.DEFAULT_MIDDLE_POS),
        textMayChange=1)
        self.middleText.hide()

        self.questProgress = DirectWaitBar(parent = self.questFrame, relief = DGG.SUNKEN,
            frameSize=(-0.95, 0.95, -0.1, 0.12),
            borderWidth = (0.025, 0.025),
            scale = 0.2,
            frameColor = (0.945, 0.875, 0.706, 1.0),
            barColor=(0.5, 0.7, 0.5, 1),
            text='0/0',
            text_font = CIGlobals.getToonFont(),
            text_scale = 0.19,
            text_fg = (0.05, 0.14, 0.4, 1),
            text_align = TextNode.ACenter,
            text_pos = (0, -0.05), #-0.02
        pos = (0, 0, -0.2425))
        self.questProgress.hide()

        rewardFrameGeom = loader.loadModel('phase_4/models/gui/gag_shop_purchase_gui.bam')
        self.rewardFrame = DirectFrame(parent = self.questFrame, relief = None,
            geom = rewardFrameGeom.find('**/Goofys_Sign'),
            geom_scale = (0.615, 0, 0.4),
            pos = (-0.01, 0, -0.25)
        )

        jellybeanJar = QuestGlobals.getFilmIcon()
        self.lRewardFrame = DirectFrame(parent = self.rewardFrame, relief = None,
            geom = jellybeanJar,
            geom_scale = QuestGlobals.TP_ACCESS_SCALE,
            sortOrder = 1,
        pos = (QuestGlobals.LEFT_TP_ACCESS_POS))
        self.lRewardFrame.setBin('gui-popup', 30)

        self.lRewardAmt = DirectFrame(parent = self.questFrame, relief = None,
            geom = rewardFrameGeom.find('**/Char_Pnl'),
            geom_scale = (0.15, 0, 0.1275),
            text = '#1',
            text_font = CIGlobals.getToonFont(),
            text_scale = 0.04,
            text_fg = (0, 0, 0, 1),
            text_align = TextNode.ACenter,
            text_pos = (0, -0.01),
            sortOrder = 2,
        pos = (-0.285, 0, -0.255))
        self.lRewardAmt.setBin('gui-popup', 40)

        self.rRewardFrame = DirectFrame(parent = self.rewardFrame, relief = None,
            geom = QuestGlobals.getJBIcon(),
            geom_scale = QuestGlobals.JB_JAR_SCALE,
        pos = QuestGlobals.RIGHT_JB_JAR_POS)

        self.rRewardAmt = DirectFrame(parent = self.questFrame, relief = None,
            geom = rewardFrameGeom.find('**/Char_Pnl'),
            geom_scale = (0.15, 0, 0.1275),
            text = '25',
            text_font = CIGlobals.getToonFont(),
            text_scale = 0.04,
            text_fg = (0, 0, 0, 1),
            text_align = TextNode.ACenter,
            text_pos = (0, -0.01),
        pos = (0.2725, 0, -0.255))
        self.rRewardAmt.setBin('gui-popup', 40)

        rewardFrameGeom.removeNode()

        # This is the rotated text on the side.
        self.sideInfo = DirectLabel(parent = self.questFrame, relief = None,
            text = QuestGlobals.JUST_FOR_FUN,
            text_fg = (0.0, 0.439, 1.0, 1.0),
            text_shadow = (0, 0, 0, 1),
            pos = (-0.2825, 0, 0.2),
        scale = 0.03)
        self.sideInfo.setR(-30)
        self.sideInfo.hide()

        bookModel.removeNode()
        self.laffMeter = None
        
        self.hide()
        return
    
    def handleIcon(self, objective, geom, scale, icon):
        isHead = True if type(geom) == ToonHead else geom.getName() == ('%sHead' % CIGlobals.Suit)

        if isHead:
            geom.setDepthWrite(1)
            geom.setDepthTest(1)
            self.fitGeometry(geom, fFlip = 1)
            
            if isinstance(objective, VisitNPCObjective) and icon == self.rQuestIcon:
                icon.setPos(icon.getX(), icon.getY(), icon.getZ() + 0.05)
                icon.setH(180)
            elif isinstance(objective, CogObjective):
                icon.setScale(QuestGlobals.IMAGE_SCALE_SMALL)
                icon.setPos(icon.getX(), icon.getY(), icon.getZ() - 0.04)
                if icon == self.lQuestIcon:
                    icon.setH(180)
            
            icon['geom'] = geom
            icon['geom_scale'] = QuestGlobals.IMAGE_SCALE_SMALL
        else:
            icon['geom'] = geom
            icon['geom_scale'] = scale

    def update(self):
        objective = self.quest.getCurrentObjective()
        objective.updateInfo()

        # Let's setup the quest info.
        self.questInfo.setPos(self.quest.getInfoPos())
        self.questInfo['text'] = self.quest.getInfoText()
        self.questInfo02.setPos(self.quest.getInfo02Pos())
        self.questInfo02['text'] = self.quest.getInfo02Text()
        
        # Let's move the picture frames to the positions we want them in.
        self.lPictureFrame.setPos(self.quest.getLeftPicturePos())
        self.rPictureFrame.setPos(self.quest.getRightPicturePos())
        
        editLeftAtr = isinstance(objective, VisitNPCObjective) or isinstance(objective, CogObjective)
        if editLeftAtr and objective.getDidEditLeft() or not editLeftAtr:
            geom = self.quest.getLeftIconGeom()
            scale = self.quest.getLeftIconScale()
            icon = self.lQuestIcon
            self.handleIcon(objective, geom, scale, icon)
            self.handleIcon(objective, self.quest.getRightIconGeom(), self.quest.getRightIconScale(), self.rQuestIcon)
        else:
            geom = self.quest.getRightIconGeom()
            scale = self.quest.getRightIconScale()
            icon = self.rQuestIcon
            self.handleIcon(objective, geom, scale, icon)
            self.handleIcon(objective, self.quest.getLeftIconGeom(), self.quest.getLeftIconScale(), self.lQuestIcon)

        if self.questInfo02['text'] == '':
            self.rPictureFrame.hide()
            self.questInfo02.hide()
        else:
            self.rPictureFrame.show()
            self.questInfo02.show()

        self.middleText['text'] = self.quest.getMiddleText()
        if not self.middleText['text'] == '':
            self.middleText.show()

        self.questInfo.show()
        self.lPictureFrame.show()

        # Let's set the location text.
        self.locationInfo['text'] = self.quest.getLocationText()
        self.locationInfo['text_pos'] = (0, self.quest.getLocationY())
        self.locationInfo.show()

        # Let's set the progress bar up.
        self.questProgress['text'] = self.quest.getProgressText()
        if len(self.questProgress['text']) > 0 and not objective.finished():
            self.questProgress.show()
            self.questProgress['range'] = objective.getNeededAmount()
            self.questProgress['value'] = objective.getProgress() & pow(2, 16) - 1
        else:
            self.questProgress.hide()

        # Let's setup the aux text.
        self.auxText.setPos(self.quest.getAuxPos())
        self.auxText['text'] = self.quest.getAuxText()
        self.auxText.show()

        maxHP = base.localAvatar.getMaxHealth()
        
        # Let's setup the rewards.
        for i in xrange(0, len(self.quest.getRewards())):
            reward = self.quest.getRewards()[i]
            frame = self.lRewardFrame if (i == 0) else self.rRewardFrame
            info = self.lRewardAmt if (i == 0) else self.rRewardAmt
            rType = reward.getType()
            if(rType == RewardType.JELLYBEANS):
                frame['pos'] = QuestGlobals.LEFT_JB_JAR_POS if (i == 0) else QuestGlobals.RIGHT_JB_JAR_POS
                frame['geom'] = QuestGlobals.getJBIcon()
                frame['geom_scale'] = QuestGlobals.JB_JAR_SCALE
                info['text'] = str(reward.getModifier())
            elif(rType == RewardType.TELEPORT_ACCESS or rType == RewardType.GAG_FRAME):
                frame['pos'] = QuestGlobals.LEFT_TP_ACCESS_POS if(i == 0) else QuestGlobals.RIGHT_TP_ACCESS_POS
                frame['geom'] = QuestGlobals.getTPAccessIcon() if(rType == RewardType.TELEPORT_ACCESS) else QuestGlobals.getFilmIcon()
                frame['geom_scale'] = QuestGlobals.TP_ACCESS_SCALE
                info['text'] = 'N/A' if(rType == RewardType.TELEPORT_ACCESS) else '#%s' % (str(reward.getModifier()))
            elif(rType == RewardType.LAFF_POINTS):
                frame.initialiseoptions(DirectFrame)
                r, g, b, _ = base.localAvatar.getHeadColor()
                pos = QuestGlobals.LEFT_LAFF_METER_POS if(i == 0) else QuestGlobals.RIGHT_LAFF_METER_POS

                # Create the laff meter with the new health.
                hp = maxHP + reward.getModifier()
                laffMeter = LaffOMeter()
                laffMeter.generate(r, g, b, base.localAvatar.getAnimal(), maxHP = hp, initialHP = hp)

                # Let's position the laff meter.
                frame['geom'] = laffMeter
                frame['geom_scale'] = QuestGlobals.LAFF_METER_SCALE
                frame.setPos(pos)
                info['text'] = '+%s' % (str(reward.getModifier()))
                laffMeter.destroy()
                laffMeter = None

        # Hide or show the other reward depending on if there's 2 rewards.
        if(len(self.quest.getRewards()) == 1):
            self.rRewardFrame.hide()
            self.rRewardAmt.hide()
        else:
            self.rRewardFrame.show()
            self.rRewardAmt.show()

        if objective.finished():
            self.setColor(Vec4(*QuestGlobals.LIGHT_GREEN))
            self.sideInfo['text'] = 'Completed!'
            self.sideInfo.show()
            
        self.questInfo.initialiseoptions(DirectLabel)
        self.questInfo02.initialiseoptions(DirectLabel)
        self.locationInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame.initialiseoptions(DirectFrame)
        self.rPictureFrame.initialiseoptions(DirectFrame)
        self.lQuestIcon.initialiseoptions(DirectFrame)
        self.rQuestIcon.initialiseoptions(DirectFrame)
        self.auxText.initialiseoptions(DirectLabel)
        self.middleText.initialiseoptions(DirectLabel)
        self.sideInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame['image_color'] = self.quest.getPictureFrameColor()
        self.rPictureFrame['image_color'] = self.quest.getPictureFrameColor()

    def fitGeometry(self, geom, fFlip = 0, dimension = 0.8):
        p1 = Point3()
        p2 = Point3()
        geom.calcTightBounds(p1, p2)
        if fFlip:
            t = p1[0]
            p1.setX(-p2[0])
            p2.setX(-t)
        d = p2 - p1
        biggest = max(d[0], d[2])
        s = dimension / biggest
        mid = (p1 + d / 2.0) * s
        geomXform = hidden.attachNewNode('geomXform')
        for child in geom.getChildren():
            child.reparentTo(geomXform)

        geomXform.setPosHprScale(-mid[0], -mid[1] + 1, -mid[2], 180, 0, 0, s, s, s)
        geomXform.reparentTo(geom)

    def destroy(self):
        self._deleteGeoms()
        DirectFrame.destroy(self)

    def _deleteGeoms(self):
        for icon in (self.lQuestIcon, self.rQuestIcon):
            geom = icon['geom']
            if geom and hasattr(geom, 'delete'):
                geom.delete()
                
    def getQuest(self):
        return self.quest
Пример #22
0
class PartyCogActivityGui(DirectObject):
    notify = directNotify.newCategory("PartyCogActivityGui")
    
    def __init__(self):
        DirectObject.__init__(self)
        
        self._piePowerMeter = None
        self._victoryBalanceBar = None
        self._scoreLabel = None
        self._cogTracker = None
        self._piePowerTitle = None
        self._victoryBalanceTitle = None
        self._scoreTitle = None
        self._spamWarning = None
        self._spamWarningIvalName = "PartyCogActivityGui-SpamWarning"       
        
    def load(self):
        self._initPiePowerMeter()
        self._initScore()
        self._initCogTracker()
        self._initSpamWarning()
        self._initControlGui()
        self._initVictoryBalanceBar()
        
    def unload(self):
        if self._cogTracker is not None:
            self._cogTracker.destory()
            self._cogTracker = None
            
        if self._piePowerMeter is not None:
            self._piePowerMeter.destroy()
            self._piePowerMeter = None
            
        if self._piePowerTitle is not None:
            self._piePowerTitle.destroy()
            self._piePowerTitle = None
        
        if self._scoreLabel is not None:
            self._scoreLabel.destroy()
            self._scoreLabel = None
            
        if self._scoreTitle is not None:
            self._scoreTitle.destroy()
            self._scoreTitle = None
            
        taskMgr.remove(self._spamWarningIvalName)
        
        if self._spamWarning:
            self._spamWarning.destroy()
            self._spamWarning = None
            
        if hasattr(self, '_attackKeys'):
            self._attackKeys.detachNode()
            del self._attackKeys
            
        if hasattr(self, '_moveKeys'):
            self._moveKeys.detachNode()
            del self._moveKeys
            
        if self._victoryBalanceBar:
            self._victoryBalanceBar.detachNode()
            self._victoryBalanceBar = None    
            
        if self._victoryBalanceBarOrange:
            self._victoryBalanceBarOrange.detachNode()
            self._victoryBalanceBarOrange = None    
            
        if self._victoryBalanceBarPie:
            self._victoryBalanceBarPie.detachNode()
            self._victoryBalanceBarPie = None
            
        if self._victoryBalanceBarArrow:
            self._victoryBalanceBarArrow.detachNode()
            self._victoryBalanceBarArrow = None
            
    def _initVictoryBalanceBar(self):
        
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
        
        victoryBalanceBar = loader.loadModel("phase_13/models/parties/tt_m_gui_pty_pieToss_balanceBar")
        self._victoryBalanceBar = victoryBalanceBar.find("**/*tt_t_gui_pty_pieToss_balanceBarBG")
        self._victoryBalanceBar.reparentTo(aspect2d)
        self._victoryBalanceBar.setBin("fixed", 0)
        self._victoryBalanceBar.setPos(PartyGlobals.CogActivityVictoryBarPos)
        self._victoryBalanceBar.setScale(1)
        
        self._victoryBalanceBarOrange = victoryBalanceBar.find("**/*tt_t_gui_pty_pieToss_balanceBarOrange")
        self._victoryBalanceBarOrange.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarOrange.setBin("fixed", 1)
        self._victoryBalanceBarOrange.setPos(PartyGlobals.CogActivityVictoryBarOrangePos)
        self._victoryBalanceBarOrange.setScale(PartyGlobals.CogActivityBarStartScale, 1.0, 1.0)
        
        self._victoryBalanceBarPie = victoryBalanceBar.find("**/*tt_t_gui_pty_pieToss_balanceBarPie")
        self._victoryBalanceBarPie.reparentTo(self._victoryBalanceBar)
        self._victoryBalanceBarPie.setBin("fixed", 2)
        self._victoryBalanceBarPie.setX(PartyGlobals.CogActivityVictoryBarPiePos[0])         
        self._victoryBalanceBarPie.setY(PartyGlobals.CogActivityVictoryBarPiePos[1])        
        self._victoryBalanceBarPie.setZ(PartyGlobals.CogActivityVictoryBarPiePos[2])        
        self._victoryBalanceBarPie.setScale(PartyGlobals.CogActivityBarPieScale)    
        
        self._victoryBalanceBarArrow = victoryBalanceBar.find("**/*tt_t_gui_pty_pieToss_balanceArrow")
        self._victoryBalanceBarArrow.reparentTo(self._victoryBalanceBarPie)
        self._victoryBalanceBarArrow.setBin("fixed", 2)
        self._victoryBalanceBarArrow.setPos(PartyGlobals.CogActivityVictoryBarArrow)
        self._victoryBalanceBarArrow.setScale(1/PartyGlobals.CogActivityBarPieScale)    
        
        # self._victoryBalanceBar = DirectWaitBar(
            # frameSize = (-h, h, -w, w),
            # relief = DGG.SUNKEN,
            # frameColor = PartyGlobals.CogActivityColors[0],
            # borderWidth = (0.0, 0.0),
            # barColor = PartyGlobals.CogActivityColors[1],
            # pos = PartyGlobals.CogActivityVictoryBarPos,
            # hpr = (0.0, 0.0, -90.0),
            # )
        
        # self._victoryBalanceBar.setBin("fixed", 0)
        # self._victoryBalanceBar["value"] = 50
        
    def _initControlGui(self):
        self._attackIvalName = "PartyCogActivityGui-attackKeys" 
        self._moveIvalName = "PartyCogActivityGui-moveKeys" 
        pieTossControls = loader.loadModel("phase_13/models/parties/tt_m_gui_pty_pieToss_controls")
        self._attackKeys = pieTossControls.find("**/*control*")
        self._moveKeys = pieTossControls.find("**/*arrow*")
        
        self._moveKeys.reparentTo(aspect2d)
        self._moveKeys.setPos(1.0, 0.0, -0.435)
        self._moveKeys.setScale(0.15)
        self._attackKeys.reparentTo(aspect2d)
        self._attackKeys.setPos(0.85, 0.0, -0.45)
        self._attackKeys.setScale(0.15)
        
        self._moveKeys.hide()
        self._attackKeys.hide()
            
    def _initPiePowerMeter(self):
        h = PartyGlobals.CogActivityPowerMeterHeight / 2.0
        w = PartyGlobals.CogActivityPowerMeterWidth / 2.0
    
        self._piePowerMeter = DirectWaitBar(
            frameSize = (-h, h, -w, w),
            relief = DGG.GROOVE,
            frameColor = (0.9, 0.9, 0.9, 1.0),
            borderWidth = (0.01, 0.01),
            barColor = PartyGlobals.CogActivityColors[0],
            pos = PartyGlobals.CogActivityPowerMeterPos,
            hpr = (0.0, 0.0, -90.0),
            )
        
        self._piePowerMeter.setBin("fixed", 0)
        
        self._piePowerTitle = OnscreenText(
            text=TTLocalizer.PartyCogGuiPowerLabel,
            pos=PartyGlobals.CogActivityPowerMeterTextPos,
            scale=0.05,
            fg=(1.0, 1.0, 1.0, 1.0),
            align=TextNode.ACenter,
            )
            
        self._piePowerTitle.setBin("fixed", 0)
        
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()  
    
    def _initScore(self):
        self._scoreLabel = OnscreenText(
            text="0",
            pos=PartyGlobals.CogActivityScorePos,
            scale=PartyGlobals.TugOfWarTextWordScale,
            #fg=base.localAvatar.style.getHeadColor(),
            #fg=PartyGlobals.TeamActivityStatusColor,
            fg=(1.0, 1.0, 0.0, 1.0),
            align=TextNode.ARight,
            font=ToontownGlobals.getSignFont(),
            mayChange=True,
            )
        
        self._scoreTitle = OnscreenText(
            text=TTLocalizer.PartyCogGuiScoreLabel,
            pos=PartyGlobals.CogActivityScoreTitle,
            scale=0.05,
            fg=(1.0, 1.0, 1.0, 1.0),
            #fg=(0.0, 0.0, 0.0, 1.0),
            align=TextNode.ARight,
            )        
        
        self._scoreLabel.hide()
        self._scoreTitle.hide()
    
    def _initCogTracker(self):
        self._cogTracker = PartyCogTrackerGui()
        
    def _initSpamWarning(self):
        self._spamWarning = OnscreenText(
            text = TTLocalizer.PartyCogGuiSpamWarning,
            scale = 0.15,
            fg = (1.0, 1.0, 0, 1.0),
            shadow = (0, 0, 0, 0.62),
            mayChange = False,
            pos = (0, 0.33)
            )
        self._spamWarning.hide()
    
    def showScore(self):
        self._scoreLabel.show()
        self._scoreTitle.show()
        
    def hideScore(self):
        self._scoreLabel.hide()
        self._scoreTitle.hide()
        
    def setScore(self, score=0):
        self._scoreLabel["text"] = str(score)
        
    def resetPiePowerMeter(self):
        self._piePowerMeter["value"] = 0
        
    def showPiePowerMeter(self):
        self._piePowerMeter.show()
        self._piePowerTitle.show()
        
    def hidePiePowerMeter(self):
        self._piePowerMeter.hide()
        self._piePowerTitle.hide()
        
    def updatePiePowerMeter(self, value):
        self._piePowerMeter["value"] = value
        
        # Uncomment this part if you want the bar to by a psychedelic change of colors.
#        self._piePowerMeter["barColor"] = (
#            min(value * 2, 100) / 100.0,
#            min((100 - value) * 2, 100) / 100.0,
#            0.0,
#            1.0
#            )
        
    def getPiePowerMeterValue(self):
        return self._piePowerMeter["value"]

    def hideSpamWarning(self):
        taskMgr.remove(self._spamWarningIvalName)
        
        if self._spamWarning:
            self._spamWarning.hide()
        
    def showSpamWarning(self):
        if self._spamWarning.isHidden():
            self._spamWarning.show()

            taskMgr.remove(self._spamWarningIvalName)
            
            Sequence(
                # Boing it in to grab attention.
                ToontownIntervals.getPulseLargerIval(self._spamWarning, ""),
                
                # Let it sit on-screen for a while.
                Wait(PartyGlobals.CogActivitySpamWarningShowTime),
                
                # Then get rid of it.
                Func(self.hideSpamWarning),
                
                name=self._spamWarningIvalName,
                autoFinish=1
                ).start()
    
    def hide(self):
        self.hidePiePowerMeter()
        self.hideScore()
        self.hideSpamWarning()
        self.hideControls()
        
    def disableToontownHUD(self):
        base.localAvatar.hideName()
        base.localAvatar.laffMeter.hide()
        base.setCellsAvailable(base.bottomCells + [base.rightCells[1]], False)
    
    def enableToontownHUD(self):
        base.localAvatar.showName()
        base.localAvatar.laffMeter.show()
        base.setCellsAvailable(base.bottomCells + [base.rightCells[1]], True)

    def setTeam(self, team):
        self.team = team
        if team == 0:
            self._cogTracker.frame.setR(180)
            
        # The old default power bar color was blue, but that was confusing because there's a blue team.
        # So the idea here is to make the color the same as the player's team.
        self._piePowerMeter["barColor"] = PartyGlobals.CogActivityColors[team]
        
    def startTrackingCogs(self, cogs):
        self.cogs = cogs
        taskMgr.add(self.trackCogs, "trackCogs")
    
    def trackCogs(self, task):
        if self.cogs is None:
            return
            
        self._updateVictoryBar()
        
        for i, cog in enumerate(self.cogs):
            self._cogTracker.updateCog(i,cog,self.team)

        return task.cont
        
    def _updateVictoryBar(self):
        if not ( hasattr(self, "_victoryBalanceBar") and self._victoryBalanceBar):
            return
        netDistance = 0
        for cog in self.cogs:
            netDistance = netDistance + cog.targetDistance
        teamDistance = netDistance/6.0
        self._victoryBalanceBarOrange.setScale(PartyGlobals.CogActivityBarStartScale + \
                                                            (teamDistance * 10 * PartyGlobals.CogActivityBarUnitScale),1.0,1.0)
        #self._victoryBalanceBar["value"] = 50 + (netDistance/6 * 100)
        self._victoryBalanceBarPie.setX(PartyGlobals.CogActivityVictoryBarPiePos[0] + \
                                                      (teamDistance * 10 *PartyGlobals.CogActivityBarPieUnitMove))         
        self._victoryBalanceBarPie.setY(PartyGlobals.CogActivityVictoryBarPiePos[1])        
        self._victoryBalanceBarPie.setZ(PartyGlobals.CogActivityVictoryBarPiePos[2])       
        
        if teamDistance>0.0:
            self._victoryBalanceBarArrow.setColor(PartyGlobals.CogActivityColors[1])
        elif teamDistance<0.0:
            self._victoryBalanceBarArrow.setColor(PartyGlobals.CogActivityColors[0])
        else:
            self._victoryBalanceBarArrow.setColor(VBase4(1.0,1.0,1.0,1.0))
        
    def stopTrackingCogs(self):
        taskMgr.remove("trackCogs")
        
    def showAttackControls(self):
        if self._attackKeys.isHidden():
            self._attackKeys.show()

            taskMgr.remove(self._attackIvalName)
            
            Sequence(
                ToontownIntervals.getPulseLargerIval(self._attackKeys, "", scale = 0.15),
                Wait(PartyGlobals.CogActivityControlsShowTime),
                Func(self.hideAttackControls),
                name=self._attackIvalName,
                autoFinish=1
                ).start()
        
        
    def showMoveControls(self):
        if self._moveKeys.isHidden() and not self._attackKeys.isHidden():
            self._moveKeys.show()

            taskMgr.remove(self._moveIvalName)
            
            Sequence(
                ToontownIntervals.getPulseLargerIval(self._moveKeys, "", scale = 0.15),
                Wait(PartyGlobals.CogActivityControlsShowTime),
                Func(self.hideMoveControls),
                name=self._moveIvalName,
                autoFinish=1
                ).start()
        
    def hideAttackControls(self):
        taskMgr.remove(self._attackIvalName)
        if hasattr(self, "_attackKeys") and self._attackKeys:
            self._attackKeys.hide()
        
    def hideMoveControls(self):
        taskMgr.remove(self._moveIvalName)
        if hasattr(self, "_moveKeys") and self._moveKeys:
            self._moveKeys.hide()
        
    def hideControls(self):
        self.hideMoveControls()
        self.hideAttackControls()
Пример #23
0
class ThrowGag(Gag):
    def __init__(self,
                 name,
                 model,
                 damage,
                 hitSfx,
                 splatColor,
                 anim=None,
                 scale=1):
        Gag.__init__(self,
                     name,
                     model,
                     damage,
                     GagType.THROW,
                     hitSfx,
                     anim=anim,
                     scale=scale)
        self.splatScale = GagGlobals.splatSizes[self.name]
        self.splatColor = splatColor
        self.entities = []
        self.timeout = 1.0
        self.power = 50
        self.powerBar = None
        self.tossPieStart = 0
        self.pieSpeed = 0.2
        self.pieExponent = 0.75

    def setAvatar(self, avatar):
        Gag.setAvatar(self, avatar)
        if self.isLocal():
            self.powerBar = DirectWaitBar(range=150,
                                          frameColor=(1, 1, 1, 1),
                                          barColor=(0.286, 0.901, 1, 1),
                                          relief=DGG.RAISED,
                                          borderWidth=(0.04, 0.04),
                                          pos=(0, 0, 0.85),
                                          scale=0.2,
                                          hpr=(0, 0, 0),
                                          parent=aspect2d,
                                          frameSize=(-0.85, 0.85, -0.12, 0.12))
            self.powerBar.hide()

    def __getPiePower(self, time):
        elapsed = max(time - self.tossPieStart, 0.0)
        t = elapsed / self.pieSpeed
        t = math.pow(t, self.pieExponent)
        power = int(t * 150) % 300
        if power > 150:
            power = 300 - power
        return power

    def build(self):
        if not self.gag:
            Gag.build(self)
            self.equip()
            if self.anim and self.gag:
                self.gag.loop('chan')
        return self.gag

    def start(self):
        super(ThrowGag, self).start()
        self.build()
        self.avatar.setPlayRate(self.playRate, 'pie')
        self.avatar.play('pie', fromFrame=0, toFrame=45)
        if self.isLocal():
            taskMgr.remove("hidePowerBarTask" + str(hash(self)))
            self.powerBar.show()
            self.startPowerBar()

    def startPowerBar(self):
        self.tossPieStart = globalClock.getFrameTime()
        taskMgr.add(self.__powerBarUpdate, "powerBarUpdate" + str(hash(self)))

    def __powerBarUpdate(self, task):
        if self.powerBar is None:
            return task.done
        self.powerBar['value'] = self.__getPiePower(globalClock.getFrameTime())
        return task.cont

    def stopPowerBar(self):
        taskMgr.remove("powerBarUpdate" + str(hash(self)))
        self.power = self.powerBar['value']

    def __hidePowerBarTask(self, task):
        self.powerBar.hide()

    def throw(self):
        if self.isLocal():
            self.stopPowerBar()
            self.power += 50
            self.power = 250 - self.power
            print self.power
            # Make other toons set the throw power on my gag.
            base.localAvatar.sendUpdate('setThrowPower', [self.id, self.power])
            self.startTimeout()
            taskMgr.doMethodLater(1.5, self.__hidePowerBarTask,
                                  "hidePowerBarTask" + str(hash(self)))
        self.avatar.play('pie', fromFrame=45, toFrame=90)
        if not self.gag:
            self.build()

    def setPower(self, power):
        self.power = power

    def release(self):
        Gag.release(self)
        base.audio3d.attachSoundToObject(self.woosh, self.gag)
        base.playSfx(self.woosh, node=self.gag)

        throwPath = NodePath('ThrowPath')
        throwPath.reparentTo(self.avatar)
        throwPath.setScale(render, 1)
        throwPath.setPos(0, self.power, -90)
        throwPath.setHpr(90, -90, 90)

        entity = self.gag

        if not entity:
            entity = self.build()

        entity.wrtReparentTo(render)
        entity.setHpr(throwPath.getHpr(render))
        self.gag = None

        if not self.handJoint:
            self.handJoint = self.avatar.find('**/def_joint_right_hold')

        track = ProjectileInterval(entity,
                                   startPos=self.handJoint.getPos(render),
                                   endPos=throwPath.getPos(render),
                                   gravityMult=0.9,
                                   duration=3)
        event = self.avatar.uniqueName('throwIvalDone') + '-' + str(
            hash(entity))
        track.setDoneEvent(event)
        base.acceptOnce(event, self.__handlePieIvalDone, [entity])
        track.start()
        self.entities.append([entity, track])
        if self.isLocal():
            self.buildCollisions(entity)
            base.localAvatar.sendUpdate('usedGag', [self.id])
        self.reset()

    def __handlePieIvalDone(self, pie):
        if not pie.isEmpty():
            pie.removeNode()

    def handleSplat(self):
        base.audio3d.detachSound(self.woosh)
        if self.woosh: self.woosh.stop()
        self.buildSplat(self.splatScale, self.splatColor)
        base.audio3d.attachSoundToObject(self.hitSfx, self.splat)
        self.splat.reparentTo(render)
        self.splat.setPos(self.splatPos)
        base.playSfx(self.hitSfx, node=self.splat)
        self.cleanupEntity(self.splatPos)
        self.splatPos = None
        taskMgr.doMethodLater(0.5, self.delSplat, 'Delete Splat')
        return

    def cleanupEntity(self, pos):
        closestPie = None
        trackOfClosestPie = None
        pieHash2range = {}
        for entity, track in self.entities:
            if not entity.isEmpty():
                pieHash2range[hash(entity)] = (entity.getPos(render) -
                                               pos).length()
        ranges = []
        for distance in pieHash2range.values():
            ranges.append(distance)
        ranges.sort()
        for pieHash in pieHash2range.keys():
            distance = pieHash2range[pieHash]
            if not distance is None and distance == ranges[0]:
                for entity, track in self.entities:
                    if hash(entity) == pieHash:
                        closestPie = entity
                        trackOfClosestPie = track
                        break
            break
        if closestPie != None and trackOfClosestPie != None:
            if [closestPie, trackOfClosestPie] in self.entities:
                self.entities.remove([closestPie, trackOfClosestPie])
            if not closestPie.isEmpty():
                if isinstance(closestPie, Actor):
                    closestPie.cleanup()
                closestPie.removeNode()

    def onCollision(self, entry):
        intoNP = entry.getIntoNodePath()
        avNP = intoNP.getParent()
        fromNP = entry.getFromNodePath().getParent()

        if fromNP.isEmpty():
            return

        for key in base.cr.doId2do.keys():
            obj = base.cr.doId2do[key]
            if obj.__class__.__name__ in CIGlobals.SuitClasses:
                if obj.getKey() == avNP.getKey():
                    obj.sendUpdate('hitByGag', [self.getID()])
            elif obj.__class__.__name__ == "DistributedToon":
                if obj.getKey() == avNP.getKey():
                    if obj.getHealth() < obj.getMaxHealth():
                        if obj != self.avatar:
                            self.avatar.sendUpdate(
                                'toonHitByPie',
                                [obj.doId, self.getID()])
                        else:
                            self.avatar.acceptOnce('gagSensor-into',
                                                   self.onCollision)
                            return
            elif obj.__class__.__name__ == "DistributedPieTurret":
                if obj.getKey() == avNP.getKey():
                    if obj.getHealth() < obj.getMaxHealth():
                        self.avatar.sendUpdate(
                            'toonHitByPie', [obj.doId, self.getID()])

        self.splatPos = fromNP.getPos()
        self.avatar.sendUpdate('setSplatPos', [
            self.getID(),
            self.splatPos.getX(),
            self.splatPos.getY(),
            self.splatPos.getZ()
        ])
        self.handleSplat()

    def buildCollisions(self, entity):
        pieSphere = CollisionSphere(0, 0, 0, 1)
        pieSensor = CollisionNode('gagSensor')
        pieSensor.addSolid(pieSphere)
        pieNP = entity.attachNewNode(pieSensor)
        pieNP.setCollideMask(BitMask32(0))
        pieNP.node().setFromCollideMask(CIGlobals.WallBitmask
                                        | CIGlobals.FloorBitmask)

        event = CollisionHandlerEvent()
        event.set_in_pattern("%fn-into")
        event.set_out_pattern("%fn-out")
        base.cTrav.add_collider(pieNP, event)
        self.avatar.acceptOnce('gagSensor-into', self.onCollision)

    def unEquip(self):
        taskMgr.remove("hidePowerBarTask" + str(hash(self)))
        if self.powerBar:
            self.powerBar.hide()
        Gag.unEquip(self)

    def delete(self):
        taskMgr.remove("powerBarUpdate" + str(hash(self)))
        taskMgr.remove("hidePowerBarTask" + str(hash(self)))
        if self.powerBar:
            self.powerBar.destroy()
            self.powerBar = None
        Gag.delete(self)