578 lines
18 KiB
Python
578 lines
18 KiB
Python
import random
|
|
import time
|
|
import datetime
|
|
from pandac.PandaModules import Vec4, TextNode, CardMaker, NodePath
|
|
from direct.distributed import DistributedObject
|
|
from direct.task.Task import Task
|
|
from direct.interval.IntervalGlobal import *
|
|
from direct.gui.DirectGui import DirectLabel
|
|
from direct.gui import OnscreenText
|
|
from toontown.toonbase import ToontownGlobals
|
|
from toontown.parties.PartyInfo import PartyInfo
|
|
from toontown.toonbase import TTLocalizer
|
|
from toontown.toon import Toon
|
|
from toontown.parties import PartyGlobals
|
|
from toontown.parties.Decoration import Decoration
|
|
import PartyUtils
|
|
|
|
class DistributedParty(DistributedObject.DistributedObject):
|
|
notify = directNotify.newCategory('DistributedParty')
|
|
generatedEvent = 'distributedPartyGenerated'
|
|
|
|
def __init__(self, cr):
|
|
DistributedObject.DistributedObject.__init__(self, cr)
|
|
self.partyDoneEvent = 'partyDone'
|
|
self.load()
|
|
self.avIdsAtParty = []
|
|
base.distributedParty = self
|
|
self.titleText = ''
|
|
self.isPartyEnding = False
|
|
|
|
def setPartyState(self, partyState):
|
|
self.isPartyEnding = partyState
|
|
messenger.send('partyStateChanged', [partyState])
|
|
|
|
def getPartyState(self):
|
|
return self.isPartyEnding
|
|
|
|
def setPartyClockInfo(self, x, y, h):
|
|
x = PartyUtils.convertDistanceFromPartyGrid(x, 0)
|
|
y = PartyUtils.convertDistanceFromPartyGrid(y, 1)
|
|
h = PartyUtils.convertDegreesFromPartyGrid(h)
|
|
self.partyClockInfo = (x, y, h)
|
|
self.loadPartyCountdownTimer()
|
|
|
|
def setInviteeIds(self, inviteeIds):
|
|
self.inviteeIds = inviteeIds
|
|
|
|
def setPartyInfoTuple(self, partyInfoTuple):
|
|
self.partyInfo = PartyInfo(*partyInfoTuple)
|
|
self.loadDecorations()
|
|
allActIds = [ x.activityId for x in self.partyInfo.activityList ]
|
|
base.partyHasJukebox = PartyGlobals.ActivityIds.PartyJukebox in allActIds or PartyGlobals.ActivityIds.PartyJukebox40 in allActIds
|
|
self.grid = [[False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False],
|
|
[False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True],
|
|
[False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False],
|
|
[False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
True,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False,
|
|
False]]
|
|
|
|
def fillGrid(x, y, size):
|
|
for i in xrange(-size[1] / 2 + 1, size[1] / 2 + 1):
|
|
for j in xrange(-size[0] / 2 + 1, size[0] / 2 + 1):
|
|
self.grid[i + y][j + x] = False
|
|
|
|
for activityBase in self.partyInfo.activityList:
|
|
fillGrid(activityBase.x, activityBase.y, PartyGlobals.ActivityInformationDict[activityBase.activityId]['gridsize'])
|
|
|
|
for decorBase in self.partyInfo.decors:
|
|
fillGrid(decorBase.x, decorBase.y, PartyGlobals.DecorationInformationDict[decorBase.decorId]['gridsize'])
|
|
|
|
self.loadGrass()
|
|
|
|
def setPartyStartedTime(self, startedTime):
|
|
stime = time.strptime(startedTime, '%Y-%m-%d %H:%M:%S')
|
|
self.partyStartedTime = datetime.datetime(year=stime.tm_year, month=stime.tm_mon, day=stime.tm_mday, hour=stime.tm_hour, minute=stime.tm_min, second=stime.tm_sec, tzinfo=base.cr.toontownTimeManager.getCurServerDateTime().tzinfo)
|
|
|
|
def disable(self):
|
|
self.notify.debug('disable')
|
|
DistributedObject.DistributedObject.disable(self)
|
|
base.localAvatar.chatMgr.chatInputSpeedChat.removeInsidePartiesMenu()
|
|
|
|
def delete(self):
|
|
self.notify.debug('delete')
|
|
self.unload()
|
|
if hasattr(base, 'distributedParty'):
|
|
del base.distributedParty
|
|
DistributedObject.DistributedObject.delete(self)
|
|
|
|
def load(self):
|
|
Toon.loadMinigameAnims()
|
|
self.defaultSignModel = loader.loadModel('phase_13/models/parties/eventSign')
|
|
self.activityIconsModel = loader.loadModel('phase_4/models/parties/eventSignIcons')
|
|
self.defaultLeverModel = loader.loadModel('phase_13/models/parties/partyLeverBase')
|
|
self.defaultStickModel = loader.loadModel('phase_13/models/parties/partyLeverStick')
|
|
|
|
def loadGrass(self):
|
|
self.grassRoot = NodePath('GrassRoot')
|
|
self.grassRoot.reparentTo(base.cr.playGame.hood.loader.geom)
|
|
grass = loader.loadModel('phase_13/models/parties/grass')
|
|
clearPositions = self.getClearSquarePositions()
|
|
numTufts = min(len(clearPositions) * 3, PartyGlobals.TuftsOfGrass)
|
|
for i in xrange(numTufts):
|
|
g = grass.copyTo(self.grassRoot)
|
|
pos = random.choice(clearPositions)
|
|
g.setPos(pos[0] + random.randint(-8, 8), pos[1] + random.randint(-8, 8), 0.0)
|
|
|
|
def loadDecorations(self):
|
|
self.decorationsList = []
|
|
for decorBase in self.partyInfo.decors:
|
|
self.decorationsList.append(Decoration(PartyGlobals.DecorationIds.getString(decorBase.decorId), PartyUtils.convertDistanceFromPartyGrid(decorBase.x, 0), PartyUtils.convertDistanceFromPartyGrid(decorBase.y, 1), PartyUtils.convertDegreesFromPartyGrid(decorBase.h)))
|
|
|
|
def unload(self):
|
|
if hasattr(self, 'decorationsList') and self.decorationsList:
|
|
for decor in self.decorationsList:
|
|
decor.unload()
|
|
|
|
del self.decorationsList
|
|
self.stopPartyClock()
|
|
self.grassRoot.removeNode()
|
|
del self.grassRoot
|
|
if hasattr(self, 'testGrid'):
|
|
self.testGrid.removeNode()
|
|
del self.testGrid
|
|
self.ignoreAll()
|
|
Toon.unloadMinigameAnims()
|
|
self.removePartyHats()
|
|
if hasattr(base, 'partyHasJukebox'):
|
|
del base.partyHasJukebox
|
|
|
|
def announceGenerate(self):
|
|
#TODO - for some reason this is getting called hundreds of times when there are multiple districts
|
|
DistributedObject.DistributedObject.announceGenerate(self)
|
|
self.sendUpdate('enteredParty', [])
|
|
globalClock.syncFrameTime()
|
|
self.startPartyClock()
|
|
base.localAvatar.chatMgr.chatInputSpeedChat.addInsidePartiesMenu()
|
|
self.spawnTitleText()
|
|
messenger.send(self.generatedEvent)
|
|
if config.GetBool('show-debug-party-grid', 0):
|
|
self.testGrid = NodePath('test_grid')
|
|
self.testGrid.reparentTo(base.cr.playGame.hood.loader.geom)
|
|
for i in xrange(len(self.grid)):
|
|
for j in xrange(len(self.grid[i])):
|
|
cm = CardMaker('gridsquare')
|
|
np = NodePath(cm.generate())
|
|
np.setScale(12)
|
|
np.setP(-90.0)
|
|
np.setPos(PartyUtils.convertDistanceFromPartyGrid(j, 0) - 6.0, PartyUtils.convertDistanceFromPartyGrid(i, 1) - 6.0, 0.1)
|
|
np.reparentTo(self.testGrid)
|
|
if self.grid[i][j]:
|
|
np.setColorScale(0.0, 1.0, 0.0, 1.0)
|
|
else:
|
|
np.setColorScale(1.0, 0.0, 0.0, 1.0)
|
|
|
|
def removePartyHats(self):
|
|
for av in base.cr.doId2do.values():
|
|
if isinstance(av, Toon.Toon):
|
|
av.removePartyHat()
|
|
|
|
def getClearSquarePos(self):
|
|
clearPositions = self.getClearSquarePositions()
|
|
if len(clearPositions) == 0:
|
|
raise StandardError, 'Party %s has no empty grid squares.' % self.doId
|
|
return random.choice(clearPositions)
|
|
|
|
def getClearSquarePositions(self):
|
|
clearPositions = []
|
|
for y in xrange(len(self.grid)):
|
|
for x in xrange(len(self.grid[0])):
|
|
if self.grid[y][x]:
|
|
pos = (PartyUtils.convertDistanceFromPartyGrid(x, 0), PartyUtils.convertDistanceFromPartyGrid(y, 1), 0.1)
|
|
clearPositions.append(pos)
|
|
|
|
return clearPositions
|
|
|
|
def startPartyClock(self):
|
|
self.partyClockModel.reparentTo(base.cr.playGame.hood.loader.geom)
|
|
curServerTime = base.cr.toontownTimeManager.getCurServerDateTime()
|
|
timePartyWillEnd = self.partyStartedTime + datetime.timedelta(hours=PartyGlobals.DefaultPartyDuration)
|
|
timeLeftInParty = timePartyWillEnd - curServerTime
|
|
if curServerTime < timePartyWillEnd:
|
|
self.secondsLeftInParty = timeLeftInParty.seconds
|
|
else:
|
|
self.secondsLeftInParty = 0
|
|
taskMgr.doMethodLater(0.5, self.partyClockTask, 'UpdatePartyClock')
|
|
self.partyClockSignFront = self.partyClockModel.find('**/signFrontText_locator')
|
|
self.partyClockSignBack = self.partyClockModel.find('**/signBackText_locator')
|
|
self.attachHostNameToSign(self.partyClockSignFront)
|
|
self.attachHostNameToSign(self.partyClockSignBack)
|
|
|
|
def attachHostNameToSign(self, locator):
|
|
if self.hostName == '':
|
|
return
|
|
nameText = TextNode('nameText')
|
|
nameText.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
|
|
nameText.setCardDecal(True)
|
|
nameText.setCardColor(1.0, 1.0, 1.0, 0.0)
|
|
r = 232.0 / 255.0
|
|
g = 169.0 / 255.0
|
|
b = 23.0 / 255.0
|
|
nameText.setTextColor(r, g, b, 1)
|
|
nameText.setAlign(nameText.ACenter)
|
|
nameText.setFont(ToontownGlobals.getBuildingNametagFont())
|
|
nameText.setShadowColor(0, 0, 0, 1)
|
|
nameText.setBin('fixed')
|
|
if TTLocalizer.BuildingNametagShadow:
|
|
nameText.setShadow(*TTLocalizer.BuildingNametagShadow)
|
|
nameWordWrap = 11.0
|
|
nameText.setWordwrap(nameWordWrap)
|
|
scaleMult = 0.48
|
|
houseName = self.hostName
|
|
nameText.setText(houseName)
|
|
textWidth = nameText.getWidth()
|
|
xScale = 1.0 * scaleMult
|
|
if textWidth > nameWordWrap:
|
|
xScale = nameWordWrap / textWidth * scaleMult
|
|
sign_origin = locator
|
|
namePlate = sign_origin.attachNewNode(nameText)
|
|
namePlate.setDepthWrite(0)
|
|
namePlate.setPos(0, 0, 0)
|
|
namePlate.setScale(xScale)
|
|
|
|
def stopPartyClock(self):
|
|
self.partyClockModel.removeNode()
|
|
taskMgr.remove('UpdatePartyClock')
|
|
|
|
def partyClockTask(self, task):
|
|
self.secondsLeftInParty -= 0.5
|
|
if self.secondsLeftInParty < 0:
|
|
self.frontTimer['minute']['text'] = '--'
|
|
self.backTimer['minute']['text'] = '--'
|
|
self.frontTimer['second']['text'] = '--'
|
|
self.backTimer['second']['text'] = '--'
|
|
return
|
|
if self.frontTimer['colon'].isStashed():
|
|
self.frontTimer['colon'].unstash()
|
|
self.backTimer['colon'].unstash()
|
|
else:
|
|
self.frontTimer['colon'].stash()
|
|
self.backTimer['colon'].stash()
|
|
minutesLeft = int(int(self.secondsLeftInParty / 60) % 60)
|
|
if minutesLeft < 10:
|
|
minutesLeft = '0%d' % minutesLeft
|
|
else:
|
|
minutesLeft = '%d' % minutesLeft
|
|
secondsLeft = int(self.secondsLeftInParty % 60)
|
|
if secondsLeft < 10:
|
|
secondsLeft = '0%d' % secondsLeft
|
|
else:
|
|
secondsLeft = '%d' % secondsLeft
|
|
self.frontTimer['minute']['text'] = minutesLeft
|
|
self.backTimer['minute']['text'] = minutesLeft
|
|
self.frontTimer['second']['text'] = secondsLeft
|
|
self.backTimer['second']['text'] = secondsLeft
|
|
taskMgr.doMethodLater(0.5, self.partyClockTask, 'UpdatePartyClock')
|
|
if self.secondsLeftInParty != int(self.secondsLeftInParty):
|
|
self.partyClockModel.find('**/middleRotateFront_grp').setR(-6.0 * (self.secondsLeftInParty % 60))
|
|
self.partyClockModel.find('**/middleRotateBack_grp').setR(6.0 * (self.secondsLeftInParty % 60))
|
|
|
|
def getAvIdsAtParty(self):
|
|
return self.avIdsAtParty
|
|
|
|
def setAvIdsAtParty(self, avIdsAtParty):
|
|
self.avIdsAtParty = avIdsAtParty
|
|
|
|
def loadPartyCountdownTimer(self):
|
|
self.partyClockModel = loader.loadModel('phase_13/models/parties/partyClock')
|
|
self.partyClockModel.setPos(self.partyClockInfo[0], self.partyClockInfo[1], 0.0)
|
|
self.partyClockModel.setH(self.partyClockInfo[2])
|
|
self.partyClockModel.reparentTo(base.cr.playGame.hood.loader.geom)
|
|
self.partyClockModel.find('**/frontText_locator').setY(-1.1)
|
|
self.partyClockModel.find('**/backText_locator').setY(0.633)
|
|
self.frontTimer = self.getTimer(self.partyClockModel.find('**/frontText_locator'))
|
|
base.frontTimerLoc = self.partyClockModel.find('**/frontText_locator')
|
|
base.backTimerLoc = self.partyClockModel.find('**/backText_locator')
|
|
self.backTimer = self.getTimer(self.partyClockModel.find('**/backText_locator'))
|
|
self.partyClockModel.stash()
|
|
|
|
def getTimer(self, parent):
|
|
timeFont = ToontownGlobals.getMinnieFont()
|
|
timer = {}
|
|
timer['minute'] = DirectLabel(parent=parent, pos=TTLocalizer.DPtimerMinutePos, relief=None, text='59', text_align=TextNode.ACenter, text_font=timeFont, text_fg=(0.7, 0.3, 0.3, 1.0), scale=TTLocalizer.DPtimerMinute)
|
|
timer['colon'] = DirectLabel(parent=parent, pos=TTLocalizer.DPtimerColonPos, relief=None, text=':', text_align=TextNode.ACenter, text_font=timeFont, text_fg=(0.7, 0.3, 0.3, 1.0), scale=TTLocalizer.DPtimerColon)
|
|
timer['second'] = DirectLabel(parent=parent, relief=None, pos=TTLocalizer.DPtimerSecondPos, text='14', text_align=TextNode.ACenter, text_font=timeFont, text_fg=(0.7, 0.3, 0.3, 1.0), scale=TTLocalizer.DPtimerSecond)
|
|
timer['textLabel'] = DirectLabel(parent=parent, relief=None, pos=(0.0, 0.0, 1.15), text=TTLocalizer.PartyCountdownClockText, text_font=timeFont, text_fg=(0.7, 0.3, 0.3, 1.0), scale=TTLocalizer.DPtimerTextLabel)
|
|
return timer
|
|
|
|
def setHostName(self, hostName):
|
|
self.hostName = hostName
|
|
if hasattr(self, 'partyClockSignFront'):
|
|
self.attachHostNameToSign(self.partyClockSignFront)
|
|
if hasattr(self, 'partyClockSignBack'):
|
|
self.attachHostNameToSign(self.partyClockSignBack)
|
|
|
|
def spawnTitleText(self):
|
|
if not self.hostName:
|
|
return
|
|
partyText = TTLocalizer.PartyTitleText % TTLocalizer.GetPossesive(self.hostName)
|
|
self.doSpawnTitleText(partyText)
|
|
|
|
def doSpawnTitleText(self, text):
|
|
self.titleColor = (1.0, 0.5, 0.4, 1.0)
|
|
self.titleText = OnscreenText.OnscreenText(text, fg=self.titleColor, font=ToontownGlobals.getSignFont(), pos=(0, -0.5), scale=0.16, drawOrder=0, mayChange=1, wordwrap=16)
|
|
self.titleText.setText(text)
|
|
self.titleText.show()
|
|
self.titleText.setColor(Vec4(*self.titleColor))
|
|
self.titleText.clearColorScale()
|
|
self.titleText.setFg(self.titleColor)
|
|
seq = Sequence(Wait(0.1), Wait(6.0), self.titleText.colorScaleInterval(0.5, Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.hideTitleText))
|
|
seq.start()
|
|
|
|
def hideTitleText(self):
|
|
if self.titleText:
|
|
self.titleText.hide()
|