from toontown.toonbase.ToontownBattleGlobals import * import types from direct.fsm import StateData from direct.fsm import ClassicFSM, State from direct.fsm import State import TownBattleAttackPanel import TownBattleWaitPanel import TownBattleChooseAvatarPanel import TownBattleSOSPanel import TownBattleSOSPetSearchPanel import TownBattleSOSPetInfoPanel import TownBattleToonPanel import TownBattleCogPanel from toontown.toontowngui import TTDialog from direct.directnotify import DirectNotifyGlobal from toontown.battle import BattleBase from toontown.toonbase import ToontownTimer from direct.showbase import PythonUtil from toontown.toonbase import TTLocalizer from toontown.pets import PetConstants from direct.gui.DirectGui import DGG from toontown.battle import FireCogPanel class TownBattle(StateData.StateData): notify = DirectNotifyGlobal.directNotify.newCategory('TownBattle') evenPos = (0.75, 0.25, -0.25, -0.75) oddPos = (0.5, 0, -0.5) def __init__(self, doneEvent): StateData.StateData.__init__(self, doneEvent) self.numCogs = 1 self.creditLevel = None self.luredIndices = [] self.trappedIndices = [] self.numToons = 1 self.toons = [] self.localNum = 0 self.time = 0 self.bldg = 0 self.track = -1 self.level = -1 self.target = 0 self.toonAttacks = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0)] self.fsm = ClassicFSM.ClassicFSM('TownBattle', [ State.State('Off', self.enterOff, self.exitOff, ['Attack']), State.State('Attack', self.enterAttack, self.exitAttack, ['ChooseCog', 'ChooseToon', 'AttackWait', 'Run', 'Fire', 'SOS']), State.State('ChooseCog', self.enterChooseCog, self.exitChooseCog, ['AttackWait', 'Attack']), State.State('AttackWait', self.enterAttackWait, self.exitAttackWait, ['ChooseCog', 'ChooseToon', 'Attack']), State.State('ChooseToon', self.enterChooseToon, self.exitChooseToon, ['AttackWait', 'Attack']), State.State('Run', self.enterRun, self.exitRun, ['Attack']), State.State('SOS', self.enterSOS, self.exitSOS, ['Attack', 'AttackWait', 'SOSPetSearch', 'SOSPetInfo']), State.State('SOSPetSearch', self.enterSOSPetSearch, self.exitSOSPetSearch, ['SOS', 'SOSPetInfo']), State.State('SOSPetInfo', self.enterSOSPetInfo, self.exitSOSPetInfo, ['SOS', 'AttackWait']), State.State('Fire', self.enterFire, self.exitFire, ['Attack', 'AttackWait'])], 'Off', 'Off') self.runPanel = TTDialog.TTDialog(dialogName='TownBattleRunPanel', text=TTLocalizer.TownBattleRun, style=TTDialog.TwoChoice, command=self.__handleRunPanelDone) self.runPanel.hide() self.attackPanelDoneEvent = 'attack-panel-done' self.attackPanel = TownBattleAttackPanel.TownBattleAttackPanel(self.attackPanelDoneEvent) self.waitPanelDoneEvent = 'wait-panel-done' self.waitPanel = TownBattleWaitPanel.TownBattleWaitPanel(self.waitPanelDoneEvent) self.chooseCogPanelDoneEvent = 'choose-cog-panel-done' self.chooseCogPanel = TownBattleChooseAvatarPanel.TownBattleChooseAvatarPanel(self.chooseCogPanelDoneEvent, 0) self.chooseToonPanelDoneEvent = 'choose-toon-panel-done' self.chooseToonPanel = TownBattleChooseAvatarPanel.TownBattleChooseAvatarPanel(self.chooseToonPanelDoneEvent, 1) self.SOSPanelDoneEvent = 'SOS-panel-done' self.SOSPanel = TownBattleSOSPanel.TownBattleSOSPanel(self.SOSPanelDoneEvent) self.SOSPetSearchPanelDoneEvent = 'SOSPetSearch-panel-done' self.SOSPetSearchPanel = TownBattleSOSPetSearchPanel.TownBattleSOSPetSearchPanel(self.SOSPetSearchPanelDoneEvent) self.SOSPetInfoPanelDoneEvent = 'SOSPetInfo-panel-done' self.SOSPetInfoPanel = TownBattleSOSPetInfoPanel.TownBattleSOSPetInfoPanel(self.SOSPetInfoPanelDoneEvent) self.fireCogPanelDoneEvent = 'fire-cog-panel-done' self.FireCogPanel = FireCogPanel.FireCogPanel(self.fireCogPanelDoneEvent) self.cogFireCosts = [None, None, None, None] self.toonPanels = (TownBattleToonPanel.TownBattleToonPanel(0), TownBattleToonPanel.TownBattleToonPanel(1), TownBattleToonPanel.TownBattleToonPanel(2), TownBattleToonPanel.TownBattleToonPanel(3)) self.cogPanels = (TownBattleCogPanel.TownBattleCogPanel(0), TownBattleCogPanel.TownBattleCogPanel(1), TownBattleCogPanel.TownBattleCogPanel(2), TownBattleCogPanel.TownBattleCogPanel(3)) self.timer = ToontownTimer.ToontownTimer() self.timer.posInTopRightCorner() self.timer.setScale(0.4) self.timer.hide() return def cleanup(self): self.ignore(self.attackPanelDoneEvent) self.unload() del self.fsm self.runPanel.cleanup() del self.runPanel del self.attackPanel del self.waitPanel del self.chooseCogPanel del self.chooseToonPanel del self.SOSPanel del self.FireCogPanel del self.SOSPetSearchPanel del self.SOSPetInfoPanel for toonPanel in self.toonPanels: toonPanel.cleanup() for cogPanel in self.cogPanels: cogPanel.cleanup() del self.toonPanels del self.cogPanels self.timer.destroy() del self.timer del self.toons def enter(self, event, parentFSMState, bldg = 0, creditMultiplier = 1, tutorialFlag = 0): self.parentFSMState = parentFSMState self.parentFSMState.addChild(self.fsm) if not self.isLoaded: self.load() print 'Battle Event %s' % event self.battleEvent = event self.fsm.enterInitialState() base.localAvatar.laffMeter.start() self.numToons = 1 self.numCogs = 1 self.toons = [base.localAvatar.doId] self.toonPanels[0].setLaffMeter(base.localAvatar) self.bldg = bldg self.creditLevel = None self.creditMultiplier = creditMultiplier self.tutorialFlag = tutorialFlag base.localAvatar.inventory.setBattleCreditMultiplier(self.creditMultiplier) base.localAvatar.inventory.setActivateMode('battle', heal=0, bldg=bldg, tutorialFlag=tutorialFlag) self.SOSPanel.bldg = bldg return def exit(self): base.localAvatar.laffMeter.stop() self.parentFSMState.removeChild(self.fsm) del self.parentFSMState base.localAvatar.inventory.setBattleCreditMultiplier(1) def load(self): if self.isLoaded: return self.attackPanel.load() self.waitPanel.load() self.chooseCogPanel.load() self.chooseToonPanel.load() self.SOSPanel.load() if hasattr(base, 'wantPets') and base.wantPets: self.SOSPetSearchPanel.load() self.SOSPetInfoPanel.load() self.isLoaded = 1 def unload(self): if not self.isLoaded: return self.attackPanel.unload() self.waitPanel.unload() self.chooseCogPanel.unload() self.chooseToonPanel.unload() self.FireCogPanel.unload() self.SOSPanel.unload() if hasattr(base, 'wantPets') and base.wantPets: self.SOSPetSearchPanel.unload() self.SOSPetInfoPanel.unload() self.isLoaded = 0 def setState(self, state): if hasattr(self, 'fsm'): self.fsm.request(state) def updateTimer(self, time): self.time = time self.timer.setTime(time) return None def __enterPanels(self, num, localNum): self.notify.debug('enterPanels() num: %d localNum: %d' % (num, localNum)) for toonPanel in self.toonPanels: toonPanel.hide() toonPanel.setPos(0, 0, -0.9) if num == 1: self.toonPanels[0].setX(self.oddPos[1]) self.toonPanels[0].show() elif num == 2: self.toonPanels[0].setX(self.evenPos[1]) self.toonPanels[0].show() self.toonPanels[1].setX(self.evenPos[2]) self.toonPanels[1].show() elif num == 3: self.toonPanels[0].setX(self.oddPos[0]) self.toonPanels[0].show() self.toonPanels[1].setX(self.oddPos[1]) self.toonPanels[1].show() self.toonPanels[2].setX(self.oddPos[2]) self.toonPanels[2].show() elif num == 4: self.toonPanels[0].setX(self.evenPos[0]) self.toonPanels[0].show() self.toonPanels[1].setX(self.evenPos[1]) self.toonPanels[1].show() self.toonPanels[2].setX(self.evenPos[2]) self.toonPanels[2].show() self.toonPanels[3].setX(self.evenPos[3]) self.toonPanels[3].show() else: self.notify.error('Bad number of toons: %s' % num) return None def __enterCogPanels(self, num): for cogPanel in self.cogPanels: cogPanel.hide() cogPanel.updateHealthBar() cogPanel.setPos(0, 0, 0.62) pos = self.evenPos if num % 2 == 0 else self.oddPos for i, panel in enumerate(self.cogPanels): if num > i: panel.setX(pos[i if num >= 3 else i + 1]) panel.show() def updateChosenAttacks(self, battleIndices, tracks, levels, targets): self.notify.debug('updateChosenAttacks bi=%s tracks=%s levels=%s targets=%s' % (battleIndices, tracks, levels, targets)) for i in xrange(4): if battleIndices[i] == -1: pass else: if tracks[i] == BattleBase.NO_ATTACK: numTargets = 0 target = -2 elif tracks[i] == BattleBase.PASS_ATTACK: numTargets = 0 target = -2 elif tracks[i] == BattleBase.NPCSOS: numTargets = 0 target = targets[i] elif tracks[i] == BattleBase.SOS or tracks[i] == BattleBase.PETSOS: numTargets = 0 target = -2 elif tracks[i] == HEAL_TRACK: numTargets = self.numToons if self.__isGroupHeal(levels[i]): target = -2 else: target = targets[i] else: numTargets = self.numCogs if self.__isGroupAttack(tracks[i], levels[i]): target = -1 else: target = targets[i] if target == -1: numTargets = None self.toonPanels[battleIndices[i]].setValues(battleIndices[i], tracks[i], levels[i], numTargets, target, self.localNum) def chooseDefaultTarget(self): if self.track > -1: response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = self.target messenger.send(self.battleEvent, [response]) return 1 return 0 def updateLaffMeter(self, toonNum, hp): self.toonPanels[toonNum].updateLaffMeter(hp) def enterOff(self): if self.isLoaded: for toonPanel in self.toonPanels: toonPanel.hide() for cogPanel in self.cogPanels: cogPanel.hide() self.toonAttacks = [(-1, 0, 0), (-1, 0, 0), (-1, 0, 0), (-1, 0, 0)] self.target = 0 if hasattr(self, 'timer'): self.timer.hide() return None def exitOff(self): if self.isLoaded: self.__enterPanels(self.numToons, self.localNum) if settings['cogInterface']: self.__enterCogPanels(self.numCogs) self.timer.show() self.track = -1 self.level = -1 self.target = 0 return None def enterAttack(self): self.attackPanel.enter() self.accept(self.attackPanelDoneEvent, self.__handleAttackPanelDone) return None def exitAttack(self): self.ignore(self.attackPanelDoneEvent) self.attackPanel.exit() return None def __handleAttackPanelDone(self, doneStatus): self.notify.debug('doneStatus: %s' % doneStatus) mode = doneStatus['mode'] if mode == 'Inventory': self.track = doneStatus['track'] self.level = doneStatus['level'] self.toonPanels[self.localNum].setValues(self.localNum, self.track, self.level) if self.track == HEAL_TRACK: if self.__isGroupHeal(self.level): response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = self.target messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') elif self.numToons == 3 or self.numToons == 4: self.fsm.request('ChooseToon') elif self.numToons == 2: response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level if self.localNum == 0: response['target'] = 1 elif self.localNum == 1: response['target'] = 0 else: self.notify.error('Bad localNum value: %s' % self.localNum) messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') else: self.notify.error('Heal was chosen when number of toons is %s' % self.numToons) elif self.__isCogChoiceNecessary(): self.notify.debug('choice needed') self.fsm.request('ChooseCog') response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = -1 messenger.send(self.battleEvent, [response]) else: self.notify.debug('no choice needed') self.fsm.request('AttackWait') response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = 0 messenger.send(self.battleEvent, [response]) elif mode == 'Run': self.fsm.request('Run') elif mode == 'SOS': self.fsm.request('SOS') elif mode == 'Fire': self.fsm.request('Fire') elif mode == 'Pass': response = {} response['mode'] = 'Pass' response['id'] = -1 messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') else: self.notify.warning('unknown mode: %s' % mode) def checkHealTrapLure(self): self.notify.debug('numToons: %s, numCogs: %s, lured: %s, trapped: %s' % (self.numToons, self.numCogs, self.luredIndices, self.trappedIndices)) if len(PythonUtil.union(self.trappedIndices, self.luredIndices)) == self.numCogs: canTrap = 0 else: canTrap = 1 if len(self.luredIndices) == self.numCogs: canLure = 0 canTrap = 0 else: canLure = 1 if self.numToons == 1: canHeal = 0 else: canHeal = 1 return (canHeal, canTrap, canLure) def adjustCogsAndToons(self, cogs, luredIndices, trappedIndices, toons): numCogs = len(cogs) self.notify.debug('adjustCogsAndToons() numCogs: %s self.numCogs: %s' % (numCogs, self.numCogs)) self.notify.debug('adjustCogsAndToons() luredIndices: %s self.luredIndices: %s' % (luredIndices, self.luredIndices)) self.notify.debug('adjustCogsAndToons() trappedIndices: %s self.trappedIndices: %s' % (trappedIndices, self.trappedIndices)) toonIds = map(lambda toon: toon.doId, toons) self.notify.debug('adjustCogsAndToons() toonIds: %s self.toons: %s' % (toonIds, self.toons)) maxSuitLevel = 0 cogFireCostIndex = 0 for cog in cogs: maxSuitLevel = max(maxSuitLevel, cog.getActualLevel()) self.cogFireCosts[cogFireCostIndex] = 1 cogFireCostIndex += 1 creditLevel = maxSuitLevel resetActivateMode = 0 if numCogs == self.numCogs and creditLevel == self.creditLevel and luredIndices == self.luredIndices and trappedIndices == self.trappedIndices and toonIds == self.toons: for i in xrange(len(cogs)): if cogs[i].getHP() == self.cogPanels[i].getDisplayedCurrHp(): if cogs[i].getMaxHP() == self.cogPanels[i].getDisplayedMaxHp(): if cogs[i] == self.cogPanels[i].getSuit(): continue else: resetActivateMode = 1 break else: resetActivateMode = 1 self.notify.debug('adjustCogsAndToons() resetActivateMode: %s' % resetActivateMode) self.numCogs = numCogs self.creditLevel = creditLevel self.luredIndices = luredIndices self.trappedIndices = trappedIndices self.toons = toonIds self.numToons = len(toons) self.localNum = toons.index(base.localAvatar) currStateName = self.fsm.getCurrentState().getName() if resetActivateMode: self.__enterPanels(self.numToons, self.localNum) for i in xrange(len(toons)): self.toonPanels[i].setLaffMeter(toons[i]) if settings['cogInterface']: self.__enterCogPanels(self.numCogs) for i in xrange(len(cogs)): self.cogPanels[i].setSuit(cogs[i]) if currStateName == 'ChooseCog': self.chooseCogPanel.adjustCogs(self.numCogs, self.luredIndices, self.trappedIndices, self.track) elif currStateName == 'ChooseToon': self.chooseToonPanel.adjustToons(self.numToons, self.localNum) canHeal, canTrap, canLure = self.checkHealTrapLure() base.localAvatar.inventory.setBattleCreditMultiplier(self.creditMultiplier) base.localAvatar.inventory.setActivateMode('battle', heal=canHeal, trap=canTrap, lure=canLure, bldg=self.bldg, creditLevel=self.creditLevel, tutorialFlag=self.tutorialFlag) def enterChooseCog(self): self.cog = 0 self.chooseCogPanel.enter(self.numCogs, luredIndices=self.luredIndices, trappedIndices=self.trappedIndices, track=self.track) self.accept(self.chooseCogPanelDoneEvent, self.__handleChooseCogPanelDone) return None def exitChooseCog(self): self.ignore(self.chooseCogPanelDoneEvent) self.chooseCogPanel.exit() return None def __handleChooseCogPanelDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'Back': self.fsm.request('Attack') elif mode == 'Avatar': self.cog = doneStatus['avatar'] self.target = self.cog self.fsm.request('AttackWait') response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = self.cog messenger.send(self.battleEvent, [response]) else: self.notify.warning('unknown mode: %s' % mode) def enterAttackWait(self, chosenToon = -1): self.accept(self.waitPanelDoneEvent, self.__handleAttackWaitBack) self.waitPanel.enter(self.numToons) def exitAttackWait(self): self.waitPanel.exit() self.ignore(self.waitPanelDoneEvent) def __handleAttackWaitBack(self, doneStatus): mode = doneStatus['mode'] if mode == 'Back': if self.track == HEAL_TRACK: self.fsm.request('Attack') elif self.track == BattleBase.NO_ATTACK: self.fsm.request('Attack') elif self.__isCogChoiceNecessary(): self.fsm.request('ChooseCog') else: self.fsm.request('Attack') response = {} response['mode'] = 'UnAttack' messenger.send(self.battleEvent, [response]) else: self.notify.error('unknown mode: %s' % mode) def enterChooseToon(self): self.toon = 0 self.chooseToonPanel.enter(self.numToons, localNum=self.localNum) self.accept(self.chooseToonPanelDoneEvent, self.__handleChooseToonPanelDone) return None def exitChooseToon(self): self.ignore(self.chooseToonPanelDoneEvent) self.chooseToonPanel.exit() return None def __handleChooseToonPanelDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'Back': self.fsm.request('Attack') elif mode == 'Avatar': self.toon = doneStatus['avatar'] self.target = self.toon self.fsm.request('AttackWait', [self.toon]) response = {} response['mode'] = 'Attack' response['track'] = self.track response['level'] = self.level response['target'] = self.toon messenger.send(self.battleEvent, [response]) else: self.notify.warning('unknown mode: %s' % mode) def enterRun(self): self.runPanel.show() def exitRun(self): self.runPanel.hide() def __handleRunPanelDone(self, doneStatus): if doneStatus == DGG.DIALOG_OK: response = {} response['mode'] = 'Run' messenger.send(self.battleEvent, [response]) else: self.fsm.request('Attack') def enterFire(self): canHeal, canTrap, canLure = self.checkHealTrapLure() self.FireCogPanel.enter(self.numCogs, luredIndices=self.luredIndices, trappedIndices=self.trappedIndices, track=self.track, fireCosts=self.cogFireCosts) self.accept(self.fireCogPanelDoneEvent, self.__handleCogFireDone) return None def exitFire(self): self.ignore(self.fireCogPanelDoneEvent) self.FireCogPanel.exit() return None def __handleCogFireDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'Back': self.fsm.request('Attack') elif mode == 'Avatar': self.cog = doneStatus['avatar'] self.target = self.cog self.fsm.request('AttackWait') response = {} response['mode'] = 'Fire' response['target'] = self.cog messenger.send(self.battleEvent, [response]) else: self.notify.warning('unknown mode: %s' % mode) def enterSOS(self): canHeal, canTrap, canLure = self.checkHealTrapLure() self.SOSPanel.enter(canLure, canTrap) self.accept(self.SOSPanelDoneEvent, self.__handleSOSPanelDone) return None def exitSOS(self): self.ignore(self.SOSPanelDoneEvent) self.SOSPanel.exit() return None def __handleSOSPanelDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'Friend': doId = doneStatus['friend'] response = {} response['mode'] = 'SOS' response['id'] = doId messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') elif mode == 'Pet': self.petId = doneStatus['petId'] self.petName = doneStatus['petName'] self.fsm.request('SOSPetSearch') elif mode == 'NPCFriend': doId = doneStatus['friend'] response = {} response['mode'] = 'NPCSOS' response['id'] = doId messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') elif mode == 'Back': self.fsm.request('Attack') def enterSOSPetSearch(self): response = {} response['mode'] = 'PETSOSINFO' response['id'] = self.petId self.SOSPetSearchPanel.enter(self.petId, self.petName) self.proxyGenerateMessage = 'petProxy-%d-generated' % self.petId self.accept(self.proxyGenerateMessage, self.__handleProxyGenerated) self.accept(self.SOSPetSearchPanelDoneEvent, self.__handleSOSPetSearchPanelDone) messenger.send(self.battleEvent, [response]) return None def exitSOSPetSearch(self): self.ignore(self.proxyGenerateMessage) self.ignore(self.SOSPetSearchPanelDoneEvent) self.SOSPetSearchPanel.exit() return None def __handleSOSPetSearchPanelDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'Back': self.fsm.request('SOS') else: self.notify.error('invalid mode in handleSOSPetSearchPanelDone') def __handleProxyGenerated(self): self.fsm.request('SOSPetInfo') def enterSOSPetInfo(self): self.SOSPetInfoPanel.enter(self.petId) self.accept(self.SOSPetInfoPanelDoneEvent, self.__handleSOSPetInfoPanelDone) return None def exitSOSPetInfo(self): self.ignore(self.SOSPetInfoPanelDoneEvent) self.SOSPetInfoPanel.exit() return None def __handleSOSPetInfoPanelDone(self, doneStatus): mode = doneStatus['mode'] if mode == 'OK': response = {} response['mode'] = 'PETSOS' response['id'] = self.petId response['trickId'] = doneStatus['trickId'] messenger.send(self.battleEvent, [response]) self.fsm.request('AttackWait') bboard.post(PetConstants.OurPetsMoodChangedKey, True) elif mode == 'Back': self.fsm.request('SOS') def __isCogChoiceNecessary(self): if self.numCogs > 1 and not self.__isGroupAttack(self.track, self.level): return 1 else: return 0 def __isGroupAttack(self, trackNum, levelNum): retval = BattleBase.attackAffectsGroup(trackNum, levelNum) return retval def __isGroupHeal(self, levelNum): retval = BattleBase.attackAffectsGroup(HEAL_TRACK, levelNum) return retval