2022-12-16 18:40:57 -06:00
|
|
|
from panda3d.core import *
|
2019-11-02 17:27:54 -05:00
|
|
|
from toontown.battle.BattleProps import *
|
|
|
|
from toontown.battle.BattleSounds import *
|
|
|
|
from toontown.distributed.ToontownMsgTypes import *
|
|
|
|
from toontown.toonbase.ToontownGlobals import *
|
|
|
|
from direct.gui.DirectGui import cleanupDialog
|
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
|
|
from toontown.hood import Place
|
|
|
|
from direct.showbase import DirectObject
|
|
|
|
from direct.fsm import StateData
|
|
|
|
from direct.fsm import ClassicFSM, State
|
|
|
|
from direct.fsm import State
|
|
|
|
from direct.task import Task
|
2019-12-30 00:07:56 -06:00
|
|
|
from . import TownBattle
|
2019-11-02 17:27:54 -05:00
|
|
|
from toontown.toon import Toon
|
|
|
|
from toontown.toon.Toon import teleportDebug
|
|
|
|
from toontown.battle import BattleParticles
|
|
|
|
from direct.fsm import StateData
|
|
|
|
from toontown.building import ToonInterior
|
|
|
|
from toontown.hood import QuietZoneState
|
|
|
|
from toontown.hood import ZoneUtil
|
|
|
|
from direct.interval.IntervalGlobal import *
|
|
|
|
|
|
|
|
class TownLoader(StateData.StateData):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('TownLoader')
|
|
|
|
|
|
|
|
def __init__(self, hood, parentFSMState, doneEvent):
|
|
|
|
StateData.StateData.__init__(self, doneEvent)
|
|
|
|
self.hood = hood
|
|
|
|
self.parentFSMState = parentFSMState
|
|
|
|
self.fsm = ClassicFSM.ClassicFSM('TownLoader', [State.State('start', self.enterStart, self.exitStart, ['quietZone', 'street', 'toonInterior']),
|
|
|
|
State.State('street', self.enterStreet, self.exitStreet, ['quietZone']),
|
|
|
|
State.State('toonInterior', self.enterToonInterior, self.exitToonInterior, ['quietZone']),
|
|
|
|
State.State('quietZone', self.enterQuietZone, self.exitQuietZone, ['street', 'toonInterior']),
|
|
|
|
State.State('final', self.enterFinal, self.exitFinal, ['start'])], 'start', 'final')
|
|
|
|
self.branchZone = None
|
|
|
|
self.canonicalBranchZone = None
|
|
|
|
self.placeDoneEvent = 'placeDone'
|
|
|
|
self.townBattleDoneEvent = 'town-battle-done'
|
|
|
|
return
|
|
|
|
|
|
|
|
def loadBattleAnims(self):
|
|
|
|
Toon.loadBattleAnims()
|
|
|
|
|
|
|
|
def unloadBattleAnims(self):
|
|
|
|
Toon.unloadBattleAnims()
|
|
|
|
|
|
|
|
def load(self, zoneId):
|
|
|
|
self.zoneId = zoneId
|
|
|
|
self.parentFSMState.addChild(self.fsm)
|
|
|
|
self.loadBattleAnims()
|
|
|
|
self.branchZone = ZoneUtil.getBranchZone(zoneId)
|
|
|
|
self.canonicalBranchZone = ZoneUtil.getCanonicalBranchZone(zoneId)
|
2019-11-23 16:18:49 -06:00
|
|
|
self.music = base.loader.loadMusic(self.musicFile)
|
|
|
|
self.activityMusic = base.loader.loadMusic(self.activityMusicFile)
|
2020-01-14 13:28:52 -06:00
|
|
|
self.battleMusic = base.loader.loadMusic('phase_3.5/audio/bgm/encntr_general_bg.ogg')
|
2019-11-02 17:27:54 -05:00
|
|
|
self.townBattle = TownBattle.TownBattle(self.townBattleDoneEvent)
|
|
|
|
self.townBattle.load()
|
|
|
|
|
|
|
|
def unload(self):
|
|
|
|
self.unloadBattleAnims()
|
|
|
|
globalPropPool.unloadProps()
|
|
|
|
globalBattleSoundCache.clear()
|
|
|
|
BattleParticles.unloadParticles()
|
|
|
|
self.parentFSMState.removeChild(self.fsm)
|
|
|
|
del self.parentFSMState
|
|
|
|
del self.fsm
|
|
|
|
del self.streetClass
|
|
|
|
self.landmarkBlocks.removeNode()
|
|
|
|
del self.landmarkBlocks
|
|
|
|
self.hood.dnaStore.resetSuitPoints()
|
|
|
|
self.hood.dnaStore.resetBattleCells()
|
|
|
|
del self.hood
|
|
|
|
del self.nodeDict
|
|
|
|
del self.zoneDict
|
2021-06-29 12:57:22 -05:00
|
|
|
if __astron__:
|
2019-11-27 19:14:30 -06:00
|
|
|
del self.node2zone
|
2019-11-02 17:27:54 -05:00
|
|
|
del self.fadeInDict
|
|
|
|
del self.fadeOutDict
|
|
|
|
del self.nodeList
|
|
|
|
self.geom.removeNode()
|
|
|
|
del self.geom
|
|
|
|
self.townBattle.unload()
|
|
|
|
self.townBattle.cleanup()
|
|
|
|
del self.townBattle
|
|
|
|
del self.battleMusic
|
|
|
|
del self.music
|
|
|
|
del self.activityMusic
|
|
|
|
del self.holidayPropTransforms
|
|
|
|
self.deleteAnimatedProps()
|
|
|
|
cleanupDialog('globalDialog')
|
|
|
|
ModelPool.garbageCollect()
|
|
|
|
TexturePool.garbageCollect()
|
|
|
|
|
|
|
|
def enter(self, requestStatus):
|
|
|
|
teleportDebug(requestStatus, 'TownLoader.enter(%s)' % requestStatus)
|
|
|
|
self.fsm.enterInitialState()
|
|
|
|
teleportDebug(requestStatus, 'setting state: %s' % requestStatus['where'])
|
|
|
|
self.setState(requestStatus['where'], requestStatus)
|
|
|
|
|
|
|
|
def exit(self):
|
|
|
|
self.ignoreAll()
|
|
|
|
|
|
|
|
def setState(self, stateName, requestStatus):
|
|
|
|
self.fsm.request(stateName, [requestStatus])
|
|
|
|
|
|
|
|
def enterStart(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def exitStart(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def enterStreet(self, requestStatus):
|
|
|
|
teleportDebug(requestStatus, 'enterStreet(%s)' % requestStatus)
|
|
|
|
self.acceptOnce(self.placeDoneEvent, self.streetDone)
|
|
|
|
self.place = self.streetClass(self, self.fsm, self.placeDoneEvent)
|
|
|
|
self.place.load()
|
|
|
|
base.cr.playGame.setPlace(self.place)
|
|
|
|
self.place.enter(requestStatus)
|
|
|
|
|
|
|
|
def exitStreet(self):
|
|
|
|
self.place.exit()
|
|
|
|
self.place.unload()
|
|
|
|
self.place = None
|
|
|
|
base.cr.playGame.setPlace(self.place)
|
|
|
|
return
|
|
|
|
|
|
|
|
def streetDone(self):
|
|
|
|
self.requestStatus = self.place.doneStatus
|
|
|
|
status = self.place.doneStatus
|
|
|
|
if status['loader'] == 'townLoader' and ZoneUtil.getBranchZone(status['zoneId']) == self.branchZone and status['shardId'] == None:
|
|
|
|
self.fsm.request('quietZone', [status])
|
|
|
|
else:
|
|
|
|
self.doneStatus = status
|
|
|
|
messenger.send(self.doneEvent)
|
|
|
|
return
|
|
|
|
|
|
|
|
def enterToonInterior(self, requestStatus):
|
|
|
|
self.acceptOnce(self.placeDoneEvent, self.handleToonInteriorDone)
|
|
|
|
self.place = ToonInterior.ToonInterior(self, self.fsm.getStateNamed('toonInterior'), self.placeDoneEvent)
|
|
|
|
base.cr.playGame.setPlace(self.place)
|
|
|
|
self.place.load()
|
|
|
|
self.place.enter(requestStatus)
|
|
|
|
|
|
|
|
def exitToonInterior(self):
|
|
|
|
self.ignore(self.placeDoneEvent)
|
|
|
|
self.place.exit()
|
|
|
|
self.place.unload()
|
|
|
|
self.place = None
|
|
|
|
base.cr.playGame.setPlace(self.place)
|
|
|
|
return
|
|
|
|
|
|
|
|
def handleToonInteriorDone(self):
|
|
|
|
status = self.place.doneStatus
|
|
|
|
if ZoneUtil.getBranchZone(status['zoneId']) == self.branchZone and status['shardId'] == None:
|
|
|
|
self.fsm.request('quietZone', [status])
|
|
|
|
else:
|
|
|
|
self.doneStatus = status
|
|
|
|
messenger.send(self.doneEvent)
|
|
|
|
return
|
|
|
|
|
|
|
|
def enterQuietZone(self, requestStatus):
|
|
|
|
self.quietZoneDoneEvent = uniqueName('quietZoneDone')
|
|
|
|
self.acceptOnce(self.quietZoneDoneEvent, self.handleQuietZoneDone)
|
|
|
|
self.quietZoneStateData = QuietZoneState.QuietZoneState(self.quietZoneDoneEvent)
|
|
|
|
self.quietZoneStateData.load()
|
|
|
|
self.quietZoneStateData.enter(requestStatus)
|
|
|
|
|
|
|
|
def exitQuietZone(self):
|
|
|
|
self.ignore(self.quietZoneDoneEvent)
|
|
|
|
del self.quietZoneDoneEvent
|
|
|
|
self.quietZoneStateData.exit()
|
|
|
|
self.quietZoneStateData.unload()
|
|
|
|
self.quietZoneStateData = None
|
|
|
|
return
|
|
|
|
|
|
|
|
def handleQuietZoneDone(self):
|
|
|
|
status = self.quietZoneStateData.getRequestStatus()
|
|
|
|
self.fsm.request(status['where'], [status])
|
|
|
|
|
|
|
|
def enterFinal(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def exitFinal(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def createHood(self, dnaFile, loadStorage = 1):
|
|
|
|
if loadStorage:
|
|
|
|
loader.loadDNAFile(self.hood.dnaStore, 'phase_5/dna/storage_town.dna')
|
|
|
|
self.notify.debug('done loading %s' % 'phase_5/dna/storage_town.dna')
|
|
|
|
loader.loadDNAFile(self.hood.dnaStore, self.townStorageDNAFile)
|
|
|
|
self.notify.debug('done loading %s' % self.townStorageDNAFile)
|
|
|
|
node = loader.loadDNAFile(self.hood.dnaStore, dnaFile)
|
|
|
|
self.notify.debug('done loading %s' % dnaFile)
|
|
|
|
if node.getNumParents() == 1:
|
|
|
|
self.geom = NodePath(node.getParent(0))
|
|
|
|
self.geom.reparentTo(hidden)
|
|
|
|
else:
|
|
|
|
self.geom = hidden.attachNewNode(node)
|
|
|
|
self.makeDictionaries(self.hood.dnaStore)
|
|
|
|
self.reparentLandmarkBlockNodes()
|
|
|
|
self.renameFloorPolys(self.nodeList)
|
|
|
|
self.createAnimatedProps(self.nodeList)
|
|
|
|
self.holidayPropTransforms = {}
|
|
|
|
npl = self.geom.findAllMatches('**/=DNARoot=holiday_prop')
|
|
|
|
for i in range(npl.getNumPaths()):
|
|
|
|
np = npl.getPath(i)
|
2019-12-30 00:07:56 -06:00
|
|
|
np.setTag('transformIndex', repr(i))
|
2019-11-02 17:27:54 -05:00
|
|
|
self.holidayPropTransforms[i] = np.getNetTransform()
|
|
|
|
|
|
|
|
self.notify.info('skipping self.geom.flattenMedium')
|
|
|
|
gsg = base.win.getGsg()
|
|
|
|
if gsg:
|
|
|
|
self.geom.prepareScene(gsg)
|
|
|
|
self.geom.setName('town_top_level')
|
|
|
|
|
|
|
|
def reparentLandmarkBlockNodes(self):
|
|
|
|
bucket = self.landmarkBlocks = hidden.attachNewNode('landmarkBlocks')
|
|
|
|
npc = self.geom.findAllMatches('**/sb*:*_landmark_*_DNARoot')
|
|
|
|
for i in range(npc.getNumPaths()):
|
|
|
|
nodePath = npc.getPath(i)
|
|
|
|
nodePath.wrtReparentTo(bucket)
|
|
|
|
|
|
|
|
npc = self.geom.findAllMatches('**/sb*:*animated_building*_DNARoot')
|
|
|
|
for i in range(npc.getNumPaths()):
|
|
|
|
nodePath = npc.getPath(i)
|
|
|
|
nodePath.wrtReparentTo(bucket)
|
|
|
|
|
|
|
|
def makeDictionaries(self, dnaStore):
|
|
|
|
self.nodeDict = {}
|
|
|
|
self.zoneDict = {}
|
2021-06-29 12:57:22 -05:00
|
|
|
if __astron__:
|
2019-11-27 19:14:30 -06:00
|
|
|
self.node2zone = {}
|
2019-11-02 17:27:54 -05:00
|
|
|
self.nodeList = []
|
|
|
|
self.fadeInDict = {}
|
|
|
|
self.fadeOutDict = {}
|
|
|
|
a1 = Vec4(1, 1, 1, 1)
|
|
|
|
a0 = Vec4(1, 1, 1, 0)
|
|
|
|
numVisGroups = dnaStore.getNumDNAVisGroups()
|
|
|
|
for i in range(numVisGroups):
|
|
|
|
groupFullName = dnaStore.getDNAVisGroupName(i)
|
|
|
|
groupName = base.cr.hoodMgr.extractGroupName(groupFullName)
|
|
|
|
zoneId = int(groupName)
|
|
|
|
zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
|
|
|
|
groupNode = self.geom.find('**/' + groupFullName)
|
|
|
|
if groupNode.isEmpty():
|
|
|
|
self.notify.error('Could not find visgroup')
|
|
|
|
else:
|
|
|
|
if ':' in groupName:
|
|
|
|
groupName = '%s%s' % (zoneId, groupName[groupName.index(':'):])
|
|
|
|
else:
|
|
|
|
groupName = '%s' % zoneId
|
|
|
|
groupNode.setName(groupName)
|
|
|
|
self.nodeDict[zoneId] = []
|
|
|
|
self.nodeList.append(groupNode)
|
|
|
|
self.zoneDict[zoneId] = groupNode
|
2021-06-29 12:57:22 -05:00
|
|
|
if __astron__:
|
2019-11-27 19:14:30 -06:00
|
|
|
self.node2zone[groupNode] = zoneId
|
2019-11-02 17:27:54 -05:00
|
|
|
fadeDuration = 0.5
|
|
|
|
self.fadeOutDict[groupNode] = Sequence(Func(groupNode.setTransparency, 1), LerpColorScaleInterval(groupNode, fadeDuration, a0, startColorScale=a1), Func(groupNode.clearColorScale), Func(groupNode.clearTransparency), Func(groupNode.stash), name='fadeZone-' + str(zoneId), autoPause=1)
|
|
|
|
self.fadeInDict[groupNode] = Sequence(Func(groupNode.unstash), Func(groupNode.setTransparency, 1), LerpColorScaleInterval(groupNode, fadeDuration, a1, startColorScale=a0), Func(groupNode.clearColorScale), Func(groupNode.clearTransparency), name='fadeZone-' + str(zoneId), autoPause=1)
|
|
|
|
|
|
|
|
for i in range(numVisGroups):
|
|
|
|
groupFullName = dnaStore.getDNAVisGroupName(i)
|
|
|
|
zoneId = int(base.cr.hoodMgr.extractGroupName(groupFullName))
|
|
|
|
zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
|
|
|
|
for j in range(dnaStore.getNumVisiblesInDNAVisGroup(i)):
|
|
|
|
visName = dnaStore.getVisibleName(i, j)
|
|
|
|
groupName = base.cr.hoodMgr.extractGroupName(visName)
|
|
|
|
nextZoneId = int(groupName)
|
|
|
|
nextZoneId = ZoneUtil.getTrueZoneId(nextZoneId, self.zoneId)
|
|
|
|
visNode = self.zoneDict[nextZoneId]
|
|
|
|
self.nodeDict[zoneId].append(visNode)
|
|
|
|
|
|
|
|
self.hood.dnaStore.resetPlaceNodes()
|
|
|
|
self.hood.dnaStore.resetDNAGroups()
|
|
|
|
self.hood.dnaStore.resetDNAVisGroups()
|
|
|
|
self.hood.dnaStore.resetDNAVisGroupsAI()
|
|
|
|
|
|
|
|
def renameFloorPolys(self, nodeList):
|
|
|
|
for i in nodeList:
|
|
|
|
collNodePaths = i.findAllMatches('**/+CollisionNode')
|
|
|
|
numCollNodePaths = collNodePaths.getNumPaths()
|
|
|
|
visGroupName = i.node().getName()
|
|
|
|
for j in range(numCollNodePaths):
|
|
|
|
collNodePath = collNodePaths.getPath(j)
|
|
|
|
bitMask = collNodePath.node().getIntoCollideMask()
|
|
|
|
if bitMask.getBit(1):
|
|
|
|
collNodePath.node().setName(visGroupName)
|
|
|
|
|
|
|
|
def createAnimatedProps(self, nodeList):
|
|
|
|
self.animPropDict = {}
|
|
|
|
self.zoneIdToInteractivePropDict = {}
|
|
|
|
for i in nodeList:
|
|
|
|
animPropNodes = i.findAllMatches('**/animated_prop_*')
|
|
|
|
numAnimPropNodes = animPropNodes.getNumPaths()
|
|
|
|
for j in range(numAnimPropNodes):
|
|
|
|
animPropNode = animPropNodes.getPath(j)
|
|
|
|
if animPropNode.getName().startswith('animated_prop_generic'):
|
|
|
|
className = 'GenericAnimatedProp'
|
|
|
|
elif animPropNode.getName().startswith('animated_prop_'):
|
|
|
|
name = animPropNode.getName()[len('animated_prop_'):]
|
|
|
|
splits = name.split('_')
|
|
|
|
className = splits[0]
|
|
|
|
else:
|
|
|
|
className = animPropNode.getName()[14:-8]
|
|
|
|
symbols = {}
|
|
|
|
base.cr.importModule(symbols, 'toontown.hood', [className])
|
|
|
|
classObj = getattr(symbols[className], className)
|
|
|
|
animPropObj = classObj(animPropNode)
|
|
|
|
animPropList = self.animPropDict.setdefault(i, [])
|
|
|
|
animPropList.append(animPropObj)
|
|
|
|
|
|
|
|
interactivePropNodes = i.findAllMatches('**/interactive_prop_*')
|
|
|
|
numInteractivePropNodes = interactivePropNodes.getNumPaths()
|
|
|
|
for j in range(numInteractivePropNodes):
|
|
|
|
interactivePropNode = interactivePropNodes.getPath(j)
|
|
|
|
className = 'InteractiveAnimatedProp'
|
|
|
|
if 'hydrant' in interactivePropNode.getName():
|
|
|
|
className = 'HydrantInteractiveProp'
|
|
|
|
elif 'trashcan' in interactivePropNode.getName():
|
|
|
|
className = 'TrashcanInteractiveProp'
|
|
|
|
elif 'mailbox' in interactivePropNode.getName():
|
|
|
|
className = 'MailboxInteractiveProp'
|
|
|
|
symbols = {}
|
|
|
|
base.cr.importModule(symbols, 'toontown.hood', [className])
|
|
|
|
classObj = getattr(symbols[className], className)
|
|
|
|
interactivePropObj = classObj(interactivePropNode)
|
|
|
|
animPropList = self.animPropDict.get(i)
|
|
|
|
if animPropList is None:
|
|
|
|
animPropList = self.animPropDict.setdefault(i, [])
|
|
|
|
animPropList.append(interactivePropObj)
|
|
|
|
if interactivePropObj.getCellIndex() == 0:
|
|
|
|
zoneId = int(i.getName())
|
|
|
|
if zoneId not in self.zoneIdToInteractivePropDict:
|
|
|
|
self.zoneIdToInteractivePropDict[zoneId] = interactivePropObj
|
|
|
|
else:
|
|
|
|
self.notify.error('already have interactive prop %s in zone %s' % (self.zoneIdToInteractivePropDict, zoneId))
|
|
|
|
|
|
|
|
animatedBuildingNodes = i.findAllMatches('**/*:animated_building_*;-h')
|
|
|
|
for np in animatedBuildingNodes:
|
|
|
|
if np.getName().startswith('sb'):
|
|
|
|
animatedBuildingNodes.removePath(np)
|
|
|
|
|
|
|
|
numAnimatedBuildingNodes = animatedBuildingNodes.getNumPaths()
|
|
|
|
for j in range(numAnimatedBuildingNodes):
|
|
|
|
animatedBuildingNode = animatedBuildingNodes.getPath(j)
|
|
|
|
className = 'GenericAnimatedBuilding'
|
|
|
|
symbols = {}
|
|
|
|
base.cr.importModule(symbols, 'toontown.hood', [className])
|
|
|
|
classObj = getattr(symbols[className], className)
|
|
|
|
animatedBuildingObj = classObj(animatedBuildingNode)
|
|
|
|
animPropList = self.animPropDict.get(i)
|
|
|
|
if animPropList is None:
|
|
|
|
animPropList = self.animPropDict.setdefault(i, [])
|
|
|
|
animPropList.append(animatedBuildingObj)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
def deleteAnimatedProps(self):
|
2019-12-30 00:07:56 -06:00
|
|
|
for zoneNode, animPropList in list(self.animPropDict.items()):
|
2019-11-02 17:27:54 -05:00
|
|
|
for animProp in animPropList:
|
|
|
|
animProp.delete()
|
|
|
|
|
|
|
|
del self.animPropDict
|
|
|
|
|
|
|
|
def enterAnimatedProps(self, zoneNode):
|
|
|
|
for animProp in self.animPropDict.get(zoneNode, ()):
|
|
|
|
animProp.enter()
|
|
|
|
|
|
|
|
def exitAnimatedProps(self, zoneNode):
|
|
|
|
for animProp in self.animPropDict.get(zoneNode, ()):
|
|
|
|
animProp.exit()
|
|
|
|
|
|
|
|
def getInteractiveProp(self, zoneId):
|
|
|
|
result = None
|
|
|
|
if zoneId in self.zoneIdToInteractivePropDict:
|
|
|
|
result = self.zoneIdToInteractivePropDict[zoneId]
|
|
|
|
return result
|