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
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
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
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()
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()
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()
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()
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()
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
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
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)
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
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)
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()
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 DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBanquetTable') rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble('water-power-speed', 15) waterPowerExponent = base.config.GetDouble('water-power-exponent', 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = 'BanquetTableUpdateKeyPressRateTask' YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.97 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedBanquetTable') self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None return def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() return def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in list(self.dinerStatusIndicators.values()): indicator.delete() self.dinerStatusIndicators = {} for diner in list(self.diners.values()): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName('pitcherSmooth') self.pitcherAdviceName = self.uniqueName('pitcherAdvice') self.posHprBroadcastName = self.uniqueName('pitcherBroadcast') self.waterPowerTaskName = self.uniqueName('updateWaterPower') self.triggerName = self.uniqueName('trigger') self.watchControlsName = self.uniqueName('watchControls') def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == 'F': self.demand('Off') elif state == 'N': self.demand('On') elif state == 'I': self.demand('Inactive') elif state == 'R': self.demand('Free') elif state == 'C': self.demand('Controlled', avId) elif state == 'L': self.demand('Flat', avId) else: self.notify.error('Invalid state from AI: %s' % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in range(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel('phase_12/models/bossbotHQ/BanquetTableChairs') tableLocator = self.boss.geom.find('**/TableLocator_%d' % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find('**/Geometry') self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx('phase_4/audio/sfx/AA_squirt_seltzer_miss.ogg') self.hitBossSfx = loader.loadSfx('phase_5/audio/sfx/SA_watercooler_spray_only.ogg') self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx('phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.ogg') self.pitcherMoveSfx = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') def setupDiners(self): for i in range(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept='c') diner.setDNA(diner.dna) diner.nametag.setNametag2d(None) diner.nametag.setNametag3d(None) if self.useNewAnimations: diner.loop('sit', fromFrame=i) else: diner.pose('landing', 0) locator = self.tableGroup.find('**/chair_%d' % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode('correctHeading') self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode('sitLocator') base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': sitLocator.setPos(0.5, 3.65, -3.75) else: sitLocator.setZ(-2.4) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath('serviceLoc-%d-%d' % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find('**/joint_head') newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in range(self.numDiners): chairCol = self.tableGroup.find('**/collision_chair_%d' % (i + 1)) colName = 'ChairCol-%d-%d' % (self.index, i) chairCol.setTag('chairIndex', str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept('enter' + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag('chairIndex')) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find('**/tray') if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel(SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval(food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc)), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0))) intervalName = 'serveFood-%d-%d' % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in range(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request('Eating', eatingDuration) diner = self.diners[chairIndex] intervalName = 'eating-%d-%d' % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self = self, diner = diner): if self.serviceLocs[chairIndex].getNumChildren() < 1: return foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.15, -0.7, -0.4)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 (foodModel.setPos(Point3(0.1, -0.25, -0.31)),) else: scaleAdj = 0.8 (foodModel.setPos(Point3(-0.25, -0.85, -0.34)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self = self, diner = diner): if diner.getRightHand().getNumChildren() < 1: return foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 else: scakeAdj = 0.8 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence(ActorInterval(diner, 'sit', duration=waitTime), ActorInterval(diner, 'sit-eat-in', startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, 'sit-eat-in', startFrame=6, endFrame=32), ActorInterval(diner, 'sit-eat-loop', duration=loopDuration, loop=1), ActorInterval(diner, 'sit-eat-out', startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, 'sit-eat-out', startFrame=12, endFrame=21)) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = 'eating-%d-%d' % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Hungry', self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop('sit-hungry-left') else: diner.loop('sit-hungry-right') def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Angry') diner = self.diners[chairIndex] diner.loop('sit-angry') def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Dead') diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence(Func(self.notify.debug, 'before actorinterval sit-lose'), ActorInterval(diner, 'sit-lose'), Func(self.notify.debug, 'before deathSuit.setHpr'), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, 'before diner.hide'), Func(diner.hide), Func(self.notify.debug, 'before deathSuit.reparentTo'), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, 'befor ActorInterval lose'), ActorInterval(deathSuit, 'lose', duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, 'before remove deathsuit'), Func(removeDeathSuit, diner, deathSuit, name='remove-death-suit-%d-%d' % (chairIndex, self.index)), Func(self.notify.debug, 'diner.stash'), Func(diner.stash)) spinningSound = base.loader.loadSfx('phase_3.5/audio/sfx/Cog_Death.ogg') deathSound = base.loader.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.ogg') deathSoundTrack = Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.2, node=deathSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=0.8, node=deathSuit), SoundInterval(deathSound, volume=0.32, node=deathSuit)) intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in list(self.diners.values()): if not diner.isHidden(): diner.loop('sit', fromFrame=startFrame) startFrame += 1 def cleanupIntervals(self): for interval in list(self.activeIntervals.values()): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish = 1): if name in self.activeIntervals: ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if name in self.activeIntervals: del self.activeIntervals[name] else: self.notify.debug('interval: %s already cleared' % name) def finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in range(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in range(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.3) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3))) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 return def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag('tableIndex')) if self.state == 'Free' and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in range(8): chair = self.tableGroup.find('**/chair_%d' % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches('**/ChairCol*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches('**/collision_chair*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find('**/collision_table') colName = 'TableCol-%d' % self.index tableCol.setTag('tableIndex', str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept('enter' + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel('phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle') lampNode = self.tableGroup.find('**/lamp_med_5') pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find('**/bottle_locator') pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode('pitcherNode') self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.nozzle = self.waterPitcherModel.find('**/nozzle_tip') self.handLocator = self.waterPitcherModel.find('**/hand_locator') self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug('grabTrack=%s' % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self.__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence(self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode)) if self.TugOfWarControls: self.__spawnUpdateKeyPressRateTask() self.accept('exitCrane', self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore('exitCrane') if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug('nextState=%s' % nextState) if nextState == 'Flat': place = base.cr.playGame.getPlace() self.notify.debug('%s' % place.fsm) if self.avId == localAvatar.doId: self.__disableControlInterface() else: if self.toon and not self.toon.isDisabled(): self.toon.loop('neutral') self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self.__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() return def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') def makeToonGrabInterval(self, toon): toon.pose('leverNeutral', 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence(Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, 'neutral'), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), Parallel(ProjectileInterval(toon, duration=0.9, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition), LerpHprInterval(toon, 0.9, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.9, Point3(1, 1, destZScale))))), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, 'leverNeutral')) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode('temp1') temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode('temp2') temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug('creating zap interval instead') grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1))) else: grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), ProjectileInterval(toon, duration=0.9, startPos=startPos, endPos=endPos)))) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus = None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitPitcher) self.accept('escape', self.__exitPitcher) self.accept(base.JUMP, self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) self.accept(base.MOVE_UP, self.__upArrowKeyPressed) self.accept(base.MOVE_DOWN, self.__downArrowKeyPressed) taskMgr.add(self.__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self.__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupPitcherAdvice() self.ignore('escape') self.ignore(base.JUMP) self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.ignore(base.MOVE_UP) self.ignore(base.MOVE_DOWN) self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self.__killUpdateKeyPressRateTask() self.keyTTL = [] self.__setMoveSound(None) return def __displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel(text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel(relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupPitcherAdvice() return def __exitPitcher(self): self.showExiting() self.d_requestFree(False) def __controlPressed(self): self.__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self.__endFireWater() elif self.state == 'Controlled': self.__beginFireWater() def __controlReleased(self): if self.TugOfWarControls: pass elif self.state == 'Controlled': self.__endFireWater() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('setPitcherPos', [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def __watchControls(self, task): if self.arrowHorz: self.__movePitcher(self.arrowHorz) else: self.__setMoveSound(None) return Task.cont def __movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug('rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f' % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h)) limitH = h self.waterPitcherNode.setH(limitH) if xd: self.__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack(self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale = 1.0, vertScale = 1.0, parent = render): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp('spray') sprayScale = hidden.attachNewNode('spray-parent') sprayRot = hidden.attachNewNode('spray-rotate') spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target = target, origin = origin, horizScale = horizScale, vertScale = vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return if self.avId != base.localAvatar.doId: return tag = self.hitObject.getNetTag('pieCode') pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate('waterHitBoss', [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.8), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' self.keyTTL = [] def __beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateWaterPower, self.waterPowerTaskName) return def __endFireWater(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.waterPowerTaskName) messenger.send('wakeup') self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode('pitcherColNode')) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() return def __updateWaterPower(self, task): if not self.powerBar: print('### no power bar!!!') return task.done newPower = self.__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) return task.cont def __getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate('firingWater', [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.8) dScaleUp = 0.1 dHold = 0.3 dScaleDown = 0.1 horizScale = 0.1 vertScale = 0.1 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt = render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug('enterFlat %d' % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState('neutral') toon.setAnimState('neutral') toon.loop('leverNeutral') def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency)) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def __upArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(0) def __downArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(1) def __pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def __spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater(0.1, self.__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __updateKeyPressRateTask(self, task): if self.state not in 'Controlled': return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.1 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug('diffPower=%.2f keyRate = %d, newPower=%.2f' % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) self.__spawnUpdateKeyPressRateTask() return Task.done def __setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
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 DistributedGolfSpot(DistributedObject.DistributedObject, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfSpot') positions = ((-45, 100, GolfGlobals.GOLF_BALL_RADIUS), (-15, 100, GolfGlobals.GOLF_BALL_RADIUS), (15, 100, GolfGlobals.GOLF_BALL_RADIUS), (45, 100, GolfGlobals.GOLF_BALL_RADIUS)) toonGolfOffsetPos = Point3(-2, 0, -GolfGlobals.GOLF_BALL_RADIUS) toonGolfOffsetHpr = Point3(-90, 0, 0) rotateSpeed = 20 golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3) golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if self.index > len(self.positions): self.notify.error('Invalid index %d' % index) self.fadeTrack = None self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None return def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setGolfSpot(self, self.index) def setIndex(self, index): self.index = index def disable(self): DistributedObject.DistributedObject.disable(self) self.ignoreAll() def delete(self): DistributedObject.DistributedObject.delete(self) self.ignoreAll() self.boss = None return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.triggerName = self.uniqueName('trigger') self.triggerEvent = 'enter%s' % self.triggerName self.smoothName = self.uniqueName('golfSpotSmooth') self.golfSpotAdviceName = self.uniqueName('golfSpotAdvice') self.posHprBroadcastName = self.uniqueName('golfSpotBroadcast') self.ballPowerTaskName = self.uniqueName('updateGolfPower') self.adjustClubTaskName = self.uniqueName('adjustClub') self.loadAssets() self.accept('flyBallHit-%d' % self.index, self.__flyBallHit) def loadAssets(self): self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg') def cleanup(self): if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None flyTracks = self.flyBallTracks.values() for track in flyTracks: track.finish() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None if self.restoreScaleTrack: self.restoreScaleTrack.finish() self.restoreScaleTrack = None self.root.removeNode() self.ballModel.removeNode() self.club.removeNode() if self.powerBar: self.powerBar.destroy() self.powerBar = None taskMgr.remove(self.triggerName) self.boss = None return def setState(self, state, avId, extraInfo): if not self.isDisabled(): self.gotHitByBoss = extraInfo if state == 'C': self.demand('Controlled', avId) elif state == 'F': self.demand('Free') elif state == 'O': self.demand('Off') else: self.notify.error('Invalid state from AI: %s' % state) def enterOff(self): pass def exitOff(self): pass def enterFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval(), name='restoreScaleTrack') self.restoreScaleTrack.start() if self.avId == localAvatar.doId: if not self.isDisabled(): self.ballModel.setAlphaScale(0.3) self.ballModel.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.ballModel.setTransparency, 1), self.ballModel.colorScaleInterval( 0.2, VBase4(1, 1, 1, 0.3)), name='fadeTrack-enterFree') self.fadeTrack.start() else: self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) self.avId = 0 return def exitFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack.finish() self.restoreScaleTrack = None taskMgr.remove(self.triggerName) self.ballModel.clearTransparency() self.trigger.stash() self.ignore(self.triggerEvent) return def enterControlled(self, avId): self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.enableControlKey() self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) if avId == localAvatar.doId: self.boss.toCraneMode() camera.reparentTo(self.root) camera.setPosHpr(0, -10, 3, 0, 0, 0) localAvatar.setPos(self.root, self.toonGolfOffsetPos) localAvatar.setHpr(self.root, self.toonGolfOffsetHpr) localAvatar.sendCurrentPosition() self.__enableControlInterface() self.startPosHprBroadcast() self.accept('exitCrane', self.gotBossZapped) self.grabTrack.start() def exitControlled(self): self.grabTrack.finish() del self.grabTrack if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if not self.ballModel.isEmpty(): if self.ballModel.isHidden(): self.notify.debug('ball is hidden scale =%s' % self.ballModel.getScale()) else: self.notify.debug('ball is showing scale=%s' % self.ballModel.getScale()) if self.toon and not self.toon.isDisabled(): self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: self.__disableControlInterface() if not self.goingToReward: camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.stopAdjustClubTask() self.releaseTrack.start() self.enableControlKey() return def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.ballModel.colorScaleInterval( 0.2, self.ballColor), Func(self.ballModel.clearTransparency), name='fadeTrack-allowDetect') self.fadeTrack.start() self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) def __hitTrigger(self, event): self.d_requestControl() def getRestoreScaleInterval(self): return Sequence() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def makeToonGrabInterval(self, toon): origPos = toon.getPos(self.root) origHpr = toon.getHpr(self.root) a = self.accomodateToon(toon) newPos = toon.getPos() newHpr = toon.getHpr() origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0])) self.notify.debug('toon.setPosHpr %s %s' % (origPos, origHpr)) toon.setPosHpr(origPos, origHpr) walkTime = 0.2 reach = Sequence() if reach.getDuration() < walkTime: reach = Sequence( ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach) i = Sequence( Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), Func(toon.stopLookAround)) if toon == base.localAvatar: i.append(Func(self.switchToAnimState, 'GolfPuttLoop')) i.append(Func(self.startAdjustClubTask)) i = Parallel(i, a) return i def accomodateToon(self, toon): toon.wrtReparentTo(self.root) toon.setPos(self.toonGolfOffsetPos) toon.setHpr(self.toonGolfOffsetHpr) return Sequence() def switchToAnimState(self, animStateName, forced=False): curAnimState = base.localAvatar.animFSM.getCurrentState() curAnimStateName = '' if curAnimState: curAnimStateName = curAnimState.getName() if curAnimStateName != animStateName or forced: base.localAvatar.b_setAnimState(animStateName) def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotGolfSpotLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitGolfSpot) self.accept('escape', self.__exitGolfSpot) self.accept('control', self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) taskMgr.add(self.__watchControls, 'watchGolfSpotControls') taskMgr.doMethodLater(5, self.__displayGolfSpotAdvice, self.golfSpotAdviceName) self.arrowVert = 0 self.arrowHorz = 0 if self.powerBar: self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupGolfSpotAdvice() self.ignore('escape') self.ignore('control') self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove('watchGolfSpotControls') if self.powerBar: self.powerBar.hide() else: self.notify.debug('self.powerBar is none') return def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' def __displayGolfSpotAdvice(self, task): if self.golfSpotAdviceLabel == None: self.golfSpotAdviceLabel = DirectLabel( text=TTLocalizer.BossbotGolfSpotAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupGolfSpotAdvice(self): if self.golfSpotAdviceLabel: self.golfSpotAdviceLabel.destroy() self.golfSpotAdviceLabel = None taskMgr.remove(self.golfSpotAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotGolfSpotLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupGolfSpotAdvice() return def __exitGolfSpot(self): self.d_requestFree(False) def __controlPressed(self): if self.controlKeyAllowed: self.__beginFireBall() def __controlReleased(self): if self.controlKeyAllowed: self.__endFireBall() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = 1 self.switchToAnimState('GolfRotateLeft') elif self.arrowHorz > 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = -1 self.switchToAnimState('GolfRotateRight') elif self.arrowHorz < 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __watchControls(self, task): if self.arrowHorz: self.__moveGolfSpot(self.arrowHorz) return Task.cont def __moveGolfSpot(self, xd): dt = globalClock.getDt() h = self.root.getH() - xd * self.rotateSpeed * dt h %= 360 limitH = h self.root.setH(limitH) def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def __beginFireBall(self): if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateBallPower, self.ballPowerTaskName) return def __endFireBall(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.ballPowerTaskName) self.disableControlKey() messenger.send('wakeup') self.aimStart = None power = self.power angle = self.root.getH() self.notify.debug('incrementing self.__flyBallSequenceNum') self.__flyBallSequenceNum = (self.__flyBallSequenceNum + 1) % 255 self.sendSwingInfo(power, angle, self.__flyBallSequenceNum) self.setSwingInfo(power, angle, self.__flyBallSequenceNum) self.resetPowerBar() return def __updateBallPower(self, task): if not self.powerBar: print '### no power bar!!!' return task.done newPower = self.__getBallPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower return task.cont def __getBallPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.golfPowerSpeed t = math.pow(t, self.golfPowerExponent) power = int(t * 100) % 200 if power > 100: power = 200 - power return power def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendGolfSpotPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendGolfSpotPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendGolfSpotPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate( 'setGolfSpotPos', [self.changeSeq, self.root.getH(), timestamp]) def setGolfSpotPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.golfSpotSmoother.setH(h) self.golfSpotSmoother.setTimestamp(local) self.golfSpotSmoother.markPosition() else: self.root.setH(h) def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus=None): self.golfSpotSmoother.clearPositions(1) def doSmoothTask(self, task): self.golfSpotSmoother.computeAndApplySmoothHpr(self.root) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def makeToonReleaseInterval(self, toon): def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if self.gotHitByBoss: grabIval = Sequence(Func(self.detachClub), name='makeToonReleaseInterval-gotHitByBoss') if not toon.isEmpty(): toonIval = Sequence(Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)), name='makeToonReleaseInterval-toonIval') grabIval.append(toonIval) else: grabIval = Sequence(Func(self.detachClub)) if not toon.isEmpty(): toonIval = Sequence( Parallel( ActorInterval(toon, 'walk', duration=1.0, playRate=-1.0), LerpPosInterval(toon, duration=1.0, pos=Point3(-10, 0, 0))), Func(toon.wrtReparentTo, render)) grabIval.append(toonIval) if localAvatar.doId == toon.doId: if not self.goingToReward and toon.hp > 0: grabIval.append(Func(self.goToFinalBattle)) grabIval.append( Func(self.notify.debug, 'goingToFinalBattlemode')) grabIval.append(Func(self.safeBossToFinalBattleMode)) return grabIval def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): curState = place.fsm.getCurrentState().getName() if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') else: self.notify.debug('NOT going to final battle, state=%s' % curState) def attachClub(self, avId, pointToBall=False): club = self.club if club: av = base.cr.doId2do.get(avId) if av: av.useLOD(1000) lHand = av.getLeftHands()[0] club.setPos(0, 0, 0) club.reparentTo(lHand) netScale = club.getNetTransform().getScale()[1] counterActToonScale = lHand.find('**/counteractToonScale') if counterActToonScale.isEmpty(): counterActToonScale = lHand.attachNewNode( 'counteractToonScale') counterActToonScale.setScale(1 / netScale) self.notify.debug('creating counterActToonScale for %s' % av.getName()) club.reparentTo(counterActToonScale) club.setX(-0.25 * netScale) if pointToBall: club.lookAt(self.clubLookatSpot) def detachClub(self): if not self.club.isEmpty(): self.club.reparentTo(self.root) self.club.setZ(-20) self.club.setScale(1) def adjustClub(self): club = self.club if club: distance = club.getDistance(self.clubLookatSpot) scaleFactor = distance / 2.058 club.setScale(1, scaleFactor, 1) def startAdjustClubTask(self): taskMgr.add(self.adjustClubTask, self.adjustClubTaskName) def stopAdjustClubTask(self): taskMgr.remove(self.adjustClubTaskName) def adjustClubTask(self, task): self.attachClub(self.avId, True) self.adjustClub() return task.cont def enableControlKey(self): self.controlKeyAllowed = True def disableControlKey(self): self.controlKeyAllowed = False def sendSwingInfo(self, power, angle, sequenceNum): self.sendUpdate('setSwingInfo', [power, angle, sequenceNum]) def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(root=self.root, relVel=relVel): return render.getRelativeVector(root, relVel) fly = Sequence( Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound return def setSwingInfo(self, power, angle, sequenceNum): av = base.cr.doId2do.get(self.avId) self.swingInterval = Sequence() if av: self.stopAdjustClubTask() self.swingInterval = Sequence( ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback, power, angle, sequenceNum), Func(self.ballModel.hide), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=24), Func(self.ballModel.setScale, 0.1), Func(self.ballModel.show), LerpScaleInterval(self.ballModel, 1.0, Point3(1, 1, 1)), Func(self.enableControlKey)) if av == localAvatar: self.swingInterval.append( Func(self.switchToAnimState, 'GolfPuttLoop', True)) self.swingInterval.start() def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) return self.__flyBallBubble def __flyBallHit(self, entry): print entry def flyBallFinishedFlying(self, sequence): if self.flyBallTracks.has_key(sequence): del self.flyBallTracks[sequence] def __finishFlyBallTrack(self, sequence): if self.flyBallTracks.has_key(sequence): flyBallTrack = self.flyBallTracks[sequence] del self.flyBallTracks[sequence] flyBallTrack.finish() def flyBallFinishedSplatting(self, sequence): if self.splatTracks.has_key(sequence): del self.splatTracks[sequence] def __flyBallHit(self, entry): if not entry.hasSurfacePoint() or not entry.hasInto(): return if not entry.getInto().isTangible(): return sequence = int(entry.getFromNodePath().getNetTag('pieSequence')) self.__finishFlyBallTrack(sequence) if self.splatTracks.has_key(sequence): splatTrack = self.splatTracks[sequence] del self.splatTracks[sequence] splatTrack.finish() flyBallCode = 0 flyBallCodeStr = entry.getIntoNodePath().getNetTag('pieCode') if flyBallCodeStr: flyBallCode = int(flyBallCodeStr) pos = entry.getSurfacePoint(render) timestamp32 = globalClockDelta.getFrameNetworkTime(bits=32) throwerId = int(entry.getFromNodePath().getNetTag('throwerId')) splat = self.getFlyBallSplatInterval(pos[0], pos[1], pos[2], flyBallCode, throwerId) splat = Sequence(splat, Func(self.flyBallFinishedSplatting, sequence)) self.splatTracks[sequence] = splat splat.start() self.notify.debug( 'doId=%d into=%s flyBallCode=%d, throwerId=%d' % (self.doId, entry.getIntoNodePath(), flyBallCode, throwerId)) if flyBallCode == ToontownGlobals.PieCodeBossCog and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum self.boss.d_ballHitBoss(10) elif flyBallCode == ToontownGlobals.PieCodeToon and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum avatarDoId = entry.getIntoNodePath().getNetTag('avatarDoId') if avatarDoId == '': self.notify.warning('Toon %s has no avatarDoId tag.' % repr(entry.getIntoNodePath())) return doId = int(avatarDoId) if doId != localAvatar.doId: pass def getFlyBallSplatInterval(self, x, y, z, flyBallCode, throwerId): from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps splatName = 'dust' splat = BattleProps.globalPropPool.getProp(splatName) splat.setBillboardPointWorld(2) color = ToontownGlobals.PieCodeColors.get(flyBallCode) if color: splat.setColor(*color) if flyBallCode == ToontownGlobals.PieCodeBossCog: self.notify.debug('changing color to %s' % self.ballColor) splat.setColor(self.ballColor) sound = loader.loadSfx('phase_11/audio/sfx/LB_evidence_miss.ogg') vol = 1.0 if flyBallCode == ToontownGlobals.PieCodeBossCog: sound = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg') soundIval = SoundInterval(sound, node=splat, volume=vol) if flyBallCode == ToontownGlobals.PieCodeBossCog and localAvatar.doId == throwerId: vol = 1.0 soundIval = SoundInterval(sound, node=localAvatar, volume=vol) ival = Parallel( Func(splat.reparentTo, render), Func(splat.setPos, x, y, z), soundIval, Sequence(ActorInterval(splat, splatName), Func(splat.detachNode))) return ival def setGoingToReward(self): self.goingToReward = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True)
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 DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedBanquetTable") rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble("water-power-speed", 15) waterPowerExponent = base.config.GetDouble("water-power-exponent", 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = "BanquetTableUpdateKeyPressRateTask" YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.96999999999999997 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, "DistributedBanquetTable") self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self._DistributedBanquetTable__broadcastPeriod = 0.20000000000000001 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in self.dinerStatusIndicators.values(): indicator.delete() self.dinerStatusIndicators = {} for diner in self.diners.values(): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName("pitcherSmooth") self.pitcherAdviceName = self.uniqueName("pitcherAdvice") self.posHprBroadcastName = self.uniqueName("pitcherBroadcast") self.waterPowerTaskName = self.uniqueName("updateWaterPower") self.triggerName = self.uniqueName("trigger") self.watchControlsName = self.uniqueName("watchControls") def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == "F": self.demand("Off") elif state == "N": self.demand("On") elif state == "I": self.demand("Inactive") elif state == "R": self.demand("Free") elif state == "C": self.demand("Controlled", avId) elif state == "L": self.demand("Flat", avId) else: self.notify.error("Invalid state from AI: %s" % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in xrange(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel("phase_12/models/bossbotHQ/BanquetTableChairs") tableLocator = self.boss.geom.find("**/TableLocator_%d" % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find("**/Geometry") self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx("phase_4/audio/sfx/AA_squirt_seltzer_miss.mp3") self.hitBossSfx = loader.loadSfx("phase_5/audio/sfx/SA_watercooler_spray_only.mp3") self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx("phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.mp3") self.pitcherMoveSfx = base.loadSfx("phase_4/audio/sfx/MG_cannon_adjust.mp3") def setupDiners(self): for i in xrange(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept="c") diner.setDNA(diner.dna) if self.useNewAnimations: diner.loop("sit", fromFrame=i) else: diner.pose("landing", 0) locator = self.tableGroup.find("**/chair_%d" % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode("correctHeading") self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode("sitLocator") base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == "c": sitLocator.setPos(0.5, 3.6499999999999999, -3.75) else: sitLocator.setZ(-2.3999999999999999) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath("serviceLoc-%d-%d" % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find("**/joint_head") newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in xrange(self.numDiners): chairCol = self.tableGroup.find("**/collision_chair_%d" % (i + 1)) colName = "ChairCol-%d-%d" % (self.index, i) chairCol.setTag("chairIndex", str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept("enter" + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag("chairIndex")) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel("phase_12/models/bossbotHQ/canoffood") foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find("**/tray") if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel( SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval( food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc) ), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0)), ) intervalName = "serveFood-%d-%d" % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in xrange(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request("Eating", eatingDuration) diner = self.diners[chairIndex] intervalName = "eating-%d-%d" % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self=self, diner=diner): foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.14999999999999999, -0.69999999999999996, -0.40000000000000002)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 (foodModel.setPos(Point3(0.10000000000000001, -0.25, -0.31)),) else: scaleAdj = 0.80000000000000004 (foodModel.setPos(Point3(-0.25, -0.84999999999999998, -0.34000000000000002)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self=self, diner=diner): foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 else: scakeAdj = 0.80000000000000004 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence( ActorInterval(diner, "sit", duration=waitTime), ActorInterval(diner, "sit-eat-in", startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, "sit-eat-in", startFrame=6, endFrame=32), ActorInterval(diner, "sit-eat-loop", duration=loopDuration, loop=1), ActorInterval(diner, "sit-eat-out", startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, "sit-eat-out", startFrame=12, endFrame=21), ) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = "eating-%d-%d" % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Hungry", self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop("sit-hungry-left") else: diner.loop("sit-hungry-right") def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Angry") diner = self.diners[chairIndex] diner.loop("sit-angry") def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Dead") diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find("**/chair_%d" % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence( Func(self.notify.debug, "before actorinterval sit-lose"), ActorInterval(diner, "sit-lose"), Func(self.notify.debug, "before deathSuit.setHpr"), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, "before diner.hide"), Func(diner.hide), Func(self.notify.debug, "before deathSuit.reparentTo"), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, "befor ActorInterval lose"), ActorInterval(deathSuit, "lose", duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, "before remove deathsuit"), Func(removeDeathSuit, diner, deathSuit, name="remove-death-suit-%d-%d" % (chairIndex, self.index)), Func(self.notify.debug, "diner.stash"), Func(diner.stash), ) spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.mp3") deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.mp3") deathSoundTrack = Sequence( Wait(0.80000000000000004), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.20000000000000001, node=deathSuit), SoundInterval( spinningSound, duration=3.0, startTime=0.59999999999999998, volume=0.80000000000000004, node=deathSuit ), SoundInterval(deathSound, volume=0.32000000000000001, node=deathSuit), ) intervalName = "dinerDie-%d-%d" % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in self.diners.values(): if not diner.isHidden(): diner.loop("sit", fromFrame=startFrame) startFrame += 1 continue def cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish=1): if self.activeIntervals.has_key(name): ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if self.activeIntervals.has_key(name): del self.activeIntervals[name] else: self.notify.debug("interval: %s already cleared" % name) def finishInterval(self, name): if self.activeIntervals.has_key(name): interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in xrange(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) continue return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in xrange(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.29999999999999999) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self._DistributedBanquetTable__allowDetect, self.triggerName) self.fadeTrack = Sequence( Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 0.29999999999999999)), ) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag("tableIndex")) if self.state == "Free" and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in xrange(8): chair = self.tableGroup.find("**/chair_%d" % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches("**/ChairCol*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches("**/collision_chair*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find("**/collision_table") colName = "TableCol-%d" % self.index tableCol.setTag("tableIndex", str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept("enter" + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel("phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle") lampNode = self.tableGroup.find("**/lamp_med_5") pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find("**/bottle_locator") pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode("pitcherNode") self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.waterPitcherModel.ls() self.nozzle = self.waterPitcherModel.find("**/nozzle_tip") self.handLocator = self.waterPitcherModel.find("**/hand_locator") self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate("requestControl") def d_requestFree(self, gotHitByBoss): self.sendUpdate("requestFree", [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return None self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug("grabTrack=%s" % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self._DistributedBanquetTable__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence( self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode), ) if self.TugOfWarControls: self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() self.accept("exitCrane", self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore("exitCrane") if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug("nextState=%s" % nextState) if nextState == "Flat": place = base.cr.playGame.getPlace() self.notify.debug("%s" % place.fsm) if self.avId == localAvatar.doId: self._DistributedBanquetTable__disableControlInterface() elif self.toon and not self.toon.isDisabled(): self.toon.loop("neutral") self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self._DistributedBanquetTable__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, "fsm"): if place.fsm.getCurrentState().getName() == "crane": place.setState("finalBattle") def makeToonGrabInterval(self, toon): toon.pose("leverNeutral", 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence( Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, "neutral"), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), Parallel( ProjectileInterval( toon, duration=0.90000000000000002, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition, ), LerpHprInterval(toon, 0.90000000000000002, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.90000000000000002, Point3(1, 1, destZScale)), ), ), ), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, "leverNeutral"), ) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode("temp1") temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode("temp2") temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug("creating zap interval instead") grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, "slip-backward"), toon.posInterval(0.5, getSlideToPos, fluid=1)), ) else: grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), ProjectileInterval(toon, duration=0.90000000000000002, startPos=startPos, endPos=endPos), ), ), ) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate("clearSmoothing", [0]) def clearSmoothing(self, bogus=None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def _DistributedBanquetTable__enableControlInterface(self): gui = loader.loadModel("phase_3.5/models/gui/avatar_panel_gui") self.closeButton = DirectButton( image=( gui.find("**/CloseBtn_UP"), gui.find("**/CloseBtn_DN"), gui.find("**/CloseBtn_Rllvr"), gui.find("**/CloseBtn_UP"), ), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.040000000000000001, text_pos=(0, -0.070000000000000007), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.81999999999999995), command=self._DistributedBanquetTable__exitPitcher, ) self.accept("escape", self._DistributedBanquetTable__exitPitcher) self.accept("control", self._DistributedBanquetTable__controlPressed) self.accept("control-up", self._DistributedBanquetTable__controlReleased) self.accept("InputState-forward", self._DistributedBanquetTable__upArrow) self.accept("InputState-reverse", self._DistributedBanquetTable__downArrow) self.accept("InputState-turnLeft", self._DistributedBanquetTable__leftArrow) self.accept("InputState-turnRight", self._DistributedBanquetTable__rightArrow) self.accept("arrow_up", self._DistributedBanquetTable__upArrowKeyPressed) self.accept("arrow_down", self._DistributedBanquetTable__downArrowKeyPressed) taskMgr.add(self._DistributedBanquetTable__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self._DistributedBanquetTable__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() def _DistributedBanquetTable__disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self._DistributedBanquetTable__cleanupPitcherAdvice() self.ignore("escape") self.ignore("control") self.ignore("control-up") self.ignore("InputState-forward") self.ignore("InputState-reverse") self.ignore("InputState-turnLeft") self.ignore("InputState-turnRight") self.ignore("arrow_up") self.ignore("arrow_down") self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self._DistributedBanquetTable__killUpdateKeyPressRateTask() self.keyTTL = [] self._DistributedBanquetTable__setMoveSound(None) def _DistributedBanquetTable__displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel( text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.68999999999999995), scale=0.10000000000000001, ) def _DistributedBanquetTable__cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.059999999999999998, text_fg=VBase4(1, 1, 1, 1), ) self._DistributedBanquetTable__cleanupPitcherAdvice() def _DistributedBanquetTable__exitPitcher(self): self.showExiting() self.d_requestFree(False) def _DistributedBanquetTable__controlPressed(self): self._DistributedBanquetTable__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self._DistributedBanquetTable__endFireWater() elif self.state == "Controlled": self._DistributedBanquetTable__beginFireWater() def _DistributedBanquetTable__controlReleased(self): if self.TugOfWarControls: pass 1 if self.state == "Controlled": self._DistributedBanquetTable__endFireWater() def _DistributedBanquetTable__upArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def _DistributedBanquetTable__downArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def _DistributedBanquetTable__rightArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def _DistributedBanquetTable__leftArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def _DistributedBanquetTable__incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) def _DistributedBanquetTable__posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate("setPitcherPos", [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def _DistributedBanquetTable__watchControls(self, task): if self.arrowHorz: self._DistributedBanquetTable__movePitcher(self.arrowHorz) else: self._DistributedBanquetTable__setMoveSound(None) return Task.cont def _DistributedBanquetTable__movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug( "rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f" % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h) ) limitH = h self.waterPitcherNode.setH(limitH) if xd: self._DistributedBanquetTable__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack( self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale=1.0, vertScale=1.0, parent=render ): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp("spray") sprayScale = hidden.attachNewNode("spray-parent") sprayRot = hidden.attachNewNode("spray-rotate") spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target=target, origin=origin, horizScale=horizScale, vertScale=vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return None if self.avId != base.localAvatar.doId: return None tag = self.hitObject.getNetTag("pieCode") pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate("waterHitBoss", [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar( pos=(0.0, 0, -0.93999999999999995), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.20000000000000001, 0.20000000000000001), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.80000000000000004), text="", text_scale=0.26000000000000001, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.050000000000000003), ) self.power = 0 self.powerBar["value"] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar["value"] = self.power self.powerBar["text"] = "" self.keyTTL = [] def _DistributedBanquetTable__beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return None if self.aimStart != None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None time = globalClock.getFrameTime() self.aimStart = time messenger.send("wakeup") taskMgr.add(self._DistributedBanquetTable__updateWaterPower, self.waterPowerTaskName) def _DistributedBanquetTable__endFireWater(self): if self.aimStart == None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None taskMgr.remove(self.waterPowerTaskName) messenger.send("wakeup") self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode("pitcherColNode")) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask( ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask ) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() def _DistributedBanquetTable__updateWaterPower(self, task): if not self.powerBar: print "### no power bar!!!" return task.done newPower = self._DistributedBanquetTable__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) return task.cont def _DistributedBanquetTable__getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate("firingWater", [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.80000000000000004) dScaleUp = 0.10000000000000001 dHold = 0.29999999999999999 dScaleDown = 0.10000000000000001 horizScale = 0.10000000000000001 vertScale = 0.10000000000000001 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt=render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug("enterFlat %d" % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState("neutral") toon.setAnimState("neutral") toon.loop("leverNeutral") def _DistributedBanquetTable__allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence( self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency), ) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def _DistributedBanquetTable__upArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(0) def _DistributedBanquetTable__downArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(1) def _DistributedBanquetTable__pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def _DistributedBanquetTable__spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater( 0.10000000000000001, self._DistributedBanquetTable__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK), ) def _DistributedBanquetTable__killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def _DistributedBanquetTable__updateKeyPressRateTask(self, task): if self.state not in "Controlled": return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.10000000000000001 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break continue self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug("diffPower=%.2f keyRate = %d, newPower=%.2f" % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() return Task.done def _DistributedBanquetTable__setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
class DistributedGolfSpot(DistributedObject.DistributedObject, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfSpot') positions = ((-45, 100, GolfGlobals.GOLF_BALL_RADIUS), (-15, 100, GolfGlobals.GOLF_BALL_RADIUS), (15, 100, GolfGlobals.GOLF_BALL_RADIUS), (45, 100, GolfGlobals.GOLF_BALL_RADIUS)) toonGolfOffsetPos = Point3(-2, 0, -GolfGlobals.GOLF_BALL_RADIUS) toonGolfOffsetHpr = Point3(-90, 0, 0) rotateSpeed = 20 golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3) golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if self.index > len(self.positions): self.notify.error('Invalid index %d' % index) self.fadeTrack = None self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None return def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setGolfSpot(self, self.index) def setIndex(self, index): self.index = index def disable(self): DistributedObject.DistributedObject.disable(self) self.ignoreAll() def delete(self): DistributedObject.DistributedObject.delete(self) self.ignoreAll() self.boss = None return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.triggerName = self.uniqueName('trigger') self.triggerEvent = 'enter%s' % self.triggerName self.smoothName = self.uniqueName('golfSpotSmooth') self.golfSpotAdviceName = self.uniqueName('golfSpotAdvice') self.posHprBroadcastName = self.uniqueName('golfSpotBroadcast') self.ballPowerTaskName = self.uniqueName('updateGolfPower') self.adjustClubTaskName = self.uniqueName('adjustClub') self.loadAssets() self.accept('flyBallHit-%d' % self.index, self.__flyBallHit) def loadAssets(self): self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg') def cleanup(self): if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None flyTracks = self.flyBallTracks.values() for track in flyTracks: track.finish() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None if self.restoreScaleTrack: self.restoreScaleTrack.finish() self.restoreScaleTrack = None self.root.removeNode() self.ballModel.removeNode() self.club.removeNode() if self.powerBar: self.powerBar.destroy() self.powerBar = None taskMgr.remove(self.triggerName) self.boss = None return def setState(self, state, avId, extraInfo): if not self.isDisabled(): self.gotHitByBoss = extraInfo if state == 'C': self.demand('Controlled', avId) elif state == 'F': self.demand('Free') elif state == 'O': self.demand('Off') else: self.notify.error('Invalid state from AI: %s' % state) def enterOff(self): pass def exitOff(self): pass def enterFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval(), name='restoreScaleTrack') self.restoreScaleTrack.start() if self.avId == localAvatar.doId: if not self.isDisabled(): self.ballModel.setAlphaScale(0.3) self.ballModel.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.ballModel.setTransparency, 1), self.ballModel.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3)), name='fadeTrack-enterFree') self.fadeTrack.start() else: self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) self.avId = 0 return def exitFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack.finish() self.restoreScaleTrack = None taskMgr.remove(self.triggerName) self.ballModel.clearTransparency() self.trigger.stash() self.ignore(self.triggerEvent) return def enterControlled(self, avId): self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.enableControlKey() self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) if avId == localAvatar.doId: self.boss.toCraneMode() camera.reparentTo(self.root) camera.setPosHpr(0, -10, 3, 0, 0, 0) localAvatar.setPos(self.root, self.toonGolfOffsetPos) localAvatar.setHpr(self.root, self.toonGolfOffsetHpr) localAvatar.sendCurrentPosition() self.__enableControlInterface() self.startPosHprBroadcast() self.accept('exitCrane', self.gotBossZapped) self.grabTrack.start() def exitControlled(self): self.grabTrack.finish() del self.grabTrack if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if not self.ballModel.isEmpty(): if self.ballModel.isHidden(): self.notify.debug('ball is hidden scale =%s' % self.ballModel.getScale()) else: self.notify.debug('ball is showing scale=%s' % self.ballModel.getScale()) if self.toon and not self.toon.isDisabled(): self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: self.__disableControlInterface() if not self.goingToReward: camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.stopAdjustClubTask() self.releaseTrack.start() self.enableControlKey() return def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.ballModel.colorScaleInterval(0.2, self.ballColor), Func(self.ballModel.clearTransparency), name='fadeTrack-allowDetect') self.fadeTrack.start() self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) def __hitTrigger(self, event): self.d_requestControl() def getRestoreScaleInterval(self): return Sequence() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def makeToonGrabInterval(self, toon): origPos = toon.getPos(self.root) origHpr = toon.getHpr(self.root) a = self.accomodateToon(toon) newPos = toon.getPos() newHpr = toon.getHpr() origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0])) self.notify.debug('toon.setPosHpr %s %s' % (origPos, origHpr)) toon.setPosHpr(origPos, origHpr) walkTime = 0.2 reach = Sequence() if reach.getDuration() < walkTime: reach = Sequence(ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach) i = Sequence(Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), Func(toon.stopLookAround)) if toon == base.localAvatar: i.append(Func(self.switchToAnimState, 'GolfPuttLoop')) i.append(Func(self.startAdjustClubTask)) i = Parallel(i, a) return i def accomodateToon(self, toon): toon.wrtReparentTo(self.root) toon.setPos(self.toonGolfOffsetPos) toon.setHpr(self.toonGolfOffsetHpr) return Sequence() def switchToAnimState(self, animStateName, forced = False): curAnimState = base.localAvatar.animFSM.getCurrentState() curAnimStateName = '' if curAnimState: curAnimStateName = curAnimState.getName() if curAnimStateName != animStateName or forced: base.localAvatar.b_setAnimState(animStateName) def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotGolfSpotLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitGolfSpot) self.accept('escape', self.__exitGolfSpot) self.accept('control', self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) taskMgr.add(self.__watchControls, 'watchGolfSpotControls') taskMgr.doMethodLater(5, self.__displayGolfSpotAdvice, self.golfSpotAdviceName) self.arrowVert = 0 self.arrowHorz = 0 if self.powerBar: self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupGolfSpotAdvice() self.ignore('escape') self.ignore('control') self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove('watchGolfSpotControls') if self.powerBar: self.powerBar.hide() else: self.notify.debug('self.powerBar is none') return def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' def __displayGolfSpotAdvice(self, task): if self.golfSpotAdviceLabel == None: self.golfSpotAdviceLabel = DirectLabel(text=TTLocalizer.BossbotGolfSpotAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupGolfSpotAdvice(self): if self.golfSpotAdviceLabel: self.golfSpotAdviceLabel.destroy() self.golfSpotAdviceLabel = None taskMgr.remove(self.golfSpotAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel(relief=None, text=TTLocalizer.BossbotGolfSpotLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupGolfSpotAdvice() return def __exitGolfSpot(self): self.d_requestFree(False) def __controlPressed(self): if self.controlKeyAllowed: self.__beginFireBall() def __controlReleased(self): if self.controlKeyAllowed: self.__endFireBall() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = 1 self.switchToAnimState('GolfRotateLeft') elif self.arrowHorz > 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = -1 self.switchToAnimState('GolfRotateRight') elif self.arrowHorz < 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __watchControls(self, task): if self.arrowHorz: self.__moveGolfSpot(self.arrowHorz) return Task.cont def __moveGolfSpot(self, xd): dt = globalClock.getDt() h = self.root.getH() - xd * self.rotateSpeed * dt h %= 360 limitH = h self.root.setH(limitH) def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def __beginFireBall(self): if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateBallPower, self.ballPowerTaskName) return def __endFireBall(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.ballPowerTaskName) self.disableControlKey() messenger.send('wakeup') self.aimStart = None power = self.power angle = self.root.getH() self.notify.debug('incrementing self.__flyBallSequenceNum') self.__flyBallSequenceNum = (self.__flyBallSequenceNum + 1) % 255 self.sendSwingInfo(power, angle, self.__flyBallSequenceNum) self.setSwingInfo(power, angle, self.__flyBallSequenceNum) self.resetPowerBar() return def __updateBallPower(self, task): if not self.powerBar: print '### no power bar!!!' return task.done newPower = self.__getBallPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower return task.cont def __getBallPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.golfPowerSpeed t = math.pow(t, self.golfPowerExponent) power = int(t * 100) % 200 if power > 100: power = 200 - power return power def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendGolfSpotPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendGolfSpotPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendGolfSpotPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('setGolfSpotPos', [self.changeSeq, self.root.getH(), timestamp]) def setGolfSpotPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.golfSpotSmoother.setH(h) self.golfSpotSmoother.setTimestamp(local) self.golfSpotSmoother.markPosition() else: self.root.setH(h) def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus = None): self.golfSpotSmoother.clearPositions(1) def doSmoothTask(self, task): self.golfSpotSmoother.computeAndApplySmoothHpr(self.root) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def makeToonReleaseInterval(self, toon): def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if self.gotHitByBoss: grabIval = Sequence(Func(self.detachClub), name='makeToonReleaseInterval-gotHitByBoss') if not toon.isEmpty(): toonIval = Sequence(Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)), name='makeToonReleaseInterval-toonIval') grabIval.append(toonIval) else: grabIval = Sequence(Func(self.detachClub)) if not toon.isEmpty(): toonIval = Sequence(Parallel(ActorInterval(toon, 'walk', duration=1.0, playRate=-1.0), LerpPosInterval(toon, duration=1.0, pos=Point3(-10, 0, 0))), Func(toon.wrtReparentTo, render)) grabIval.append(toonIval) if localAvatar.doId == toon.doId: if not self.goingToReward and toon.hp > 0: grabIval.append(Func(self.goToFinalBattle)) grabIval.append(Func(self.notify.debug, 'goingToFinalBattlemode')) grabIval.append(Func(self.safeBossToFinalBattleMode)) return grabIval def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): curState = place.fsm.getCurrentState().getName() if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') else: self.notify.debug('NOT going to final battle, state=%s' % curState) def attachClub(self, avId, pointToBall = False): club = self.club if club: av = base.cr.doId2do.get(avId) if av: av.useLOD(1000) lHand = av.getLeftHands()[0] club.setPos(0, 0, 0) club.reparentTo(lHand) netScale = club.getNetTransform().getScale()[1] counterActToonScale = lHand.find('**/counteractToonScale') if counterActToonScale.isEmpty(): counterActToonScale = lHand.attachNewNode('counteractToonScale') counterActToonScale.setScale(1 / netScale) self.notify.debug('creating counterActToonScale for %s' % av.getName()) club.reparentTo(counterActToonScale) club.setX(-0.25 * netScale) if pointToBall: club.lookAt(self.clubLookatSpot) def detachClub(self): if not self.club.isEmpty(): self.club.reparentTo(self.root) self.club.setZ(-20) self.club.setScale(1) def adjustClub(self): club = self.club if club: distance = club.getDistance(self.clubLookatSpot) scaleFactor = distance / 2.058 club.setScale(1, scaleFactor, 1) def startAdjustClubTask(self): taskMgr.add(self.adjustClubTask, self.adjustClubTaskName) def stopAdjustClubTask(self): taskMgr.remove(self.adjustClubTaskName) def adjustClubTask(self, task): self.attachClub(self.avId, True) self.adjustClub() return task.cont def enableControlKey(self): self.controlKeyAllowed = True def disableControlKey(self): self.controlKeyAllowed = False def sendSwingInfo(self, power, angle, sequenceNum): self.sendUpdate('setSwingInfo', [power, angle, sequenceNum]) def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(root = self.root, relVel = relVel): return render.getRelativeVector(root, relVel) fly = Sequence(Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound return def setSwingInfo(self, power, angle, sequenceNum): av = base.cr.doId2do.get(self.avId) self.swingInterval = Sequence() if av: self.stopAdjustClubTask() self.swingInterval = Sequence(ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback, power, angle, sequenceNum), Func(self.ballModel.hide), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=24), Func(self.ballModel.setScale, 0.1), Func(self.ballModel.show), LerpScaleInterval(self.ballModel, 1.0, Point3(1, 1, 1)), Func(self.enableControlKey)) if av == localAvatar: self.swingInterval.append(Func(self.switchToAnimState, 'GolfPuttLoop', True)) self.swingInterval.start() def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) return self.__flyBallBubble def __flyBallHit(self, entry): print entry def flyBallFinishedFlying(self, sequence): if self.flyBallTracks.has_key(sequence): del self.flyBallTracks[sequence] def __finishFlyBallTrack(self, sequence): if self.flyBallTracks.has_key(sequence): flyBallTrack = self.flyBallTracks[sequence] del self.flyBallTracks[sequence] flyBallTrack.finish() def flyBallFinishedSplatting(self, sequence): if self.splatTracks.has_key(sequence): del self.splatTracks[sequence] def __flyBallHit(self, entry): if not entry.hasSurfacePoint() or not entry.hasInto(): return if not entry.getInto().isTangible(): return sequence = int(entry.getFromNodePath().getNetTag('pieSequence')) self.__finishFlyBallTrack(sequence) if self.splatTracks.has_key(sequence): splatTrack = self.splatTracks[sequence] del self.splatTracks[sequence] splatTrack.finish() flyBallCode = 0 flyBallCodeStr = entry.getIntoNodePath().getNetTag('pieCode') if flyBallCodeStr: flyBallCode = int(flyBallCodeStr) pos = entry.getSurfacePoint(render) timestamp32 = globalClockDelta.getFrameNetworkTime(bits=32) throwerId = int(entry.getFromNodePath().getNetTag('throwerId')) splat = self.getFlyBallSplatInterval(pos[0], pos[1], pos[2], flyBallCode, throwerId) splat = Sequence(splat, Func(self.flyBallFinishedSplatting, sequence)) self.splatTracks[sequence] = splat splat.start() self.notify.debug('doId=%d into=%s flyBallCode=%d, throwerId=%d' % (self.doId, entry.getIntoNodePath(), flyBallCode, throwerId)) if flyBallCode == ToontownGlobals.PieCodeBossCog and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum self.boss.d_ballHitBoss(1) elif flyBallCode == ToontownGlobals.PieCodeToon and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum avatarDoId = entry.getIntoNodePath().getNetTag('avatarDoId') if avatarDoId == '': self.notify.warning('Toon %s has no avatarDoId tag.' % repr(entry.getIntoNodePath())) return doId = int(avatarDoId) if doId != localAvatar.doId: pass def getFlyBallSplatInterval(self, x, y, z, flyBallCode, throwerId): from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps splatName = 'dust' splat = BattleProps.globalPropPool.getProp(splatName) splat.setBillboardPointWorld(2) color = ToontownGlobals.PieCodeColors.get(flyBallCode) if color: splat.setColor(*color) if flyBallCode == ToontownGlobals.PieCodeBossCog: self.notify.debug('changing color to %s' % self.ballColor) splat.setColor(self.ballColor) sound = loader.loadSfx('phase_11/audio/sfx/LB_evidence_miss.ogg') vol = 1.0 if flyBallCode == ToontownGlobals.PieCodeBossCog: sound = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg') soundIval = SoundInterval(sound, node=splat, volume=vol) if flyBallCode == ToontownGlobals.PieCodeBossCog and localAvatar.doId == throwerId: vol = 1.0 soundIval = SoundInterval(sound, node=localAvatar, volume=vol) ival = Parallel(Func(splat.reparentTo, render), Func(splat.setPos, x, y, z), soundIval, Sequence(ActorInterval(splat, splatName), Func(splat.detachNode))) return ival def setGoingToReward(self): self.goingToReward = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True)
class DistributedCannonDefenseShip(DistributedNPCSimpleShip): __module__ = __name__ specialHitSfx = {} coldShotHitSfx = None sharkChompSfx = {} def __init__(self, cr): DistributedNPCSimpleShip.__init__(self, cr) self.goldStolenlbl = None self.hasGoldlbl = None self.hasBNote = None self.textureCard = None self.goldIcon = None self.flameEffects = [] self.isSinkingWhileOnFire = False self.healthModifier = 0 self.modifierSet = False self.shipStatsSet = False self.shipStatIndex = None self.initHealthBar() self.initIndicatorIcons() self.sinkTimeScale = CannonDefenseGlobals.SHIP_SINK_DURATION_SCALE self.sharkActor = Actor( 'models/char/pir_r_gam_fsh_lgComTshark.bam', {'attack': 'models/char/pir_a_gam_fsh_lgComTshark_attack.bam'}) self.sharkParallel = None self.fader = None if not self.coldShotHitSfx: DistributedCannonDefenseShip.specialHitSfx = { InventoryType.DefenseCannonMineInWater: loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_MINE_HIT), InventoryType.DefenseCannonBomb: loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_BOMB_HIT), InventoryType.DefenseCannonHotShot: loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_HOTSHOT_HIT), InventoryType.DefenseCannonFireStorm: loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_FIRESTORM_HIT), InventoryType.DefenseCannonChumShot: loadSfx(SoundGlobals.SFX_MINIGAME_CANNON_SHARK) } DistributedCannonDefenseShip.coldShotHitSfx = loadSfx( SoundGlobals.SFX_MINIGAME_CANNON_ICE_HIT) DistributedCannonDefenseShip.sharkChompSfxs = [ loadSfx(SoundGlobals.SFX_MONSTER_SMASH_01), loadSfx(SoundGlobals.SFX_MONSTER_SMASH_02), loadSfx(SoundGlobals.SFX_MONSTER_SMASH_03) ] return def buildShip(self): DistributedNPCSimpleShip.buildShip(self) self.model.sfxAlternativeStyle = True def setupLocalStats(self): DistributedNPCSimpleShip.setupLocalStats(self) def setShipStatIndex(self, statIndex): self.shipStatsSet = True self.shipStatIndex = statIndex self.maxHp = CannonDefenseGlobals.shipStats[ self.shipStatIndex]['shipHp'] self.maxMastHealth = CannonDefenseGlobals.shipStats[ self.shipStatIndex]['mastHp'] self.healthBar.setPos( 0.0, 0.0, CannonDefenseGlobals.shipStats[self.shipStatIndex] ['healthBarHeight']) if self.modifierSet: self.calcModifiedHealth() def setHealthModifier(self, modifier): self.modifierSet = True self.healthModifier = modifier if self.shipStatsSet: self.calcModifiedHealth() def calcModifiedHealth(self): if self.healthModifier == 0: return self.maxHp += self.healthModifier * ( self.maxHp * CannonDefenseGlobals.ENEMY_DIFFICULTY_INCREASE) mastList = CannonDefenseGlobals.shipStats[self.shipStatIndex]['mastHp'] mastFinalHp = [] for mastHealth in mastList: hp = mastHealth hp += self.healthModifier * ( mastHealth * CannonDefenseGlobals.ENEMY_DIFFICULTY_INCREASE) mastFinalHp.append(hp) self.maxMastHealth = mastFinalHp def setLogo(self, logo): self.logo = logo def setStyle(self, style): self.style = style def announceGenerate(self): DistributedNPCSimpleShip.announceGenerate(self) rad = (self.model.dimensions / 2.0).length() cn = NodePath(CollisionNode('c')) cs = CollisionSphere(0, 0, 0, rad) cn.node().addSolid(cs) cn.reparentTo(self.model.modelCollisions) cn.setTransform(self.model.center.getTransform(self)) cn.node().setIntoCollideMask(PiratesGlobals.GenericShipBitmask) self.model.defendSphere = cn self.model.modelRoot.setScale(CannonDefenseGlobals.SHIP_SCALE) self.fadeIn(CannonDefenseGlobals.SHIP_FADEIN) self.smoother.setExpectedBroadcastPeriod(0.3) self.smoother.setDelay(2) self.healthBar.reparentTo(self.model.modelRoot) def initHealthBar(self): self.healthBar = DirectWaitBar(frameSize=(-0.35, 0.35, -0.04, 0.04), relief=DGG.FLAT, frameColor=(0.0, 0.0, 0.0, 0.0), borderWidth=(0.0, 0.0), barColor=(0.0, 1.0, 0.0, 1.0), scale=100) self.healthBar.setBillboardPointEye() self.healthBar['value'] = 100 self.healthBar.hide(OTPRender.ReflectionCameraBitmask) self.healthBar.setLightOff() def initIndicatorIcons(self): self.textureCard = loader.loadModel( 'models/textureCards/pir_m_gam_can_ship_icons') if self.textureCard: self.goldIcon = self.textureCard.find('**/pir_t_shp_can_gold*') self.goldStolenlbl = DirectLabel( parent=self.healthBar, relief=None, pos=(0, 0, 0.2), text_align=TextNode.ACenter, text_scale=0.5, textMayChange=0, text='!', text_fg=PiratesGuiGlobals.TextFG23, text_shadow=PiratesGuiGlobals.TextShadow, text_font=PiratesGlobals.getPirateBoldOutlineFont(), sortOrder=2) self.goldStolenlbl.setTransparency(1) self.goldStolenlbl.hide() self.hasGoldlbl = DirectLabel(parent=self.healthBar, relief=None, pos=(0, 0, 0.35), image=self.goldIcon, image_scale=0.5, image_pos=(0, 0, 0), sortOrder=2) self.hasGoldlbl.setTransparency(1) self.hasGoldlbl.hide() self.hasBNote = self.healthBar.attachNewNode('noteIndicator') self.bnoteBack = loader.loadModel( 'models/textureCards/skillIcons').find( '**/pir_t_gui_can_moneyIcon').copyTo(self.hasBNote) self.hasBNote.setZ(0.35) self.hasBNote.setScale(0.6) self.hasBNote.hide() return def getHealthBarColor(self, health): return CannonDefenseGlobals.SHIP_HEALTH_COLORS[int( health / 100.0 * (len(CannonDefenseGlobals.SHIP_HEALTH_COLORS) - 1))] def setHealthState(self, health): DistributedNPCSimpleShip.setHealthState(self, health) self.healthBar['value'] = health self.healthBar['barColor'] = self.getHealthBarColor(health) def setCurrentState(self, state): if state == CannonDefenseGlobals.SHIP_STATE_STEALING: self.goldStolenlbl.show() else: if state == CannonDefenseGlobals.SHIP_STATE_HASTREASURE: self.hasGoldlbl.show() self.goldStolenlbl.hide() else: if state == CannonDefenseGlobals.SHIP_STATE_HASBNOTES: self.hasBNote.show() self.goldStolenlbl.hide() else: self.hasGoldlbl.hide() self.hasBNote.hide() self.goldStolenlbl.hide() rad = (self.model.dimensions / 2.0).length() cn = NodePath(CollisionNode('c')) cs = CollisionSphere(0, 0, 0, rad) cn.node().addSolid(cs) cn.reparentTo(self.model.modelCollisions) cn.setTransform(self.model.center.getTransform(self)) cn.node().setIntoCollideMask(PiratesGlobals.GenericShipBitmask) self.model.defendSphere = cn self.model.modelRoot.setScale(CannonDefenseGlobals.SHIP_SCALE) self.fadeIn(CannonDefenseGlobals.SHIP_FADEIN) self.smoother.setExpectedBroadcastPeriod(0.3) self.smoother.setDelay(2) self.healthBar.reparentTo(self.model.modelRoot) def initHealthBar(self): self.healthBar = DirectWaitBar(frameSize=(-0.35, 0.35, -0.04, 0.04), relief=DGG.FLAT, frameColor=(0.0, 0.0, 0.0, 0.0), borderWidth=(0.0, 0.0), barColor=(0.0, 1.0, 0.0, 1.0), scale=100) self.healthBar.setBillboardPointEye() self.healthBar['value'] = 100 self.healthBar.hide(OTPRender.ReflectionCameraBitmask) self.healthBar.setLightOff() def initIndicatorIcons(self): self.textureCard = loader.loadModel( 'models/textureCards/pir_m_gam_can_ship_icons') if self.textureCard: self.goldIcon = self.textureCard.find('**/pir_t_shp_can_gold*') self.goldStolenlbl = DirectLabel( parent=self.healthBar, relief=None, pos=(0, 0, 0.2), text_align=TextNode.ACenter, text_scale=0.5, textMayChange=0, text='!', text_fg=PiratesGuiGlobals.TextFG23, text_shadow=PiratesGuiGlobals.TextShadow, text_font=PiratesGlobals.getPirateBoldOutlineFont(), sortOrder=2) self.goldStolenlbl.setTransparency(1) self.goldStolenlbl.hide() self.hasGoldlbl = DirectLabel(parent=self.healthBar, relief=None, pos=(0, 0, 0.35), image=self.goldIcon, image_scale=0.5, image_pos=(0, 0, 0), sortOrder=2) self.hasGoldlbl.setTransparency(1) self.hasGoldlbl.hide() self.hasBNote = self.healthBar.attachNewNode('noteIndicator') self.bnoteBack = loader.loadModel( 'models/textureCards/skillIcons').find( '**/pir_t_gui_can_moneyIcon').copyTo(self.hasBNote) self.hasBNote.setZ(0.35) self.hasBNote.setScale(0.6) self.hasBNote.hide() return def getHealthBarColor(self, health): return CannonDefenseGlobals.SHIP_HEALTH_COLORS[int( health / 100.0 * (len(CannonDefenseGlobals.SHIP_HEALTH_COLORS) - 1))] def setHealthState(self, health): DistributedNPCSimpleShip.setHealthState(self, health) self.healthBar['value'] = health self.healthBar['barColor'] = self.getHealthBarColor(health) def setCurrentState(self, state): if state == CannonDefenseGlobals.SHIP_STATE_STEALING: self.goldStolenlbl.show() else: if state == CannonDefenseGlobals.SHIP_STATE_HASTREASURE: self.hasGoldlbl.show() self.goldStolenlbl.hide() else: if state == CannonDefenseGlobals.SHIP_STATE_HASBNOTES: self.hasBNote.show() self.goldStolenlbl.hide() else: self.hasGoldlbl.hide() self.hasBNote.hide() self.goldStolenlbl.hide() def calculateLook(self): pass def playProjectileHitSfx(self, ammoSkillId, hitSail): if ammoSkillId in [ InventoryType.DefenseCannonColdShotInWater, InventoryType.DefenseCannonSmokePowder ]: return if ammoSkillId in self.specialHitSfx: sfx = self.specialHitSfx[ammoSkillId] base.playSfx(sfx, node=self, cutoff=2000) return DistributedNPCSimpleShip.playProjectileHitSfx(self, ammoSkillId, hitSail) def projectileWeaponHit(self, skillId, ammoSkillId, skillResult, targetEffects, pos, normal, codes, attacker, itemEffects=[]): DistributedNPCSimpleShip.projectileWeaponHit(self, skillId, ammoSkillId, skillResult, targetEffects, pos, normal, codes, attacker, itemEffects) def sinkingBegin(self): self.healthBar.reparentTo(hidden) if len(self.flameEffects) > 0: self.isSinkingWhileOnFire = True DistributedNPCSimpleShip.sinkingBegin(self) def sinkingEnd(self): while len(self.flameEffects) > 0: effect = self.flameEffects.pop() effect.stopLoop() DistributedNPCSimpleShip.sinkingEnd(self) def addStatusEffect(self, effectId, attackerId, duration=0, timeLeft=0, timestamp=0, buffData=[0]): if effectId == WeaponGlobals.C_CANNON_DEFENSE_FIRE: self.addFireEffect(self.getModelRoot().getPos()) if effectId == WeaponGlobals.C_CANNON_DEFENSE_ICE: base.playSfx(self.coldShotHitSfx, node=self, cutoff=2000) DistributedNPCSimpleShip.addStatusEffect(self, effectId, attackerId, duration, timeLeft, timestamp, buffData) def removeStatusEffect(self, effectId, attackerId): DistributedNPCSimpleShip.removeStatusEffect(self, effectId, attackerId) if effectId == WeaponGlobals.C_CANNON_DEFENSE_FIRE: if not self.isSinkingWhileOnFire: while len(self.flameEffects) > 0: effect = self.flameEffects.pop() effect.stopLoop() def addFireEffect(self, pos): fireEffect = ShipFire.getEffect() if fireEffect: fireEffect.reparentTo(self.getModelRoot()) fireEffect.setPos(pos) fireEffect.setHpr(90, -15, 0) fireEffect.startLoop() fireEffect.setEffectScale(20.0) self.flameEffects.append(fireEffect) def playSharkAttack(self, pos): if self.sharkActor.getCurrentAnim() == None: self.sharkActor.wrtReparentTo(self.getModelRoot()) self.sharkActor.setPos(self, pos) self.sharkActor.setScale(20) self.sharkActor.play('attack') sharkAttackEffect = None if base.options.getSpecialEffectsSetting( ) >= base.options.SpecialEffectsLow: effect = CannonSplash.getEffect() if effect: effect.reparentTo(base.effectsRoot) effect.setPos(self, pos) effect.setZ(1) effect.play() sharkAttackEffect = Func(self.playAttackEffect, pos) hprIvalShip = LerpHprInterval(self.getModelRoot(), duration=3, hpr=(0, 0, -180)) s1 = Sequence(Wait(0.75), hprIvalShip, Func(self.getModelRoot().stash)) s2 = Sequence(Wait(0.75), sharkAttackEffect, Wait(0.5), sharkAttackEffect) self.sharkParallel = Parallel(s1, s2) self.sharkParallel.start() taskMgr.doMethodLater(self.sharkActor.getDuration('attack'), self.detachShark, self.uniqueName('playSharkAttack'), extraArgs=[]) return def playAttackEffect(self, pos): effect = BulletEffect.getEffect() if effect: effect.reparentTo(base.effectsRoot) effect.setPos(self, pos) effect.loadObjects(6) effect.play() sfx = random.choice(self.sharkChompSfxs) base.playSfx(sfx, node=self.getModelRoot(), cutoff=2000) def detachShark(self): self.sharkActor.detachNode() def delete(self): if self.fader: self.fader.pause() self.fader = None DistributedNPCSimpleShip.delete(self) return def destroy(self): if self.goldStolenlbl: self.goldStolenlbl.destroy() self.goldStolenlbl = None if self.hasGoldlbl: self.hasGoldlbl.destroy() self.hasGoldlbl = None if self.textureCard: self.textureCard.removeNode() self.textureCard = None self.goldIcon = None if self.healthBar: self.healthBar.destroy() if self.sharkActor: self.sharkActor.cleanUp() self.sharkActor.removeNode() if self.sharkParallel: self.sharkParallel.pause() self.sharkParallel = None DistributedNPCSimpleShip.destroy(self) return def fadeIn(self, length): if self.fader: self.fader.finish() self.fader = None self.setTransparency(1) self.fader = Sequence( self.colorScaleInterval(length, Vec4(1, 1, 1, 1), Vec4(1, 1, 1, 0)), Func(self.clearTransparency)) self.fader.start() return def fadeOut(self, length): if self.fader: self.fader.finish() self.fader = None self.setTransparency(1) self.fader = Sequence( self.colorScaleInterval(length, Vec4(1, 1, 1, 0), Vec4(1, 1, 1, 1)), Func(self.hide), Func(self.clearTransparency)) self.fader.start() return
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()
class QuestPoster(DirectFrame): notify = directNotify.newCategory('QuestPoster') def __init__(self, quest, parent=aspect2d, **kw): DirectFrame.__init__(self, relief=None) 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) self._deleteCallback = None self.questFrame = DirectFrame(parent=self, relief=None) self.headline = DirectLabel(parent=self.questFrame, relief=None, text='', text_font=CIGlobals.getMinnieFont(), text_fg=self.normalTextColor, text_scale=0.05, text_align=TextNode.ACenter, text_wordwrap=12.0, textMayChange=1, pos=(0, 0, 0.23)) self.questInfo = DirectLabel(parent=self.questFrame, relief=None, text='', text_fg=self.normalTextColor, text_scale=TEXT_SCALE, text_align=TextNode.ACenter, text_wordwrap=TEXT_WORDWRAP, textMayChange=1, pos=(0, 0, -0.0625)) self.rewardText = DirectLabel(parent=self.questFrame, relief=None, text='', text_fg=self.colors['rewardRed'], 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=IMAGE_SCALE_SMALL, text='', text_pos=(0, -0.11), text_fg=self.normalTextColor, text_scale=TEXT_SCALE, text_align=TextNode.ACenter, text_wordwrap=11.0, textMayChange=1) self.lPictureFrame.hide() self.rPictureFrame = DirectFrame( parent=self.questFrame, relief=None, image=bookModel.find('**/questPictureFrame'), image_scale=IMAGE_SCALE_SMALL, text='', text_pos=(0, -0.11), text_fg=self.normalTextColor, text_scale=TEXT_SCALE, text_align=TextNode.ACenter, text_wordwrap=11.0, textMayChange=1, pos=(0.18, 0, 0.13)) self.rPictureFrame.hide() self.lQuestIcon = DirectFrame(parent=self.lPictureFrame, relief=None, text=' ', text_font=CIGlobals.getSuitFont(), text_pos=(0, -0.03), text_fg=self.normalTextColor, 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=self.normalTextColor, text_scale=0.13, text_align=TextNode.ACenter, text_wordwrap=13.0, textMayChange=1) self.rQuestIcon.setColorOff(-1) self.auxText = DirectLabel(parent=self.questFrame, relief=None, text='', text_scale=QuestGlobals.QPauxText, text_fg=self.normalTextColor, text_align=TextNode.ACenter, textMayChange=1) self.auxText.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_scale=0.19, text_fg=(0.05, 0.14, 0.4, 1), text_align=TextNode.ACenter, text_pos=(0, -0.04), pos=(0, 0, -0.195)) self.questProgress.hide() # 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 return def destroy(self): self._deleteGeoms() DirectFrame.destroy(self) def _deleteGeoms(self): for icon in (self.lQuestIcon, self.rQuestIcon): geom = icon['geom'] if geom: if hasattr(geom, 'delete'): geom.delete()
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))
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
class DistributedGolfSpot(DistributedObject.DistributedObject, FSM.FSM): """ This is one of four golf spots to appear in the corner of the CEO banquet room. """ notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfSpot') positions = ((-45, 100, GolfGlobals.GOLF_BALL_RADIUS), (-15, 100, GolfGlobals.GOLF_BALL_RADIUS), (15, 100, GolfGlobals.GOLF_BALL_RADIUS), (45, 100, GolfGlobals.GOLF_BALL_RADIUS)) toonGolfOffsetPos = Point3(-2, 0, -GolfGlobals.GOLF_BALL_RADIUS) toonGolfOffsetHpr = Point3(-90, 0, 0) rotateSpeed = 20 # degrees per second # The number of seconds it takes to move the power meter to # full the first time. golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3) # The exponent that controls the factor at which the power # meter slows down over time. Values closer to 1.0 slow down less # quickly. golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None # the actual toon which should match up with self.avId self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if (self.index is not None) and (self.index > len(self.positions)): self.notify.error("Invalid index %d" % self.index) self.fadeTrack = None # stuff related to power bar self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None # This number increments each time we change direction on the # crane controls. It's used to update the animation # appropriately. self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None def setBossCogId(self, bossCogId): """Handle receiving the CEO doId from the server.""" self.bossCogId = bossCogId # This would be risky if we had toons entering the zone during # a battle--but since all the toons are always there from the # beginning, we can be confident that the BossCog has already # been generated by the time we receive the generate for its # associated battles. self.boss = base.cr.doId2do[bossCogId] self.boss.setGolfSpot(self, self.index) def setIndex(self, index): """Handle receiving the index which identifies our side the server.""" self.index = index # WARNING debug only, remove this #if (index == 0): # base.gs = self def disable(self): """Disable ourself.""" DistributedObject.DistributedObject.disable(self) self.ignoreAll() def delete(self): """Delete ourself.""" DistributedObject.DistributedObject.delete(self) self.ignoreAll() self.boss = None def announceGenerate(self): """Do more setup once all required fields are in.""" DistributedObject.DistributedObject.announceGenerate(self) self.triggerName = self.uniqueName('trigger') self.triggerEvent = 'enter%s' % (self.triggerName) self.smoothName = self.uniqueName('golfSpotSmooth') self.golfSpotAdviceName = self.uniqueName('golfSpotAdvice') self.posHprBroadcastName = self.uniqueName('golfSpotBroadcast') self.ballPowerTaskName = self.uniqueName('updateGolfPower') self.adjustClubTaskName = self.uniqueName('adjustClub') self.loadAssets() self.accept('flyBallHit-%d' % self.index, self.__flyBallHit) def loadAssets(self): """Load our assets.""" self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) # create a collision sphere to trigger when we touch the ball # Make a trigger sphere so we can detect when the local avatar # runs up to the controls. We bury the sphere mostly under # the floor to minimize accidental collisions. cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.mp3') def cleanup(self): if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None flyTracks = list(self.flyBallTracks.values()) for track in flyTracks: track.finish() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None if self.restoreScaleTrack: self.restoreScaleTrack.finish() self.restoreScaleTrack = None self.root.removeNode() self.ballModel.removeNode() self.club.removeNode() if self.powerBar: self.powerBar.destroy() self.powerBar = None taskMgr.remove(self.triggerName) assert self.notify.debugStateCall(self) self.boss = None def setState(self, state, avId, extraInfo): """Handle the AI telling us the current state, and who controls us.""" if not self.isDisabled(): self.gotHitByBoss = extraInfo if state == 'C': self.demand('Controlled', avId) elif state == 'F': self.demand('Free') elif state == 'O': self.demand('Off') else: self.notify.error("Invalid state from AI: %s" % (state)) ### FSM States ### def enterOff(self): """Handle entering the off state.""" assert self.notify.debugStateCall(self) pass def exitOff(self): """Handle exiting the off state.""" assert self.notify.debugStateCall(self) pass def enterFree(self): """Handle entering the free state.""" assert self.notify.debugStateCall(self) if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None # Wait a few seconds before neutralizing the scale; maybe the # same avatar wants to come right back (after his 5-second # timeout). self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval(), name="restoreScaleTrack") self.restoreScaleTrack.start() if self.avId == localAvatar.doId: # Five second timeout on grabbing the same crane again. Go # get a different crane! if not self.isDisabled(): self.ballModel.setAlphaScale(0.3) self.ballModel.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.ballModel.setTransparency, 1), self.ballModel.colorScaleInterval( 0.2, VBase4(1, 1, 1, 0.3)), name='fadeTrack-enterFree') self.fadeTrack.start() else: # Other players can grab this crane immediately. self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) self.avId = 0 def exitFree(self): """Handle exiting the free state.""" if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack.finish() # make sure we don't see a small ball self.restoreScaleTrack = None taskMgr.remove(self.triggerName) #self.ballModel.clearColorScale() self.ballModel.clearTransparency() self.trigger.stash() self.ignore(self.triggerEvent) pass def enterControlled(self, avId): """Handle entering the controlled state.""" assert self.notify.debugStateCall(self) self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.enableControlKey() self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) if avId == localAvatar.doId: # The local toon is beginning to control the crane. self.boss.toCraneMode() camera.reparentTo(self.root) camera.setPosHpr(0, -10, 3, 0, 0, 0) #self.tube.stash() #localAvatar.setPosHpr(self.controls, 0, 0, 0, 0, 0, 0) localAvatar.setPos(self.root, self.toonGolfOffsetPos) localAvatar.setHpr(self.root, self.toonGolfOffsetHpr) localAvatar.sendCurrentPosition() #self.__activatePhysics() self.__enableControlInterface() self.startPosHprBroadcast() #self.startShadow() # If we get a message from the Place that we exited Crane # mode--for instance, because we got hit by flying # gears--then ask the AI to yield us up. self.accept('exitCrane', self.gotBossZapped) else: pass #self.startSmooth() #toon.stopSmooth() #self.grabTrack = Sequence(self.grabTrack, # Func(toon.startSmooth)) self.grabTrack.start() pass def exitControlled(self): """Handle exiting the controlled state.""" assert self.notify.debugStateCall(self) self.grabTrack.finish() del self.grabTrack if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if not self.ballModel.isEmpty(): if self.ballModel.isHidden(): self.notify.debug('ball is hidden scale =%s' % self.ballModel.getScale()) else: self.notify.debug('ball is showing scale=%s' % self.ballModel.getScale()) if self.toon and not self.toon.isDisabled(): #self.toon.loop('neutral') #self.notify.debug('looping neutral') self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() #self.stopShadow() self.stopSmooth() if self.avId == localAvatar.doId: # The local toon is no longer in control of the crane. self.__disableControlInterface() #self.__deactivatePhysics() #self.tube.unstash() if not self.goingToReward: camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) #self.__straightenCable() #self.avId = 0 #self.toon = None self.stopAdjustClubTask() self.releaseTrack.start() self.enableControlKey() def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence( self.ballModel.colorScaleInterval(0.2, self.ballColor), #Func(self.ballModel.clearColorScale), Func(self.ballModel.clearTransparency), name='fadeTrack-allowDetect') self.fadeTrack.start() self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) def __hitTrigger(self, event): self.d_requestControl() def getRestoreScaleInterval(self): # This undoes the effect of accomodateToon(), to restore the # controls' scale to neutral position. Unlike # accomodateToon(), it has no side effects; you must play (or # immediately finish) the interval to restore the scale. return Sequence() #lerpTime = 1 #return Parallel( # self.controlModel.scaleInterval(lerpTime, 1, blendType = 'easeInOut'), # self.cc.posInterval(lerpTime, Point3(0, 0, 0), blendType = 'easeInOut'), # self.bottom.posInterval(lerpTime, self.bottomPos, blendType = 'easeInOut'), # self.stickHinge.quatInterval(lerpTime, self.neutralStickHinge, blendType = 'easeInOut'), # ) def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def makeToonGrabInterval(self, toon): # Generates an interval showing the crane controls scaling to # match the toon and the toon simultaneously reaching to grab # the controls. Thenceforth, the toon will animate with the # controls. origPos = toon.getPos(self.root) origHpr = toon.getHpr(self.root) a = self.accomodateToon(toon) newPos = toon.getPos() newHpr = toon.getHpr() origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0])) self.notify.debug('toon.setPosHpr %s %s' % (origPos, origHpr)) toon.setPosHpr(origPos, origHpr) walkTime = 0.2 reach = Sequence() #ActorInterval(toon, 'GolfPuttLoop') if reach.getDuration() < walkTime: reach = Sequence( ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach) i = Sequence( Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), #Func(self.startWatchJoystick, toon) Func(toon.stopLookAround), ) if toon == base.localAvatar: i.append(Func(self.switchToAnimState, 'GolfPuttLoop')) i.append(Func(self.startAdjustClubTask)) i = Parallel(i, a) return i def accomodateToon(self, toon): # This method has two effects: # (1) It computes and returns an interval to scale and slide # the crane controls to suit the indicated toon. # (2) As a side effect, when it returns, the crane controls are # *already* scaled and slid to accomodate the toon, and the toon # has been positioned in place to operate the controls. # Thus, you can use it either by calling it and playing the # interval that it returns to get a smooth lerp, or simply by # calling it and ignoring the return value, to jump to # position. toon.wrtReparentTo(self.root) toon.setPos(self.toonGolfOffsetPos) toon.setHpr(self.toonGolfOffsetHpr) return Sequence() def switchToAnimState(self, animStateName, forced=False): """Switch the toon to another anim state if not in it already.""" # temp since we only have anims for male medium torso medium legs #dna = base.localAvatar.getStyle() #if not( dna.gender == 'm' and (dna.torso =='ms' or dna.torso =='ls')\ # and (dna.legs=='m' or dna.legs=='l')): # return curAnimState = base.localAvatar.animFSM.getCurrentState() #self.notify.debug('curAnimState=%s' % curAnimState) curAnimStateName = '' if curAnimState: curAnimStateName = curAnimState.getName() if curAnimStateName != animStateName or forced: base.localAvatar.b_setAnimState(animStateName) def __enableControlInterface(self): """Enable the control interface.""" gui = loader.loadModel("phase_3.5/models/gui/avatar_panel_gui") self.closeButton = DirectButton( image=( gui.find("**/CloseBtn_UP"), gui.find("**/CloseBtn_DN"), gui.find("**/CloseBtn_Rllvr"), gui.find("**/CloseBtn_UP"), ), relief=None, scale=2, text=TTLocalizer.BossbotGolfSpotLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitGolfSpot, ) self.accept('escape', self.__exitGolfSpot) self.accept('control', self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) taskMgr.add(self.__watchControls, 'watchGolfSpotControls') # In case they don't figure it out, hit them over the head # with it after a few seconds. taskMgr.doMethodLater(5, self.__displayGolfSpotAdvice, self.golfSpotAdviceName) #taskMgr.doMethodLater(10, self.__displayMagnetAdvice, # self.magnetAdviceName) # Up in the sky, it's hard to read what people are saying. #NametagGlobals.setOnscreenChatForced(1) self.arrowVert = 0 self.arrowHorz = 0 if self.powerBar: self.powerBar.show() def __disableControlInterface(self): """Disable the control interface.""" #self.__turnOffMagnet() if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupGolfSpotAdvice() #self.__cleanupMagnetAdvice() self.ignore('escape') self.ignore('control') self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.arrowVert = 0 self.arrowHorz = 0 #NametagGlobals.setOnscreenChatForced(0) taskMgr.remove('watchGolfSpotControls') if self.powerBar: self.powerBar.hide() else: self.notify.debug('self.powerBar is none') #self.__setMoveSound(None) def setupPowerBar(self): """Create the power bar for the water golfSpot.""" self.powerBar = DirectWaitBar( pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text="", text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05), ) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): """Bring the power and power bar to zero.""" self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' def __displayGolfSpotAdvice(self, task): """Display golfSpot advice on the screen.""" if self.golfSpotAdviceLabel == None: self.golfSpotAdviceLabel = DirectLabel( text=TTLocalizer.BossbotGolfSpotAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) def __cleanupGolfSpotAdvice(self): """Remove golfSpot advice from the screen.""" if self.golfSpotAdviceLabel: self.golfSpotAdviceLabel.destroy() self.golfSpotAdviceLabel = None taskMgr.remove(self.golfSpotAdviceName) def showExiting(self): """Indicate that we've sent an exiting message to AI.""" if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotGolfSpotLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1), ) self.__cleanupGolfSpotAdvice() def __exitGolfSpot(self): """Handle the toon clicking on exit button.""" self.d_requestFree(False) def __controlPressed(self): """Handle control key being pressed.""" if self.controlKeyAllowed: self.__beginFireBall() pass #self.__cleanupMagnetAdvice() #self.__turnOnMagnet() def __controlReleased(self): """Handle control key being released.""" if self.controlKeyAllowed: self.__endFireBall() def __upArrow(self, pressed): """Handle up arrow key being pressed.""" self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): """Handle down arrow key being pressed.""" self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): """Handle right arrow key being pressed.""" self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = 1 self.switchToAnimState('GolfRotateLeft') elif self.arrowHorz > 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __leftArrow(self, pressed): """Handle left arrow key being pressed.""" self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = -1 self.switchToAnimState('GolfRotateRight') elif self.arrowHorz < 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __watchControls(self, task): """Check the arrow key press and call move golfSpot if needed.""" if self.arrowHorz: self.__moveGolfSpot(self.arrowHorz) else: pass #self.__setMoveSound(None) return Task.cont def __moveGolfSpot(self, xd): """Rotate the golfSpot by the given xdelta.""" dt = globalClock.getDt() h = self.root.getH() - xd * self.rotateSpeed * dt h %= 360 limitH = h self.root.setH(limitH) #self.__setMoveSound(self.craneMoveSfx) def __incrementChangeSeq(self): """Increment our change counter.""" self.changeSeq = (self.changeSeq + 1) & 0xff def __beginFireBall(self): """Handle player pressing control and starting the power meter.""" # The control key was pressed. if self.aimStart != None: # This is probably just key-repeat. return if not self._state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateBallPower, self.ballPowerTaskName) def __endFireBall(self): """Handle player releasing control and shooting the ball.""" # The control key was released. Fire the ball. if self.aimStart == None: return if not self._state == 'Controlled': return if not self.avId == localAvatar.doId: return #if not self.power: # return taskMgr.remove(self.ballPowerTaskName) self.disableControlKey() messenger.send('wakeup') self.aimStart = None power = self.power angle = self.root.getH() self.notify.debug('incrementing self.__flyBallSequenceNum') self.__flyBallSequenceNum = (self.__flyBallSequenceNum + 1) % 0xff self.sendSwingInfo(power, angle, self.__flyBallSequenceNum) self.setSwingInfo(power, angle, self.__flyBallSequenceNum) self.resetPowerBar() pass #self.__turnOffMagnet() def __updateBallPower(self, task): """Change the value of the power meter.""" if not self.powerBar: print("### no power bar!!!") return task.done newPower = self.__getBallPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower return task.cont def __getBallPower(self, time): """Return a value between 0 and 100 to indicate golf power.""" elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.golfPowerSpeed t = math.pow(t, self.golfPowerExponent) power = int(t * 100) % 200 if power > 100: power = 200 - power return power def stopPosHprBroadcast(self): """Stop the pitcher rotation broadcast task.""" taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): """Start the golfSpot rotation broadcast task.""" taskName = self.posHprBroadcastName # Broadcast our initial position self.b_clearSmoothing() self.d_sendGolfSpotPos() # remove any old tasks taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): """Periodically broadcast the golfSpot rotation.""" self.d_sendGolfSpotPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendGolfSpotPos(self): """Send the golfSpot rotation to the other clients.""" timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate( 'setGolfSpotPos', [self.changeSeq, self.root.getH(), timestamp]) def setGolfSpotPos(self, changeSeq, h, timestamp): """Handle another client sending an update on the golfSpot rotation.""" #assert self.notify.debugStateCall(self) self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) #self.golfSpotSmoother.setY(y) self.golfSpotSmoother.setH(h) self.golfSpotSmoother.setTimestamp(local) self.golfSpotSmoother.markPosition() else: #self.crane.setY(y) self.root.setH(h) ### Handle smoothing of distributed updates. This is similar to ### code in DistributedSmoothNode, but streamlined for our ### purposes. def b_clearSmoothing(self): """Tell us and other clients to clear smoothing.""" self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): """Tell other clients to clear smoothing.""" self.sendUpdate("clearSmoothing", [0]) def clearSmoothing(self, bogus=None): """Invalidate old position reports.""" # Call this to invalidate all the old position reports # (e.g. just before popping to a new position). self.golfSpotSmoother.clearPositions(1) def doSmoothTask(self, task): """ This function updates the position of the node to its computed smoothed position. This may be overridden by a derived class to specialize the behavior. """ self.golfSpotSmoother.computeAndApplySmoothHpr(self.root) return Task.cont def startSmooth(self): """ This function starts the task that ensures the node is positioned correctly every frame. However, while the task is running, you won't be able to lerp the node or directly position it. """ if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): """ This function stops the task spawned by startSmooth(), and allows show code to move the node around directly. """ if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def makeToonReleaseInterval(self, toon): """Return an interval of the toon jumping to pitcher position.""" def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if self.gotHitByBoss: grabIval = Sequence(Func(self.detachClub), name='makeToonReleaseInterval-gotHitByBoss') if not toon.isEmpty(): toonIval = Sequence(Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)), name='makeToonReleaseInterval-toonIval') #Func(toon.loop, 'neutral'), grabIval.append(toonIval) else: grabIval = Sequence(Func(self.detachClub), ) if not toon.isEmpty(): toonIval = Sequence( Parallel( ActorInterval(toon, 'walk', duration=1.0, playRate=-1.0), LerpPosInterval( toon, duration=1.0, pos=Point3(-10, 0, 0), )), Func(toon.wrtReparentTo, render), #Func(toon.loop, 'neutral'), ) grabIval.append(toonIval) if localAvatar.doId == toon.doId: if not self.goingToReward and toon.hp > 0: grabIval.append(Func(self.goToFinalBattle)) grabIval.append( Func(self.notify.debug, 'goingToFinalBattlemode')) grabIval.append(Func(self.safeBossToFinalBattleMode)) return grabIval def safeBossToFinalBattleMode(self): """Call boss.toFinalBattleMode if self.boss is valid.""" if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): """Go to final battle if we're in crane mode.""" # This is a bit hacky. Go back to finalBattle mode, but # only if we're still in crane mode. (We might have been # zapped to 'ouch' mode by a hit.) if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): curState = place.fsm.getCurrentState().getName() if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') else: self.notify.debug('NOT going to final battle, state=%s' % curState) def attachClub(self, avId, pointToBall=False): """Attach the club to the right hand.""" club = self.club if club: av = base.cr.doId2do.get(avId) if av: av.useLOD(1000) lHand = av.getLeftHands()[0] club.setPos(0, 0, 0) club.reparentTo(lHand) # we have to account for small toons like the mouse netScale = club.getNetTransform().getScale()[1] counterActToonScale = lHand.find('**/counteractToonScale') if counterActToonScale.isEmpty(): counterActToonScale = lHand.attachNewNode( 'counteractToonScale') counterActToonScale.setScale(1 / netScale) self.notify.debug('creating counterActToonScale for %s' % av.getName()) club.reparentTo(counterActToonScale) club.setX(-0.25 * netScale) if pointToBall: club.lookAt(self.clubLookatSpot) # self.notify.debug('after lookat, hpr = %s' % club.getHpr()) def detachClub(self): """Detach the club and store it someplace safe.""" if not self.club.isEmpty(): self.club.reparentTo(self.root) self.club.setZ(-20) self.club.setScale(1) def adjustClub(self): """Change the club so that the head is more or less behind the ball.""" club = self.club if club: distance = club.getDistance(self.clubLookatSpot) # from maya the club has a length of 2.058, scaleFactor = distance / 2.058 # self.notify.debug('scaleFactor = %s' % scaleFactor) club.setScale(1, scaleFactor, 1) def startAdjustClubTask(self): """Start the task to automatically adjust the club so it looks right.""" taskMgr.add(self.adjustClubTask, self.adjustClubTaskName) def stopAdjustClubTask(self): """Stop the task to automatically adjust the club so it looks right.""" taskMgr.remove(self.adjustClubTaskName) def adjustClubTask(self, task): """Continuously adjust the club so the head is behind the ball.""" self.attachClub(self.avId, True) self.adjustClub() return task.cont def enableControlKey(self): """Allow control key events to come in.""" self.controlKeyAllowed = True def disableControlKey(self): """Disable control key events from coming in.""" self.controlKeyAllowed = False def sendSwingInfo(self, power, angle, sequenceNum): """Tell the other clients we're firing.""" self.sendUpdate('setSwingInfo', [power, angle, sequenceNum]) def startBallPlayback(self, power, angle, sequenceNum): """Start the ball flying in the air.""" assert self.notify.debugStateCall(self) # duplicate our current ball model flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) # First, create a ProjectileInterval to compute the relative # velocity. t = power / 100.0 # make the ball travel farther, the longer you press the bar t = 1.0 - t # Distance ranges from 300 - 100 ft, time ranges from 1.5 - 2 s. dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval( None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time, ) relVel = proj.startVel def getVelocity(root=self.root, relVel=relVel): return render.getRelativeVector(root, relVel) fly = Sequence( #Func(self.ballModel.hide), Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, "removed collider"), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound pass def setSwingInfo(self, power, angle, sequenceNum): """Handle a toon swinging at the golf ball.""" assert self.notify.debugStateCall(self) av = base.cr.doId2do.get(self.avId) self.swingInterval = Sequence() if av: self.stopAdjustClubTask() self.swingInterval = Sequence( ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback, power, angle, sequenceNum), Func(self.ballModel.hide), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=24), Func(self.ballModel.setScale, 0.1), Func(self.ballModel.show), LerpScaleInterval(self.ballModel, 1.0, Point3(1, 1, 1)), Func(self.enableControlKey), ) if av == localAvatar: self.swingInterval.append( Func(self.switchToAnimState, 'GolfPuttLoop', True)) self.swingInterval.start() def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) #self.flyBallHandler.addInPattern('flyBallHit-%d--%in') return self.__flyBallBubble def __flyBallHit(self, entry): """Handle the flying golf ball hitting something in the world.""" #import pdb; pdb.set_trace() print(entry) pass def flyBallFinishedFlying(self, sequence): """Handle the flyball sequence finishing.""" if sequence in self.flyBallTracks: del self.flyBallTracks[sequence] def __finishFlyBallTrack(self, sequence): """Force the flyball sequence to finish prematurely.""" if sequence in self.flyBallTracks: flyBallTrack = self.flyBallTracks[sequence] del self.flyBallTracks[sequence] flyBallTrack.finish() def flyBallFinishedSplatting(self, sequence): """Handle the flyball splatt finishing.""" if sequence in self.splatTracks: del self.splatTracks[sequence] def __flyBallHit(self, entry): """Handle the flyball colliding against something in the world.""" if not entry.hasSurfacePoint() or not entry.hasInto(): # Not a collision solid we understand. Weird. return if not entry.getInto().isTangible(): # Just a trigger polygon. Ignore it. return sequence = int(entry.getFromNodePath().getNetTag('pieSequence')) self.__finishFlyBallTrack(sequence) if sequence in self.splatTracks: splatTrack = self.splatTracks[sequence] del self.splatTracks[sequence] splatTrack.finish() # The pie hit something solid. Generate a distributed splat. # Check the thing we hit for a pieCode. If it has one, it # gets passed along with the message. This may mean something # different according to context (it may indicate, for # instance, the kind of target we hit). flyBallCode = 0 flyBallCodeStr = entry.getIntoNodePath().getNetTag('pieCode') if flyBallCodeStr: flyBallCode = int(flyBallCodeStr) pos = entry.getSurfacePoint(render) timestamp32 = globalClockDelta.getFrameNetworkTime(bits=32) throwerId = int(entry.getFromNodePath().getNetTag('throwerId')) splat = self.getFlyBallSplatInterval(pos[0], pos[1], pos[2], flyBallCode, throwerId) splat = Sequence(splat, Func(self.flyBallFinishedSplatting, sequence)) assert sequence not in self.splatTracks self.splatTracks[sequence] = splat splat.start() self.notify.debug( 'doId=%d into=%s flyBallCode=%d, throwerId=%d' % (self.doId, entry.getIntoNodePath(), flyBallCode, throwerId)) if flyBallCode == ToontownGlobals.PieCodeBossCog and \ self.avId == localAvatar.doId and \ self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum self.boss.d_ballHitBoss(1) elif flyBallCode == ToontownGlobals.PieCodeToon and \ self.avId == localAvatar.doId and \ self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum avatarDoId = entry.getIntoNodePath().getNetTag('avatarDoId') if avatarDoId == '': self.notify.warning("Toon %s has no avatarDoId tag." % (repr(entry.getIntoNodePath()))) return doId = int(avatarDoId) if doId != localAvatar.doId: # turn this off since food comes out of the belt # self.boss.d_hitToon(doId) pass def getFlyBallSplatInterval(self, x, y, z, flyBallCode, throwerId): """Return an interval showing a flyBall hitting a target in the world.""" from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps splatName = 'dust' splat = BattleProps.globalPropPool.getProp(splatName) splat.setBillboardPointWorld(2) color = ToontownGlobals.PieCodeColors.get(flyBallCode) if color: splat.setColor(*color) if flyBallCode == ToontownGlobals.PieCodeBossCog: self.notify.debug('changing color to %s' % self.ballColor) splat.setColor(self.ballColor) sound = loader.loadSfx('phase_11/audio/sfx/LB_evidence_miss.mp3') vol = 1.0 if flyBallCode == ToontownGlobals.PieCodeBossCog: sound = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.mp3') soundIval = SoundInterval(sound, node=splat, volume=vol) if flyBallCode == ToontownGlobals.PieCodeBossCog and \ localAvatar.doId == throwerId: vol = 1.0 soundIval = SoundInterval(sound, node=localAvatar, volume=vol) ival = Parallel( Func(splat.reparentTo, render), Func(splat.setPos, x, y, z), soundIval, Sequence(ActorInterval(splat, splatName), Func(splat.detachNode)), ) return ival def setGoingToReward(self): """Flag that the boss battle is going to the reward state.""" assert self.notify.debugStateCall(self) self.goingToReward = True def gotBossZapped(self): """Handle the local toon getting hit by a ranged attack.""" self.showExiting() self.d_requestFree(True)
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)