oldschool-toontown/toontown/town/Street.py

395 lines
16 KiB
Python

from panda3d.core import *
from panda3d.otp import *
from toontown.battle.BattleProps import *
from toontown.battle.BattleSounds import *
from toontown.distributed.ToontownMsgTypes import *
from direct.gui.DirectGui import cleanupDialog
from direct.directnotify import DirectNotifyGlobal
from toontown.battle import BattlePlace
from direct.fsm import ClassicFSM, State
from direct.task import Task
from otp.distributed.TelemetryLimiter import RotationLimitToH, TLGatherAllAvs
from toontown.building import Elevator
from toontown.hood import ZoneUtil
from toontown.toonbase import ToontownGlobals
from toontown.toon.Toon import teleportDebug
from direct.interval.IntervalGlobal import *
visualizeZones = ConfigVariableBool('visualize-zones', 0).value
class Street(BattlePlace.BattlePlace):
notify = DirectNotifyGlobal.directNotify.newCategory('Street')
def __init__(self, loader, parentFSM, doneEvent):
BattlePlace.BattlePlace.__init__(self, loader, doneEvent)
self.fsm = ClassicFSM.ClassicFSM('Street', [State.State('start', self.enterStart, self.exitStart, ['walk',
'tunnelIn',
'doorIn',
'teleportIn',
'elevatorIn']),
State.State('walk', self.enterWalk, self.exitWalk, ['push',
'sit',
'stickerBook',
'WaitForBattle',
'battle',
'DFA',
'trialerFA',
'doorOut',
'elevator',
'tunnelIn',
'tunnelOut',
'teleportOut',
'quest',
'stopped',
'fishing',
'purchase',
'died']),
State.State('sit', self.enterSit, self.exitSit, ['walk']),
State.State('push', self.enterPush, self.exitPush, ['walk']),
State.State('stickerBook', self.enterStickerBook, self.exitStickerBook, ['walk',
'push',
'sit',
'battle',
'DFA',
'trialerFA',
'doorOut',
'elevator',
'tunnelIn',
'tunnelOut',
'WaitForBattle',
'teleportOut',
'quest',
'stopped',
'fishing',
'purchase']),
State.State('WaitForBattle', self.enterWaitForBattle, self.exitWaitForBattle, ['battle', 'walk']),
State.State('battle', self.enterBattle, self.exitBattle, ['walk', 'teleportOut', 'died']),
State.State('doorIn', self.enterDoorIn, self.exitDoorIn, ['walk']),
State.State('doorOut', self.enterDoorOut, self.exitDoorOut, ['walk', 'stopped']),
State.State('elevatorIn', self.enterElevatorIn, self.exitElevatorIn, ['walk']),
State.State('elevator', self.enterElevator, self.exitElevator, ['walk']),
State.State('trialerFA', self.enterTrialerFA, self.exitTrialerFA, ['trialerFAReject', 'DFA']),
State.State('trialerFAReject', self.enterTrialerFAReject, self.exitTrialerFAReject, ['walk']),
State.State('DFA', self.enterDFA, self.exitDFA, ['DFAReject', 'teleportOut', 'tunnelOut']),
State.State('DFAReject', self.enterDFAReject, self.exitDFAReject, ['walk']),
State.State('teleportIn', self.enterTeleportIn, self.exitTeleportIn, ['walk',
'teleportOut',
'quietZone',
'WaitForBattle',
'battle']),
State.State('teleportOut', self.enterTeleportOut, self.exitTeleportOut, ['teleportIn', 'quietZone', 'WaitForBattle']),
State.State('died', self.enterDied, self.exitDied, ['quietZone']),
State.State('tunnelIn', self.enterTunnelIn, self.exitTunnelIn, ['walk']),
State.State('tunnelOut', self.enterTunnelOut, self.exitTunnelOut, ['final']),
State.State('quietZone', self.enterQuietZone, self.exitQuietZone, ['teleportIn']),
State.State('quest', self.enterQuest, self.exitQuest, ['walk', 'stopped']),
State.State('stopped', self.enterStopped, self.exitStopped, ['walk']),
State.State('stopped', self.enterStopped, self.exitStopped, ['walk']),
State.State('fishing', self.enterFishing, self.exitFishing, ['walk']),
State.State('purchase', self.enterPurchase, self.exitPurchase, ['walk']),
State.State('final', self.enterFinal, self.exitFinal, ['start'])], 'start', 'final')
self.parentFSM = parentFSM
self.tunnelOriginList = []
self.elevatorDoneEvent = 'elevatorDone'
self.halloweenLights = []
def enter(self, requestStatus, visibilityFlag = 1, arrowsOn = 1):
teleportDebug(requestStatus, 'Street.enter(%s)' % (requestStatus,))
self._ttfToken = None
self.fsm.enterInitialState()
base.playMusic(self.loader.music, looping=1, volume=0.8)
self.loader.geom.reparentTo(render)
if visibilityFlag:
self.visibilityOn()
base.localAvatar.setGeom(self.loader.geom)
base.localAvatar.setOnLevelGround(1)
self._telemLimiter = TLGatherAllAvs('Street', RotationLimitToH)
NametagGlobals.setMasterArrowsOn(arrowsOn)
def __lightDecorationOn__():
geom = base.cr.playGame.getPlace().loader.geom
self.halloweenLights = geom.findAllMatches('**/*light*')
self.halloweenLights += geom.findAllMatches('**/*lamp*')
self.halloweenLights += geom.findAllMatches('**/prop_snow_tree*')
for light in self.halloweenLights:
light.setColorScaleOff(1)
newsManager = base.cr.newsManager
if newsManager:
holidayIds = base.cr.newsManager.getDecorationHolidayId()
if (ToontownGlobals.HALLOWEEN_COSTUMES in holidayIds or ToontownGlobals.SPOOKY_COSTUMES in holidayIds) and self.loader.hood.spookySkyFile:
lightsOff = Sequence(LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 0.1, Vec4(0.55, 0.55, 0.65, 1)), Func(self.loader.hood.startSpookySky))
lightsOff.start()
else:
self.loader.hood.startSky()
lightsOn = LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 0.1, Vec4(1, 1, 1, 1))
lightsOn.start()
else:
self.loader.hood.startSky()
lightsOn = LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 0.1, Vec4(1, 1, 1, 1))
lightsOn.start()
self.accept('doorDoneEvent', self.handleDoorDoneEvent)
self.accept('DistributedDoor_doorTrigger', self.handleDoorTrigger)
self.enterZone(requestStatus['zoneId'])
self.tunnelOriginList = base.cr.hoodMgr.addLinkTunnelHooks(self, self.loader.nodeList, self.zoneId)
self.fsm.request(requestStatus['how'], [requestStatus])
if base.cr.wantStreetSign:
self.replaceStreetSignTextures()
return
def exit(self, visibilityFlag = 1):
if visibilityFlag:
self.visibilityOff()
self.loader.geom.reparentTo(hidden)
self._telemLimiter.destroy()
del self._telemLimiter
def __lightDecorationOff__():
for light in self.halloweenLights:
light.reparentTo(hidden)
newsManager = base.cr.newsManager
NametagGlobals.setMasterArrowsOn(0)
self.loader.hood.stopSky()
self.loader.music.stop()
base.localAvatar.setGeom(render)
base.localAvatar.setOnLevelGround(0)
def load(self):
BattlePlace.BattlePlace.load(self)
self.parentFSM.getStateNamed('street').addChild(self.fsm)
def unload(self):
self.parentFSM.getStateNamed('street').removeChild(self.fsm)
del self.parentFSM
del self.fsm
self.enterZone(None)
cleanupDialog('globalDialog')
self.ignoreAll()
BattlePlace.BattlePlace.unload(self)
return
def enterElevatorIn(self, requestStatus):
self._eiwbTask = taskMgr.add(Functor(self._elevInWaitBldgTask, requestStatus['bldgDoId']), uniqueName('elevInWaitBldg'))
def _elevInWaitBldgTask(self, bldgDoId, task):
bldg = base.cr.doId2do.get(bldgDoId)
if bldg:
if bldg.elevatorNodePath is not None:
self._enterElevatorGotElevator()
return Task.done
return Task.cont
def _enterElevatorGotElevator(self):
messenger.send('insideVictorElevator')
def exitElevatorIn(self):
taskMgr.remove(self._eiwbTask)
def enterElevator(self, distElevator):
base.localAvatar.cantLeaveGame = 1
self.accept(self.elevatorDoneEvent, self.handleElevatorDone)
self.elevator = Elevator.Elevator(self.fsm.getStateNamed('elevator'), self.elevatorDoneEvent, distElevator)
self.elevator.load()
self.elevator.enter()
def exitElevator(self):
base.localAvatar.cantLeaveGame = 0
self.ignore(self.elevatorDoneEvent)
self.elevator.unload()
self.elevator.exit()
del self.elevator
def detectedElevatorCollision(self, distElevator):
self.fsm.request('elevator', [distElevator])
return None
def handleElevatorDone(self, doneStatus):
self.notify.debug('handling elevator done event')
where = doneStatus['where']
if where == 'reject':
if hasattr(base.localAvatar, 'elevatorNotifier') and base.localAvatar.elevatorNotifier.isNotifierOpen():
pass
else:
self.fsm.request('walk')
elif where == 'exit':
self.fsm.request('walk')
elif where in ('suitInterior', 'cogdoInterior'):
self.doneStatus = doneStatus
messenger.send(self.doneEvent)
else:
self.notify.error('Unknown mode: ' + where + ' in handleElevatorDone')
def enterTunnelIn(self, requestStatus):
self.enterZone(requestStatus['zoneId'])
BattlePlace.BattlePlace.enterTunnelIn(self, requestStatus)
def enterTeleportIn(self, requestStatus):
teleportDebug(requestStatus, 'Street.enterTeleportIn(%s)' % (requestStatus,))
zoneId = requestStatus['zoneId']
self._ttfToken = self.addSetZoneCompleteCallback(Functor(self._teleportToFriend, requestStatus))
self.enterZone(zoneId)
BattlePlace.BattlePlace.enterTeleportIn(self, requestStatus)
def _teleportToFriend(self, requestStatus):
avId = requestStatus['avId']
hoodId = requestStatus['hoodId']
zoneId = requestStatus['zoneId']
if avId != -1:
if avId not in base.cr.doId2do:
teleportDebug(requestStatus, "couldn't find friend %s" % avId)
handle = base.cr.identifyFriend(avId)
requestStatus = {'how': 'teleportIn',
'hoodId': hoodId,
'zoneId': hoodId,
'shardId': None,
'loader': 'safeZoneLoader',
'where': 'playground',
'avId': avId}
self.fsm.request('final')
self.__teleportOutDone(requestStatus)
return
def exitTeleportIn(self):
self.removeSetZoneCompleteCallback(self._ttfToken)
self._ttfToken = None
BattlePlace.BattlePlace.exitTeleportIn(self)
return
def enterTeleportOut(self, requestStatus):
if 'battle' in requestStatus:
self.__teleportOutDone(requestStatus)
else:
BattlePlace.BattlePlace.enterTeleportOut(self, requestStatus, self.__teleportOutDone)
def __teleportOutDone(self, requestStatus):
hoodId = requestStatus['hoodId']
zoneId = requestStatus['zoneId']
shardId = requestStatus['shardId']
if hoodId == self.loader.hood.id and shardId == None:
if zoneId == self.zoneId:
self.fsm.request('teleportIn', [requestStatus])
elif requestStatus['where'] == 'street' and ZoneUtil.getBranchZone(zoneId) == self.loader.branchZone:
self.fsm.request('quietZone', [requestStatus])
else:
self.doneStatus = requestStatus
messenger.send(self.doneEvent)
elif hoodId == ToontownGlobals.MyEstate:
self.getEstateZoneAndGoHome(requestStatus)
else:
self.doneStatus = requestStatus
messenger.send(self.doneEvent)
return
def exitTeleportOut(self):
BattlePlace.BattlePlace.exitTeleportOut(self)
def goHomeFailed(self, task):
self.notifyUserGoHomeFailed()
self.ignore('setLocalEstateZone')
self.doneStatus['avId'] = -1
self.doneStatus['zoneId'] = self.getZoneId()
self.fsm.request('teleportIn', [self.doneStatus])
return Task.done
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 hideAllVisibles(self):
for i in self.loader.nodeList:
i.stash()
def showAllVisibles(self):
for i in self.loader.nodeList:
i.unstash()
def visibilityOn(self):
self.hideAllVisibles()
self.accept('on-floor', self.enterZone)
def visibilityOff(self):
self.ignore('on-floor')
self.showAllVisibles()
def doEnterZone(self, newZoneId):
if self.zoneId != None:
for i in self.loader.nodeDict[self.zoneId]:
if newZoneId:
if i not in self.loader.nodeDict[newZoneId]:
self.loader.fadeOutDict[i].start()
self.loader.exitAnimatedProps(i)
else:
i.stash()
self.loader.exitAnimatedProps(i)
if newZoneId != None:
for i in self.loader.nodeDict[newZoneId]:
if self.zoneId:
if i not in self.loader.nodeDict[self.zoneId]:
self.loader.fadeInDict[i].start()
self.loader.enterAnimatedProps(i)
else:
if self.loader.fadeOutDict[i].isPlaying():
self.loader.fadeOutDict[i].finish()
if self.loader.fadeInDict[i].isPlaying():
self.loader.fadeInDict[i].finish()
self.loader.enterAnimatedProps(i)
i.unstash()
if newZoneId != self.zoneId:
if visualizeZones:
if self.zoneId != None:
self.loader.zoneDict[self.zoneId].clearColor()
if newZoneId != None:
self.loader.zoneDict[newZoneId].setColor(0, 0, 1, 1, 100)
if newZoneId != None:
if not __astron__:
base.cr.sendSetZoneMsg(newZoneId)
else:
visZones = [ZoneUtil.getBranchZone(newZoneId)]
visZones += [self.loader.node2zone[x] for x in self.loader.nodeDict[newZoneId]]
if newZoneId not in visZones:
visZones.append(newZoneId)
base.cr.sendSetZoneMsg(newZoneId, visZones)
self.notify.debug('Entering Zone %d' % newZoneId)
self.zoneId = newZoneId
geom = base.cr.playGame.getPlace().loader.geom
self.halloweenLights = geom.findAllMatches('**/*light*')
self.halloweenLights += geom.findAllMatches('**/*lamp*')
self.halloweenLights += geom.findAllMatches('**/prop_snow_tree*')
for light in self.halloweenLights:
light.setColorScaleOff(1)
return
def replaceStreetSignTextures(self):
if not hasattr(base.cr, 'playGame'):
return
place = base.cr.playGame.getPlace()
if place is None:
return
geom = base.cr.playGame.getPlace().loader.geom
signs = geom.findAllMatches('**/*tunnelAheadSign*;+s')
if signs.getNumPaths() > 0:
streetSign = base.cr.streetSign
signTexturePath = streetSign.StreetSignBaseDir + '/' + streetSign.StreetSignFileName
loaderTexturePath = Filename(str(signTexturePath))
inDreamland = False
if place.zoneId and ZoneUtil.getCanonicalHoodId(place.zoneId) == ToontownGlobals.DonaldsDreamland:
inDreamland = True
if Filename(signTexturePath).exists():
signTexture = loader.loadTexture(loaderTexturePath)
for sign in signs:
if Filename(signTexturePath).exists():
sign.setTexture(signTexture, 1)
if inDreamland:
sign.setColorScale(0.525, 0.525, 0.525, 1)
return