historical/toontown-classic.git/toontown/toonbase/ToonBase.py
2024-01-16 11:20:27 -06:00

449 lines
21 KiB
Python

from otp.otpbase import OTPBase
from otp.otpbase import OTPLauncherGlobals
from otp.otpbase import OTPGlobals
from direct.showbase.PythonUtil import *
import ToontownGlobals
from direct.directnotify import DirectNotifyGlobal
import ToontownLoader
from direct.gui import DirectGuiGlobals
from direct.gui.DirectGui import *
from panda3d.core import *
from libotp import *
import sys
import os
import math
from toontown.toonbase import ToontownAccess
from toontown.toonbase import TTLocalizer
from toontown.toonbase import ToontownBattleGlobals
from toontown.toonbase import ToontownSettings
from toontown.launcher import ToontownDownloadWatcher
import tempfile
import atexit
import shutil
class ToonBase(OTPBase.OTPBase):
notify = DirectNotifyGlobal.directNotify.newCategory('ToonBase')
def __init__(self):
if not config.GetInt('ignore-user-options', 0):
self.settings = ToontownSettings.ToontownSettings()
self.loadFromSettings()
else:
self.settings = None
OTPBase.OTPBase.__init__(self)
if not self.isMainWindowOpen():
try:
launcher.setPandaErrorCode(7)
except:
pass
sys.exit(1)
self.disableShowbaseMouse()
self.addCullBins()
base.debugRunningMultiplier /= OTPGlobals.ToonSpeedFactor
self.toonChatSounds = self.config.GetBool('toon-chat-sounds', 1)
self.placeBeforeObjects = config.GetBool('place-before-objects', 1)
self.endlessQuietZone = False
self.wantDynamicShadows = 0
self.exitErrorCode = 0
camera.setPosHpr(0, 0, 0, 0, 0, 0)
self.camLens.setMinFov(ToontownGlobals.DefaultCameraFov / (4. / 3.))
self.camLens.setNearFar(ToontownGlobals.DefaultCameraNear, ToontownGlobals.DefaultCameraFar)
self.musicManager.setVolume(0.65)
self.setBackgroundColor(ToontownGlobals.DefaultBackgroundColor)
tpm = TextPropertiesManager.getGlobalPtr()
candidateActive = TextProperties()
candidateActive.setTextColor(0, 0, 1, 1)
tpm.setProperties('candidate_active', candidateActive)
candidateInactive = TextProperties()
candidateInactive.setTextColor(0.3, 0.3, 0.7, 1)
tpm.setProperties('candidate_inactive', candidateInactive)
self.transitions.IrisModelName = 'phase_3/models/misc/iris'
self.transitions.FadeModelName = 'phase_3/models/misc/fade'
self.exitFunc = self.userExit
if 'launcher' in __builtins__ and launcher:
launcher.setPandaErrorCode(11)
globalClock.setMaxDt(0.2)
if self.config.GetBool('want-particles', 1) == 1:
self.notify.debug('Enabling particles')
self.enableParticles()
self.accept(ToontownGlobals.ScreenshotHotkey, self.takeScreenShot)
self.accept('panda3d-render-error', self.panda3dRenderError)
oldLoader = self.loader
self.loader = ToontownLoader.ToontownLoader(self)
__builtins__['loader'] = self.loader
oldLoader.destroy()
self.accept('PandaPaused', self.disableAllAudio)
self.accept('PandaRestarted', self.enableAllAudio)
self.friendMode = self.config.GetBool('switchboard-friends', 0)
self.wantPets = self.config.GetBool('want-pets', 1)
self.wantBingo = self.config.GetBool('want-fish-bingo', 1)
self.wantKarts = self.config.GetBool('want-karts', 1)
self.wantNewSpecies = self.config.GetBool('want-new-species', 0)
self.inactivityTimeout = self.config.GetFloat('inactivity-timeout', ToontownGlobals.KeyboardTimeout)
if self.inactivityTimeout:
self.notify.debug('Enabling Panda timeout: %s' % self.inactivityTimeout)
self.mouseWatcherNode.setInactivityTimeout(self.inactivityTimeout)
self.randomMinigameAbort = self.config.GetBool('random-minigame-abort', 0)
self.randomMinigameDisconnect = self.config.GetBool('random-minigame-disconnect', 0)
self.randomMinigameNetworkPlugPull = self.config.GetBool('random-minigame-netplugpull', 0)
self.autoPlayAgain = self.config.GetBool('auto-play-again', 0)
self.skipMinigameReward = self.config.GetBool('skip-minigame-reward', 0)
self.wantMinigameDifficulty = self.config.GetBool('want-minigame-difficulty', 0)
self.minigameDifficulty = self.config.GetFloat('minigame-difficulty', -1.0)
if self.minigameDifficulty == -1.0:
del self.minigameDifficulty
self.minigameSafezoneId = self.config.GetInt('minigame-safezone-id', -1)
if self.minigameSafezoneId == -1:
del self.minigameSafezoneId
cogdoGameSafezoneId = self.config.GetInt('cogdo-game-safezone-id', -1)
cogdoGameDifficulty = self.config.GetFloat('cogdo-game-difficulty', -1)
if cogdoGameDifficulty != -1:
self.cogdoGameDifficulty = cogdoGameDifficulty
if cogdoGameSafezoneId != -1:
self.cogdoGameSafezoneId = cogdoGameSafezoneId
ToontownBattleGlobals.SkipMovie = self.config.GetBool('skip-battle-movies', 0)
self.creditCardUpFront = self.config.GetInt('credit-card-up-front', -1)
if self.creditCardUpFront == -1:
del self.creditCardUpFront
else:
self.creditCardUpFront = self.creditCardUpFront != 0
self.housingEnabled = self.config.GetBool('want-housing', 1)
self.cannonsEnabled = self.config.GetBool('estate-cannons', 0)
self.fireworksEnabled = self.config.GetBool('estate-fireworks', 0)
self.dayNightEnabled = self.config.GetBool('estate-day-night', 0)
self.cloudPlatformsEnabled = self.config.GetBool('estate-clouds', 0)
self.greySpacing = self.config.GetBool('allow-greyspacing', 0)
self.goonsEnabled = self.config.GetBool('estate-goon', 0)
self.restrictTrialers = self.config.GetBool('restrict-trialers', 1)
self.roamingTrialers = self.config.GetBool('roaming-trialers', 1)
self.slowQuietZone = self.config.GetBool('slow-quiet-zone', 0)
self.slowQuietZoneDelay = self.config.GetFloat('slow-quiet-zone-delay', 5)
self.killInterestResponse = self.config.GetBool('kill-interest-response', 0)
tpMgr = TextPropertiesManager.getGlobalPtr()
WLDisplay = TextProperties()
WLDisplay.setSlant(0.3)
WLEnter = TextProperties()
WLEnter.setTextColor(1.0, 0.0, 0.0, 1)
tpMgr.setProperties('WLDisplay', WLDisplay)
tpMgr.setProperties('WLEnter', WLEnter)
del tpMgr
self.lastScreenShotTime = globalClock.getRealTime()
self.accept('InputState-forward', self.__walking)
self.canScreenShot = 1
self.glitchCount = 0
self.walking = 0
self.oldX = max(1, base.win.getXSize())
self.oldY = max(1, base.win.getYSize())
self.aspectRatio = float(self.oldX) / self.oldY
return
def openMainWindow(self, *args, **kw):
result = OTPBase.OTPBase.openMainWindow(self, *args, **kw)
self.setCursorAndIcon()
return result
def setCursorAndIcon(self):
tempdir = tempfile.mkdtemp()
atexit.register(shutil.rmtree, tempdir)
vfs = VirtualFileSystem.getGlobalPtr()
searchPath = DSearchPath()
searchPath.appendDirectory(Filename('/phase_3/models/gui'))
for filename in ['toonmono.cur', 'icon.ico']:
p3filename = Filename(filename)
found = vfs.resolveFilename(p3filename, searchPath)
if not found:
return # Can't do anything past this point.
with open(os.path.join(tempdir, filename), 'wb') as f:
f.write(vfs.readFile(p3filename, False))
wp = WindowProperties()
wp.setCursorFilename(Filename.fromOsSpecific(os.path.join(tempdir, 'toonmono.cur')))
wp.setIconFilename(Filename.fromOsSpecific(os.path.join(tempdir, 'icon.ico')))
self.win.requestProperties(wp)
def windowEvent(self, win):
OTPBase.OTPBase.windowEvent(self, win)
if not config.GetInt('keep-aspect-ratio', 0):
return
x = max(1, win.getXSize())
y = max(1, win.getYSize())
maxX = base.pipe.getDisplayWidth()
maxY = base.pipe.getDisplayHeight()
cwp = win.getProperties()
originX = 0
originY = 0
if cwp.hasOrigin():
originX = cwp.getXOrigin()
originY = cwp.getYOrigin()
if originX > maxX:
originX = originX - maxX
if originY > maxY:
oringY = originY - maxY
maxX -= originX
maxY -= originY
if math.fabs(x - self.oldX) > math.fabs(y - self.oldY):
newY = x / self.aspectRatio
newX = x
if newY > maxY:
newY = maxY
newX = self.aspectRatio * maxY
else:
newX = self.aspectRatio * y
newY = y
if newX > maxX:
newX = maxX
newY = maxX / self.aspectRatio
wp = WindowProperties()
wp.setSize(newX, newY)
base.win.requestProperties(wp)
base.cam.node().getLens().setFilmSize(newX, newY)
self.oldX = newX
self.oldY = newY
def disableShowbaseMouse(self):
self.useDrive()
self.disableMouse()
if self.mouseInterface:
self.mouseInterface.detachNode()
if base.mouse2cam:
self.mouse2cam.detachNode()
def addCullBins(self):
cullBinMgr = CullBinManager.getGlobalPtr()
cullBinMgr.addBin('gui-popup', CullBinManager.BTUnsorted, 60)
cullBinMgr.addBin('shadow', CullBinManager.BTFixed, 15)
cullBinMgr.addBin('ground', CullBinManager.BTFixed, 14)
def __walking(self, pressed):
self.walking = pressed
def takeScreenShot(self):
if not os.path.exists('screenshots/'):
os.mkdir('screenshots/')
namePrefix = 'screenshot'
namePrefix = 'screenshots/' + launcher.logPrefix + namePrefix
timedif = globalClock.getRealTime() - self.lastScreenShotTime
if self.glitchCount > 10 and self.walking:
return
if timedif < 1.0 and self.walking:
self.glitchCount += 1
return
if not hasattr(self, 'localAvatar'):
self.screenshot(namePrefix=namePrefix)
self.lastScreenShotTime = globalClock.getRealTime()
return
coordOnScreen = self.config.GetBool('screenshot-coords', 0)
self.localAvatar.stopThisFrame = 1
ctext = self.localAvatar.getAvPosStr()
self.screenshotStr = ''
messenger.send('takingScreenshot')
if coordOnScreen:
coordTextLabel = DirectLabel(pos=(-0.81, 0.001, -0.87), text=ctext, text_scale=0.05, text_fg=VBase4(1.0, 1.0, 1.0, 1.0), text_bg=(0, 0, 0, 0), text_shadow=(0, 0, 0, 1), relief=None)
coordTextLabel.setBin('gui-popup', 0)
strTextLabel = None
if len(self.screenshotStr):
strTextLabel = DirectLabel(pos=(0.0, 0.001, 0.9), text=self.screenshotStr, text_scale=0.05, text_fg=VBase4(1.0, 1.0, 1.0, 1.0), text_bg=(0, 0, 0, 0), text_shadow=(0, 0, 0, 1), relief=None)
strTextLabel.setBin('gui-popup', 0)
self.graphicsEngine.renderFrame()
self.screenshot(namePrefix=namePrefix, imageComment=ctext + ' ' + self.screenshotStr)
self.lastScreenShotTime = globalClock.getRealTime()
if coordOnScreen:
if strTextLabel is not None:
strTextLabel.destroy()
coordTextLabel.destroy()
return
def addScreenshotString(self, str):
if len(self.screenshotStr):
self.screenshotStr += '\n'
self.screenshotStr += str
def initNametagGlobals(self):
arrow = loader.loadModel('phase_3/models/props/arrow')
card = loader.loadModel('phase_3/models/props/panel')
speech3d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox').node())
thought3d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox_thought_cutout').node())
speech2d = ChatBalloon(loader.loadModel('phase_3/models/props/chatbox_noarrow').node())
chatButtonGui = loader.loadModel('phase_3/models/gui/chat_button_gui')
NametagGlobals.setCamera(self.cam)
NametagGlobals.setArrowModel(arrow)
NametagGlobals.setNametagCard(card, VBase4(-0.5, 0.5, -0.5, 0.5))
if self.mouseWatcherNode:
NametagGlobals.setMouseWatcher(self.mouseWatcherNode)
NametagGlobals.setSpeechBalloon3d(speech3d)
NametagGlobals.setThoughtBalloon3d(thought3d)
NametagGlobals.setSpeechBalloon2d(speech2d)
NametagGlobals.setThoughtBalloon2d(thought3d)
NametagGlobals.setPageButton(PGButton.SReady, chatButtonGui.find('**/Horiz_Arrow_UP'))
NametagGlobals.setPageButton(PGButton.SDepressed, chatButtonGui.find('**/Horiz_Arrow_DN'))
NametagGlobals.setPageButton(PGButton.SRollover, chatButtonGui.find('**/Horiz_Arrow_Rllvr'))
NametagGlobals.setQuitButton(PGButton.SReady, chatButtonGui.find('**/CloseBtn_UP'))
NametagGlobals.setQuitButton(PGButton.SDepressed, chatButtonGui.find('**/CloseBtn_DN'))
NametagGlobals.setQuitButton(PGButton.SRollover, chatButtonGui.find('**/CloseBtn_Rllvr'))
rolloverSound = DirectGuiGlobals.getDefaultRolloverSound()
if rolloverSound:
NametagGlobals.setRolloverSound(rolloverSound)
clickSound = DirectGuiGlobals.getDefaultClickSound()
if clickSound:
NametagGlobals.setClickSound(clickSound)
NametagGlobals.setToon(self.cam)
self.marginManager = MarginManager()
self.margins = self.aspect2d.attachNewNode(self.marginManager, DirectGuiGlobals.MIDGROUND_SORT_INDEX + 1)
mm = self.marginManager
self.leftCells = [mm.addGridCell(0, 1, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dTopLeft, (0.222222, 0, -1.5)), mm.addGridCell(0, 2, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dTopLeft, (0.222222, 0, -1.16667)), mm.addGridCell(0, 3, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dTopLeft, (0.222222, 0, -0.833333))]
self.bottomCells = [mm.addGridCell(0.5, 0, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dBottomCenter, (-0.888889, 0, 0.166667)),
mm.addGridCell(1.5, 0, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dBottomCenter, (-0.444444, 0, 0.166667)),
mm.addGridCell(2.5, 0, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dBottomCenter, (0, 0, 0.166667)),
mm.addGridCell(3.5, 0, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dBottomCenter, (0.444444, 0, 0.166667)),
mm.addGridCell(4.5, 0, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dBottomCenter, (0.888889, 0, 0.166667))]
self.rightCells = [mm.addGridCell(5, 2, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dTopRight, (-0.222222, 0, -1.16667)), mm.addGridCell(5, 1, -1.33333333333, 1.33333333333, -1.0, 1.0, base.a2dTopRight, (-0.222222, 0, -1.5))]
def setCellsAvailable(self, cell_list, available):
for cell in cell_list:
self.marginManager.setCellAvailable(cell, available)
def cleanupDownloadWatcher(self):
self.downloadWatcher.cleanup()
self.downloadWatcher = None
return
def startShow(self, cr, launcherServer = None):
self.cr = cr
if base.config.GetBool('framebuffer-multisample', False):
render.setAntialias(AntialiasAttrib.MAuto)
base.graphicsEngine.renderFrame()
self.downloadWatcher = ToontownDownloadWatcher.ToontownDownloadWatcher(TTLocalizer.LauncherPhaseNames)
if launcher.isDownloadComplete():
self.cleanupDownloadWatcher()
else:
self.acceptOnce('launcherAllPhasesComplete', self.cleanupDownloadWatcher)
gameServer = base.config.GetString('game-server', '')
if gameServer:
self.notify.info('Using game-server from Configrc: %s ' % gameServer)
elif launcherServer:
gameServer = launcherServer
self.notify.info('Using gameServer from launcher: %s ' % gameServer)
else:
gameServer = '127.0.0.1'
serverPort = base.config.GetInt('server-port', 7198)
serverList = []
for name in gameServer.split(';'):
url = URLSpec(name, 1)
if config.GetBool('want-ssl', False):
url.setScheme('s')
if not url.hasPort():
url.setPort(serverPort)
serverList.append(url)
if len(serverList) == 1:
failover = base.config.GetString('server-failover', '')
serverURL = serverList[0]
for arg in failover.split():
try:
port = int(arg)
url = URLSpec(serverURL)
url.setPort(port)
except:
url = URLSpec(arg, 1)
if url != serverURL:
serverList.append(url)
cr.loginFSM.request('connect', [serverList])
self.ttAccess = ToontownAccess.ToontownAccess()
self.ttAccess.initModuleInfo()
def removeGlitchMessage(self):
self.ignore('InputState-forward')
print 'ignoring InputState-forward'
def exitShow(self, errorCode = None):
self.notify.info('Exiting Toontown: errorCode = %s' % errorCode)
if errorCode:
launcher.setPandaErrorCode(errorCode)
else:
launcher.setPandaErrorCode(0)
sys.exit()
def setExitErrorCode(self, code):
self.exitErrorCode = code
if os.name == 'nt':
exitCode2exitPage = {OTPLauncherGlobals.ExitEnableChat: 'chat',
OTPLauncherGlobals.ExitSetParentPassword: 'setparentpassword',
OTPLauncherGlobals.ExitPurchase: 'purchase'}
if code in exitCode2exitPage:
launcher.setRegistry('EXIT_PAGE', exitCode2exitPage[code])
def getExitErrorCode(self):
return self.exitErrorCode
def userExit(self):
try:
self.localAvatar.d_setAnimState('TeleportOut', 1)
except:
pass
if hasattr(self, 'ttAccess'):
self.ttAccess.delete()
if self.cr.timeManager:
self.cr.timeManager.setDisconnectReason(ToontownGlobals.DisconnectCloseWindow)
base.cr._userLoggingOut = False
try:
localAvatar
except:
pass
else:
messenger.send('clientLogout')
self.cr.dumpAllSubShardObjects()
self.cr.loginFSM.request('shutdown')
self.notify.warning('Could not request shutdown; exiting anyway.')
self.exitShow()
def panda3dRenderError(self):
launcher.setPandaErrorCode(14)
if self.cr.timeManager:
self.cr.timeManager.setDisconnectReason(ToontownGlobals.DisconnectGraphicsError)
self.cr.sendDisconnect()
sys.exit()
def getShardPopLimits(self):
if self.cr.productName == 'JP':
return (config.GetInt('shard-low-pop', ToontownGlobals.LOW_POP_JP), config.GetInt('shard-mid-pop', ToontownGlobals.MID_POP_JP), config.GetInt('shard-high-pop', ToontownGlobals.HIGH_POP_JP))
elif self.cr.productName in ['BR', 'FR']:
return (config.GetInt('shard-low-pop', ToontownGlobals.LOW_POP_INTL), config.GetInt('shard-mid-pop', ToontownGlobals.MID_POP_INTL), config.GetInt('shard-high-pop', ToontownGlobals.HIGH_POP_INTL))
else:
return (config.GetInt('shard-low-pop', ToontownGlobals.LOW_POP), config.GetInt('shard-mid-pop', ToontownGlobals.MID_POP), config.GetInt('shard-high-pop', ToontownGlobals.HIGH_POP))
def playMusic(self, music, looping = 0, interrupt = 1, volume = None, time = 0.0):
OTPBase.OTPBase.playMusic(self, music, looping, interrupt, volume, time)
def loadFromSettings(self):
if not config.GetInt('ignore-user-options', 0):
fullscreen = self.settings.getBool('game', 'fullscreen', False)
music = self.settings.getBool('game', 'music', True)
sfx = self.settings.getBool('game', 'sfx', True)
toonChatSounds = self.settings.getBool('game', 'toon-chat-sounds', True)
musicVol = self.settings.getFloat('game', 'music-volume', 1.0)
sfxVol = self.settings.getFloat('game', 'sfx-volume', 1.0)
res = self.settings.getList('game', 'resolution', [800, 600])
antialias = self.settings.getInt('game', 'antialiasing', 0)
if antialias:
loadPrcFileData('toonBase Settings Framebuffer MSAA', 'framebuffer-multisample 1')
loadPrcFileData('toonBase Settings MSAA Level', 'multisamples %i' % antialias)
else:
self.settings.updateSetting('game', 'antialiasing', antialias)
loadPrcFileData('toonBase Settings Framebuffer MSAA', 'framebuffer-multisample 0')
loadPrcFileData('toonBase Settings Window Res', 'win-size %s %s' % (res[0], res[1]))
loadPrcFileData('toonBase Settings Window FullScreen', 'fullscreen %s' % fullscreen)
loadPrcFileData('toonBase Settings Music Active', 'audio-music-active %s' % music)
loadPrcFileData('toonBase Settings Sound Active', 'audio-sfx-active %s' % sfx)
loadPrcFileData('toonBase Settings Music Volume', 'audio-master-music-volume %s' % musicVol)
loadPrcFileData('toonBase Settings Sfx Volume', 'audio-master-sfx-volume %s' % sfxVol)
loadPrcFileData('toonBase Settings Toon Chat Sounds', 'toon-chat-sounds %s' % toonChatSounds)
self.settings.loadFromSettings()