toontown-just-works/toontown/town/TownBattle.py
2024-07-07 18:08:39 -05:00

683 lines
26 KiB
Python

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 direct.showbase import PythonUtil
from toontown.toonbase import TTLocalizer, ToontownGlobals, ToontownTimer
from toontown.pets import PetConstants
from direct.gui.DirectGui import *
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)] * 4
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.rolloverFrame = DirectFrame(aspect2d, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=(0.6, 1.0, 0.4, 1), geom_scale=(0.5, 0.3, 0.2), text_scale=0.05, text_pos=(0, 0.0125), text='', text_fg=(0, 0, 0, 1), pos=(0.4, 0, 0))
self.rolloverFrame.setBin('gui-popup', 0)
self.rolloverFrame.hide()
self.suitGui = loader.loadModel('phase_3.5/models/gui/suit_detail_panel')
self.suitGui.find('**/avatar_panel/shadow').setColor(1, 1, 1, 0.5)
self.toonPanels = [TownBattleToonPanel.TownBattleToonPanel(self) for i in xrange(4)]
self.cogPanels = [TownBattleCogPanel.TownBattleCogPanel(self) for i in xrange(4)]
self.timer = ToontownTimer.ToontownTimer()
self.timer.posInTopRightCorner()
self.timer.setScale(0.4)
self.timer.hide()
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
del self.rolloverFrame
for panel in self.toonPanels + self.cogPanels:
panel.cleanup()
del self.toonPanels
del self.cogPanels
self.timer.destroy()
self.suitGui.removeNode()
del self.suitGui
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()
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
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 showRolloverFrame(self, parent, type, text, extra=None):
dict = TTLocalizer.BattleHoverAttributes[type]
for key, value in dict.iteritems():
if key == 'pos':
self.rolloverFrame.setPos(value)
elif key == 'suit':
if value:
self.rolloverFrame['text_font'] = ToontownGlobals.getSuitFont()
self.rolloverFrame['geom'] = self.suitGui.find('**/avatar_panel')
else:
self.rolloverFrame['text_font'] = ToontownGlobals.getInterfaceFont()
self.rolloverFrame['geom'] = DGG.getDefaultDialogGeom()
else:
self.rolloverFrame[key] = value
self.rolloverFrame.reparentTo(parent)
self.rolloverFrame.show()
self.rolloverFrame['text'] = text
def hideRolloverFrame(self, extra=None):
self.rolloverFrame.hide()
def isAttackDangerous(self, hp):
for panel in self.toonPanels:
if panel.hasAvatar() and panel.avatar.getHp() <= hp:
return True
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)
self.positionPanels(num, self.toonPanels)
def __enterCogPanels(self, num):
for cogPanel in self.cogPanels:
cogPanel.hide()
cogPanel.updateHealthBar()
cogPanel.updateRolloverBind()
cogPanel.setPos(0, 0, 0.62)
self.positionPanels(num, self.cogPanels)
def positionPanels(self, num, panels):
pos = self.evenPos if num % 2 == 0 else self.oddPos
for i, panel in enumerate(panels):
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 panel in self.toonPanels + self.cogPanels:
panel.hide()
self.toonAttacks = [(-1, 0, 0)] * 4
self.target = 0
if hasattr(self, 'timer'):
self.timer.hide()
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
def enterAttack(self):
self.attackPanel.enter()
self.accept(self.attackPanelDoneEvent, self.__handleAttackPanelDone)
def exitAttack(self):
self.ignore(self.attackPanelDoneEvent)
self.attackPanel.exit()
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 = [toon.doId for toon in toons]
self.notify.debug('adjustCogsAndToons() toonIds: %s self.toons: %s' % (toonIds, self.toons))
maxSuitLevel = 0
for cog in cogs:
maxSuitLevel = max(maxSuitLevel, cog.getActualLevel())
creditLevel = maxSuitLevel
resetActivateMode = numCogs != self.numCogs or creditLevel != self.creditLevel or luredIndices != self.luredIndices or trappedIndices != self.trappedIndices or toonIds != self.toons
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 settings['cogInterface']:
self.__enterCogPanels(self.numCogs)
for i in xrange(len(cogs)):
self.cogPanels[i].setSuit(cogs[i])
if resetActivateMode:
self.__enterPanels(self.numToons, self.localNum)
for i in xrange(len(toons)):
self.toonPanels[i].setLaffMeter(toons[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)
def exitChooseCog(self):
self.ignore(self.chooseCogPanelDoneEvent)
self.chooseCogPanel.exit()
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)
def exitChooseToon(self):
self.ignore(self.chooseToonPanelDoneEvent)
self.chooseToonPanel.exit()
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)
self.accept(self.fireCogPanelDoneEvent, self.__handleCogFireDone)
def exitFire(self):
self.ignore(self.fireCogPanelDoneEvent)
self.FireCogPanel.exit()
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)
def exitSOS(self):
self.ignore(self.SOSPanelDoneEvent)
self.SOSPanel.exit()
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])
def exitSOSPetSearch(self):
self.ignore(self.proxyGenerateMessage)
self.ignore(self.SOSPetSearchPanelDoneEvent)
self.SOSPetSearchPanel.exit()
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)
def exitSOSPetInfo(self):
self.ignore(self.SOSPetInfoPanelDoneEvent)
self.SOSPetInfoPanel.exit()
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):
return self.numCogs > 1 and not self.__isGroupAttack(self.track, self.level)
def __isGroupAttack(self, trackNum, levelNum):
return BattleBase.attackAffectsGroup(trackNum, levelNum)
def __isGroupHeal(self, levelNum):
return self.__isGroupAttack(HEAL_TRACK, levelNum)