holidays: Add some client documentation & Cleanup imports

This commit is contained in:
Leo 2026-03-22 09:31:42 -04:00
parent 0be1f99f03
commit 730140e222
33 changed files with 322 additions and 139 deletions

View File

@ -1,6 +1,5 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
class BlackCatHolidayMgrAI(HolidayBaseAI.HolidayBaseAI): class BlackCatHolidayMgrAI(HolidayBaseAI.HolidayBaseAI):
notify = DirectNotifyGlobal.directNotify.newCategory( notify = DirectNotifyGlobal.directNotify.newCategory(

View File

@ -1,7 +1,7 @@
from panda3d.core import CSDefault, ConfigVariable, ConfigVariableBool from panda3d.core import CSDefault, ConfigVariableBool
from panda3d.toontown import loadDNAFile
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import * from direct.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import *
from . import HolidayDecorator from . import HolidayDecorator
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals
from toontown.hood import GSHood from toontown.hood import GSHood

View File

@ -3,18 +3,28 @@ from direct.distributed import DistributedObject
from direct.interval.IntervalGlobal import * from direct.interval.IntervalGlobal import *
from toontown.effects import DustCloud from toontown.effects import DustCloud
def getDustCloudIval(toon): def getDustCloudIval(toon):
dustCloud = DustCloud.DustCloud(fBillboard=0) dustCloud = DustCloud.DustCloud(fBillboard=0)
dustCloud.setBillboardAxis(2.0) dustCloud.setBillboardAxis(2)
dustCloud.setZ(3) dustCloud.setZ(3)
dustCloud.setScale(0.4) dustCloud.setScale(0.4)
dustCloud.createTrack() dustCloud.createTrack()
toon.laffMeter.color = toon.style.getBlackColor() toon.laffMeter.color = toon.style.getBlackColor()
return Sequence(Wait(0.5), Func(dustCloud.reparentTo, toon), dustCloud.track, Func(dustCloud.detachNode), Func(toon.laffMeter.adjustFace, toon.hp, toon.maxHp)) return Sequence(
Wait(.5),
Func(dustCloud.reparentTo, toon),
dustCloud.track,
Func(dustCloud.detachNode),
Func(toon.laffMeter.adjustFace, toon.hp, toon.maxHp)
)
class DistributedBlackCatMgr(DistributedObject.DistributedObject): class DistributedBlackCatMgr(DistributedObject.DistributedObject):
"""Black cat client implementation; turn a cat into a black cat if
they say 'Toontastic!' to Flippy in the tutorial on Halloween."""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBlackCatMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBlackCatMgr')
ActivateEvent = 'DistributedBlackCatMgr-activate' ActivateEvent = 'DistributedBlackCatMgr-activate'
def __init__(self, cr): def __init__(self, cr):
@ -24,11 +34,11 @@ class DistributedBlackCatMgr(DistributedObject.DistributedObject):
self.avId = avId self.avId = avId
def announceGenerate(self): def announceGenerate(self):
DistributedBlackCatMgr.notify.debug('announceGenerate') self.notify.debug("announceGenerate()")
DistributedObject.DistributedObject.announceGenerate(self) DistributedObject.DistributedObject.announceGenerate(self)
self.acceptOnce(DistributedBlackCatMgr.ActivateEvent, self.doBlackCatTransformation) self.acceptOnce(DistributedBlackCatMgr.ActivateEvent,
self.doBlackCatTransformation)
self.dustCloudIval = None self.dustCloudIval = None
return
def delete(self): def delete(self):
if self.dustCloudIval: if self.dustCloudIval:
@ -38,14 +48,19 @@ class DistributedBlackCatMgr(DistributedObject.DistributedObject):
DistributedObject.DistributedObject.delete(self) DistributedObject.DistributedObject.delete(self)
def doBlackCatTransformation(self): def doBlackCatTransformation(self):
DistributedBlackCatMgr.notify.debug('doBlackCatTransformation') self.notify.debug("doBlackCatTransformation()")
toon = base.cr.doId2do[self.avId] toon = base.cr.doId2do[self.avId]
if not toon: if not toon:
DistributedBlackCatMgr.notify.warning("couldn't find Toon %s" % self.avId) self.notify.warning(f"Couldn't find Toon {self.avId}")
return return
# are they a cat?
if toon.style.getAnimal() != 'cat': if toon.style.getAnimal() != 'cat':
DistributedBlackCatMgr.notify.warning('not a cat: %s' % self.avId) self.notify.warning(f"Not a cat: {self.avId}")
return return
self.sendUpdate('doBlackCatTransformation', []) self.sendUpdate('doBlackCatTransformation', [])
# kick off a dust cloud.
# If a player has a LOT of lag, the dust cloud will disappear before
# the cat turns black.
self.dustCloudIval = getDustCloudIval(toon) self.dustCloudIval = getDustCloudIval(toon)
self.dustCloudIval.start() self.dustCloudIval.start()

View File

@ -5,6 +5,8 @@ from otp.speedchat import SpeedChatGlobals
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
class DistributedGreenToonEffectMgr(DistributedObject.DistributedObject): class DistributedGreenToonEffectMgr(DistributedObject.DistributedObject):
"""Green toon client implementation; turn a toon green if
they say 'It's easy to be green!' to Eugene during the Ires of March event."""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGreenToonEffectMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGreenToonEffectMgr')
def __init__(self, cr): def __init__(self, cr):
@ -19,14 +21,14 @@ class DistributedGreenToonEffectMgr(DistributedObject.DistributedObject):
def announceGenerate(self): def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self) DistributedObject.DistributedObject.announceGenerate(self)
DistributedGreenToonEffectMgr.notify.debug('announceGenerate') self.notify.debug("announceGenerate()")
def delete(self): def delete(self):
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent) self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self) DistributedObject.DistributedObject.delete(self)
def addGreenToonEffect(self): def addGreenToonEffect(self):
DistributedGreenToonEffectMgr.notify.debug('addGreenToonEffect') self.notify.debug("addGreenToonEffect()")
av = base.localAvatar av = base.localAvatar
self.sendUpdate('addGreenToonEffect', []) self.sendUpdate('addGreenToonEffect', [])
msgTrack = Sequence(Func(av.setSystemMessage, 0, TTLocalizer.GreenToonEffectMsg)) msgTrack = Sequence(Func(av.setSystemMessage, 0, TTLocalizer.GreenToonEffectMsg))

View File

@ -1,8 +1,9 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.ai import DistributedPhaseEventMgr from toontown.ai import DistributedPhaseEventMgr
class DistributedHydrantZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr): class DistributedHydrantZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the hydrant zero manager"""
neverDisable = 1 neverDisable = 1
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedHydrantZeroMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedHydrantZeroMgr')
@ -11,20 +12,25 @@ class DistributedHydrantZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMg
cr.hydrantZeroMgr = self cr.hydrantZeroMgr = self
def announceGenerate(self): def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('hydrantZeroIsRunning', [self.isRunning]) messenger.send('hydrantZeroIsRunning', [self.isRunning])
def delete(self): def delete(self):
self.notify.debug('deleting hydrantzeromgr') self.notify.debug("deleting hydrantzeromgr")
messenger.send('hydrantZeroIsRunning', [False]) messenger.send('hydrantZeroIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'hydrantZeroMgr'): if hasattr(self.cr, "hydrantZeroMgr"):
del self.cr.hydrantZeroMgr del self.cr.hydrantZeroMgr
def setCurPhase(self, newPhase): def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the hydrants."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('hydrantZeroPhase', [newPhase]) messenger.send('hydrantZeroPhase', [newPhase])
def setIsRunning(self, isRunning): def setIsRunning(self, isRunning):
"""We've gotten a new phase lets, tell the hydrants."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('hydrantZeroIsRunning', [isRunning]) messenger.send('hydrantZeroIsRunning', [isRunning])

View File

@ -1,30 +1,39 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.ai import DistributedPhaseEventMgr from toontown.ai import DistributedPhaseEventMgr
class DistributedMailboxZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr): class DistributedMailboxZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the mailbox zero manager"""
neverDisable = 1 neverDisable = 1
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedMailboxZeroMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedMailboxZeroMgr')
# tempted to change this to have mailbox, hydrant, and trashcan as fields
# but for holiday and magic word convenience, we'll use 3 separate classes
def __init__(self, cr): def __init__(self, cr):
DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr) DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr)
cr.mailboxZeroMgr = self cr.mailboxZeroMgr = self
def announceGenerate(self): def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('mailboxZeroIsRunning', [self.isRunning]) messenger.send('mailboxZeroIsRunning', [self.isRunning])
def delete(self): def delete(self):
self.notify.debug('deleting mailboxzeromgr') self.notify.debug("deleting mailboxzeromgr")
messenger.send('mailboxZeroIsRunning', [False]) messenger.send('mailboxZeroIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'mailboxZeroMgr'): if hasattr(self.cr, "mailboxZeroMgr"):
del self.cr.mailboxZeroMgr del self.cr.mailboxZeroMgr
def setCurPhase(self, newPhase): def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the mailboxs."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('mailboxZeroPhase', [newPhase]) messenger.send('mailboxZeroPhase', [newPhase])
def setIsRunning(self, isRunning): def setIsRunning(self, isRunning):
"""We've gotten a new phase lets, tell the mailboxs."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('mailboxZeroIsRunning', [isRunning]) messenger.send('mailboxZeroIsRunning', [isRunning])

View File

@ -2,7 +2,9 @@ from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject from direct.distributed import DistributedObject
import datetime import datetime
class DistributedPhaseEventMgr(DistributedObject.DistributedObject): class DistributedPhaseEventMgr(DistributedObject.DistributedObject):
"""Base Class to manage the hydrant/mailbox/trashcan zero manager"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPhaseEventMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPhaseEventMgr')
def __init__(self, cr): def __init__(self, cr):
@ -28,5 +30,10 @@ class DistributedPhaseEventMgr(DistributedObject.DistributedObject):
return self.curPhase return self.curPhase
def setDates(self, holidayDates): def setDates(self, holidayDates):
"""
Provide the client with the phase date information
"""
for holidayDate in holidayDates: for holidayDate in holidayDates:
self.holidayDates.append(datetime.datetime(holidayDate[0], holidayDate[1], holidayDate[2], holidayDate[3], holidayDate[4], holidayDate[5])) # year, month, day, hour, min, sec
self.holidayDates.append(datetime.datetime(holidayDate[0], holidayDate[1], holidayDate[2],
holidayDate[3], holidayDate[4], holidayDate[5]))

View File

@ -4,12 +4,17 @@ from direct.interval.IntervalGlobal import *
from otp.speedchat import SpeedChatGlobals from otp.speedchat import SpeedChatGlobals
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
class DistributedPolarPlaceEffectMgr(DistributedObject.DistributedObject): class DistributedPolarPlaceEffectMgr(DistributedObject.DistributedObject):
"""PolarPlace effect client implementation; make the toon large and white if
they say 'Howdy!' to Paula Behr in during the promotion for Lawbot HQ."""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPolarPlaceEffectMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPolarPlaceEffectMgr')
def __init__(self, cr): def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr) DistributedObject.DistributedObject.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(phraseId): def phraseSaid(phraseId):
helpPhrase = 104 helpPhrase = 104
if phraseId == helpPhrase: if phraseId == helpPhrase:
@ -19,15 +24,24 @@ class DistributedPolarPlaceEffectMgr(DistributedObject.DistributedObject):
def announceGenerate(self): def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self) DistributedObject.DistributedObject.announceGenerate(self)
DistributedPolarPlaceEffectMgr.notify.debug('announceGenerate') self.notify.debug("announceGenerate()")
def delete(self): def delete(self):
# stop listening to speed chat
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent) self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self) DistributedObject.DistributedObject.delete(self)
# do the event
def addPolarPlaceEffect(self): def addPolarPlaceEffect(self):
DistributedPolarPlaceEffectMgr.notify.debug('addResitanceEffect') self.notify.debug("addPolarPlaceEffect()")
av = base.localAvatar av = base.localAvatar
self.sendUpdate('addPolarPlaceEffect', []) self.sendUpdate('addPolarPlaceEffect', [])
msgTrack = Sequence(Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect1), Wait(2), Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect2), Wait(4), Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect3))
msgTrack = Sequence(
Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect1),
Wait(2),
Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect2),
Wait(4),
Func(av.setSystemMessage, 0, TTLocalizer.PolarPlaceEffect3),
)
msgTrack.start() msgTrack.start()

View File

@ -4,14 +4,19 @@ from direct.interval.IntervalGlobal import *
from otp.speedchat import SpeedChatGlobals from otp.speedchat import SpeedChatGlobals
from otp.otpbase.OTPLocalizerEnglish import EmoteFuncDict from otp.otpbase.OTPLocalizerEnglish import EmoteFuncDict
from toontown.toonbase import TTLocalizer from toontown.toonbase import TTLocalizer
RESIST_INDEX = EmoteFuncDict['Resistance Salute']
RESIST_INDEX = EmoteFuncDict["Resistance Salute"]
class DistributedResistanceEmoteMgr(DistributedObject.DistributedObject): class DistributedResistanceEmoteMgr(DistributedObject.DistributedObject):
"""Resistance emote client implementation; turn a cat into a black cat if
they say 'Do you need help?' to Whispering Willow during the promotion for Cashbot HQ."""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedResistanceEmoteMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedResistanceEmoteMgr')
def __init__(self, cr): def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr) DistributedObject.DistributedObject.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(phraseId): def phraseSaid(phraseId):
helpPhrase = 513 helpPhrase = 513
if phraseId == helpPhrase: if phraseId == helpPhrase:
@ -21,16 +26,27 @@ class DistributedResistanceEmoteMgr(DistributedObject.DistributedObject):
def announceGenerate(self): def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self) DistributedObject.DistributedObject.announceGenerate(self)
DistributedResistanceEmoteMgr.notify.debug('announceGenerate') self.notify.debug("announceGenerate()")
def delete(self): def delete(self):
# stop listening to speed chat
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent) self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self) DistributedObject.DistributedObject.delete(self)
# do the event
def addResistanceEmote(self): def addResistanceEmote(self):
DistributedResistanceEmoteMgr.notify.debug('addResitanceEmote') self.notify.debug("addResistanceEmote()")
av = base.localAvatar av = base.localAvatar
# make sure they haven't already done this
if not av.emoteAccess[RESIST_INDEX]: if not av.emoteAccess[RESIST_INDEX]:
self.sendUpdate('addResistanceEmote', []) self.sendUpdate('addResistanceEmote', [])
msgTrack = Sequence(Wait(1), Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote1), Wait(3), Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote2), Wait(4), Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote3))
msgTrack = Sequence(
Wait(1),
Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote1),
Wait(3),
Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote2),
Wait(4),
Func(av.setSystemMessage, 0, TTLocalizer.ResistanceEmote3),
)
msgTrack.start() msgTrack.start()

View File

@ -2,7 +2,13 @@ from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject from direct.distributed import DistributedObject
from otp.speedchat import SpeedChatGlobals from otp.speedchat import SpeedChatGlobals
class DistributedScavengerHuntTarget(DistributedObject.DistributedObject): class DistributedScavengerHuntTarget(DistributedObject.DistributedObject):
"""
Upon the occurence of some event, it stops listening for
a few seconds in order to screen repeated attempts during high lag periods.
"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedScavengerHuntTarget') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedScavengerHuntTarget')
def __init__(self, cr): def __init__(self, cr):
@ -10,31 +16,38 @@ class DistributedScavengerHuntTarget(DistributedObject.DistributedObject):
def setupListenerDetails(self): def setupListenerDetails(self):
self.triggered = False self.triggered = False
self.triggerDelay = 15 self.triggerDelay = 15 # Seconds to disable the listener
self.accept(SpeedChatGlobals.SCCustomMsgEvent, self.phraseSaid) self.accept(SpeedChatGlobals.SCCustomMsgEvent, self.phraseSaid)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId): def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said') self.notify.debug("Checking if phrase was said")
helpPhrase = 10003 helpPhrase = 10003 # 'Trick or Treat!'
def reset(): def reset():
self.triggered = False self.triggered = False
# self.accept(SpeedChatGlobals.SCCustomMsgEvent, phraseSaid)
if phraseId == helpPhrase and not self.triggered: if phraseId == helpPhrase and not self.triggered:
self.triggered = True self.triggered = True
self.attemptScavengerHunt() self.attemptScavengerHunt()
# self.ignore(SpeedChatGlobals.SCCustomMsgEvent)
taskMgr.doMethodLater(self.triggerDelay, reset, 'ScavengerHunt-phrase-reset', extraArgs=[]) taskMgr.doMethodLater(self.triggerDelay, reset, 'ScavengerHunt-phrase-reset', extraArgs=[])
def announceGenerate(self): def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self) DistributedObject.DistributedObject.announceGenerate(self)
DistributedScavengerHuntTarget.notify.debug('announceGenerate') DistributedScavengerHuntTarget.notify.debug('announceGenerate')
self.setupListenerDetails() self.setupListenerDetails()
def delete(self): def delete(self):
# stop listening to speed chat
self.ignoreAll() self.ignoreAll()
taskMgr.remove('ScavengerHunt-phrase-reset') taskMgr.remove('ScavengerHunt-phrase-reset')
DistributedObject.DistributedObject.delete(self) DistributedObject.DistributedObject.delete(self)
# do the event
def attemptScavengerHunt(self): def attemptScavengerHunt(self):
DistributedScavengerHuntTarget.notify.debug('attempScavengerHunt') self.notify.debug("attemptScavengerHunt()")
self.sendUpdate('attemptScavengerHunt', []) self.sendUpdate('attemptScavengerHunt', [])

View File

@ -1,9 +1,10 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.ai import DistributedPhaseEventMgr from toontown.ai import DistributedPhaseEventMgr
import time import time
class DistributedSillyMeterMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr): class DistributedSillyMeterMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the SillyOMeter"""
neverDisable = 1 neverDisable = 1
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSillyMeterMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSillyMeterMgr')
@ -12,44 +13,51 @@ class DistributedSillyMeterMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr
cr.SillyMeterMgr = self cr.SillyMeterMgr = self
def announceGenerate(self): def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('SillyMeterIsRunning', [self.isRunning]) messenger.send('SillyMeterIsRunning', [self.isRunning])
def delete(self): def delete(self):
self.notify.debug('deleting SillyMetermgr') self.notify.debug("deleting SillyMetermgr")
messenger.send('SillyMeterIsRunning', [False]) messenger.send('SillyMeterIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'SillyMeterMgr'): if hasattr(self.cr, "SillyMeterMgr"):
del self.cr.SillyMeterMgr del self.cr.SillyMeterMgr
def setCurPhase(self, newPhase): def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the silly meter."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('SillyMeterPhase', [newPhase]) messenger.send('SillyMeterPhase', [newPhase])
def setIsRunning(self, isRunning): def setIsRunning(self, isRunning):
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('SillyMeterIsRunning', [isRunning]) messenger.send('SillyMeterIsRunning', [isRunning])
def getCurPhaseDuration(self): def getCurPhaseDuration(self):
"""return the duration in time of the current phase"""
if len(self.holidayDates) > 0: if len(self.holidayDates) > 0:
startHolidayDate = self.holidayDates[self.curPhase] startHolidayDate = self.holidayDates[self.curPhase]
if self.curPhase + 1 >= len(self.holidayDates): if (self.curPhase + 1) >= len(self.holidayDates):
self.notify.error('No end date for phase %' % self.curPhase) self.notify.error(f"No end date for phase {self.curPhase}")
return -1 return -1
else: else:
endHolidayDate = self.holidayDates[self.curPhase + 1] endHolidayDate = self.holidayDates[(self.curPhase + 1)]
startHolidayTime = time.mktime(startHolidayDate.timetuple()) startHolidayTime = time.mktime(startHolidayDate.timetuple())
endHolidayTime = time.mktime(endHolidayDate.timetuple()) endHolidayTime = time.mktime(endHolidayDate.timetuple())
holidayDuration = endHolidayTime - startHolidayTime holidayDuration = endHolidayTime - startHolidayTime
if holidayDuration < 0: if holidayDuration < 0:
self.notify.error('Duration not set for phase %' % self.curPhase) self.notify.error(f"Duration not set for phase {self.curPhase}")
return -1 return -1
else: else:
return holidayDuration return holidayDuration
else: else:
self.notify.warning('Phase dates not yet known') self.notify.warning("Phase dates not yet known")
return -1 return -1
def getCurPhaseStartDate(self): def getCurPhaseStartDate(self):
"""return the start date of the current phase"""
if len(self.holidayDates) > 0: if len(self.holidayDates) > 0:
return self.holidayDates[self.curPhase] return self.holidayDates[self.curPhase]

View File

@ -1,29 +1,40 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import DistributedPhaseEventMgr from toontown.ai import DistributedPhaseEventMgr
class DistributedTrashcanZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr): class DistributedTrashcanZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the trashcan zero manager"""
neverDisable = 1 neverDisable = 1
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTrashcanZeroMgr') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTrashcanZeroMgr')
# tempted to change this to have mailbox, hydrant, and trashcan as fields
# but for holiday and magic word convenience, we'll use 3 separate classes
def __init__(self, cr): def __init__(self, cr):
DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr) DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr)
cr.trashcanZeroMgr = self cr.trashcanZeroMgr = self
def announceGenerate(self): def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('trashcanZeroIsRunning', [self.isRunning]) messenger.send('trashcanZeroIsRunning', [self.isRunning])
def delete(self): def delete(self):
self.notify.debug('deleting trashcanzeromgr') self.notify.debug("Deleting TrashcanZeroMgr")
messenger.send('trashcanZeroIsRunning', [False]) messenger.send('trashcanZeroIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self) DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'trashcanZeroMgr'): if hasattr(self.cr, "trashcanZeroMgr"):
del self.cr.trashcanZeroMgr del self.cr.trashcanZeroMgr
def setCurPhase(self, newPhase): def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the trashcans."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('trashcanZeroPhase', [newPhase]) messenger.send('trashcanZeroPhase', [newPhase])
def setIsRunning(self, isRunning): def setIsRunning(self, isRunning):
"""We've gotten a new phase lets, tell the trashcans."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning) DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('trashcanZeroIsRunning', [isRunning]) messenger.send('trashcanZeroIsRunning', [isRunning])

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObjectAI
from toontown.ai import DistributedPhaseEventMgrAI from toontown.ai import DistributedPhaseEventMgrAI
class DistributedTrashcanZeroMgrAI(DistributedPhaseEventMgrAI.DistributedPhaseEventMgrAI): class DistributedTrashcanZeroMgrAI(DistributedPhaseEventMgrAI.DistributedPhaseEventMgrAI):

View File

@ -1,15 +1,22 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from . import DistributedScavengerHuntTarget from . import DistributedScavengerHuntTarget
class DistributedTrickOrTreatTarget(DistributedScavengerHuntTarget.DistributedScavengerHuntTarget): class DistributedTrickOrTreatTarget(DistributedScavengerHuntTarget.DistributedScavengerHuntTarget):
"""
Upon hearing the 'Trick or Treat!' phrase, it stops listening for
a few seconds in order to screen repeated attempts during high lag periods.
"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTrickOrTreatTarget') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedTrickOrTreatTarget')
def __init__(self, cr): def __init__(self, cr):
DistributedScavengerHuntTarget.DistributedScavengerHuntTarget.__init__(self, cr) DistributedScavengerHuntTarget.DistributedScavengerHuntTarget.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId): def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said') self.notify.debug("Checking if phrase was said")
helpPhrase = 10003 helpPhrase = 10003 # 'Trick or Treat!'
def reset(): def reset():
self.triggered = False self.triggered = False

View File

@ -1,9 +1,14 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.speedchat.TTSCIndexedTerminal import TTSCIndexedMsgEvent from toontown.speedchat.TTSCIndexedTerminal import TTSCIndexedMsgEvent
from . import DistributedScavengerHuntTarget from . import DistributedScavengerHuntTarget
class DistributedWinterCarolingTarget(DistributedScavengerHuntTarget.DistributedScavengerHuntTarget): class DistributedWinterCarolingTarget(DistributedScavengerHuntTarget.DistributedScavengerHuntTarget):
"""
Upon hearing a musical phrase, it stops listening for
a few seconds in order to screen repeated attempts during high lag periods.
"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedWinterCarolingTarget') notify = DirectNotifyGlobal.directNotify.newCategory('DistributedWinterCarolingTarget')
def __init__(self, cr): def __init__(self, cr):
@ -11,14 +16,16 @@ class DistributedWinterCarolingTarget(DistributedScavengerHuntTarget.Distributed
def setupListenerDetails(self): def setupListenerDetails(self):
self.triggered = False self.triggered = False
self.triggerDelay = 15 self.triggerDelay = 15 # Seconds to disable the listener
self.accept(TTSCIndexedMsgEvent, self.phraseSaid) self.accept(TTSCIndexedMsgEvent, self.phraseSaid)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId): def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said') self.notify.debug("Checking if phrase was said")
helpPhrases = [] helpPhrases = []
for i in range(6): for i in range(6):
helpPhrases.append(30220 + i) helpPhrases.append(60220 + i)
def reset(): def reset():
self.triggered = False self.triggered = False

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObjectAI
from . import DistributedScavengerHuntTargetAI from . import DistributedScavengerHuntTargetAI
class DistributedWinterCarolingTargetAI(DistributedScavengerHuntTargetAI.DistributedScavengerHuntTargetAI): class DistributedWinterCarolingTargetAI(DistributedScavengerHuntTargetAI.DistributedScavengerHuntTargetAI):
@ -13,8 +12,7 @@ class DistributedWinterCarolingTargetAI(DistributedScavengerHuntTargetAI.Distrib
'DistributedScavengerHuntTargetAI') 'DistributedScavengerHuntTargetAI')
def __init__(self, air, hunt, goal, totMgr): def __init__(self, air, hunt, goal, totMgr):
DistributedScavengerHuntTargetAI.DistributedScavengerHuntTargetAI.__init__(self, \ DistributedScavengerHuntTargetAI.DistributedScavengerHuntTargetAI.__init__(self, air, hunt, goal, totMgr)
air, hunt, goal, totMgr)
def attemptScavengerHunt(self): def attemptScavengerHunt(self):
avId = self.air.getAvatarIdFromSender() avId = self.air.getAvatarIdFromSender()

View File

@ -1,6 +1,5 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
from toontown.ai import DistributedGreenToonEffectMgrAI from toontown.ai import DistributedGreenToonEffectMgrAI
EVENT_ZONE = 5819 # 'Green Bean Jeans' interior EVENT_ZONE = 5819 # 'Green Bean Jeans' interior

View File

@ -1,107 +1,180 @@
#################################################
# Halloween decorator class for non-dna based
# decoration changes to hoods
#################################################
# Panda3D imports
from panda3d.core import Vec4, CSDefault from panda3d.core import Vec4, CSDefault
from panda3d.toontown import loadDNAFile from panda3d.toontown import loadDNAFile
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import * from direct.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import * from direct.interval.IntervalGlobal import *
from . import HolidayDecorator from . import HolidayDecorator
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals
from toontown.safezone import Playground from toontown.safezone import Playground
from toontown.town import Street from toontown.town import Street
from toontown.estate import Estate from toontown.estate import Estate
class HalloweenHolidayDecorator(HolidayDecorator.HolidayDecorator): class HalloweenHolidayDecorator(HolidayDecorator.HolidayDecorator):
notify = DirectNotifyGlobal.directNotify.newCategory('HalloweenHolidayDecorator') notify = DirectNotifyGlobal.directNotify.newCategory('HalloweenHolidayDecorator')
def __init__(self): def __init__(self):
HolidayDecorator.HolidayDecorator.__init__(self) HolidayDecorator.HolidayDecorator.__init__(self)
#####################################################
# Function that checks the validity of a street,
# it's loader and the geometry
#####################################################
def __checkStreetValidity(self): def __checkStreetValidity(self):
if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace() and isinstance(base.cr.playGame.getPlace(), Street.Street) and hasattr(base.cr.playGame.getPlace(), 'loader') and base.cr.playGame.getPlace().loader and hasattr(base.cr.playGame.getPlace().loader, 'geom') and base.cr.playGame.getPlace().loader.geom: if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and \
isinstance(base.cr.playGame.getPlace(), Street.Street) and \
hasattr(base.cr.playGame.getPlace(), "loader") and base.cr.playGame.getPlace().loader \
and hasattr(base.cr.playGame.getPlace().loader, "geom") and base.cr.playGame.getPlace().loader.geom:
return True return True
else: else:
if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace(): if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace():
self.notify.debug('Failed Street Check %s' % base.cr.playGame.getPlace()) self.notify.debug("Failed Street Check %s" % base.cr.playGame.getPlace())
else: else:
self.notify.debug('Failed Street Check') self.notify.debug("Failed Street Check")
return False return False
#####################################################
# Function that checks the validity of a hood,
# it's loader and the geometry
#####################################################
def __checkHoodValidity(self): def __checkHoodValidity(self):
if (hasattr(base.cr.playGame, 'getPlace') and if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and \
base.cr.playGame.getPlace() and (isinstance(base.cr.playGame.getPlace(), Playground.Playground) or isinstance(
(isinstance(base.cr.playGame.getPlace(), Playground.Playground) or base.cr.playGame.getPlace(), Estate.Estate)) and \
isinstance(base.cr.playGame.getPlace(), Estate.Estate)) and hasattr(base.cr.playGame.getPlace(), "loader") and base.cr.playGame.getPlace().loader and \
hasattr(base.cr.playGame.getPlace(), 'loader') and hasattr(base.cr.playGame.getPlace().loader, "hood") and base.cr.playGame.getPlace().loader.hood and \
base.cr.playGame.getPlace().loader and hasattr(base.cr.playGame.getPlace().loader.hood,
hasattr(base.cr.playGame.getPlace().loader, 'hood') and "loader") and base.cr.playGame.getPlace().loader.hood.loader \
base.cr.playGame.getPlace().loader.hood and and hasattr(base.cr.playGame.getPlace().loader.hood.loader,
hasattr(base.cr.playGame.getPlace().loader.hood, 'loader') and "geom") and base.cr.playGame.getPlace().loader.hood.loader.geom:
base.cr.playGame.getPlace().loader.hood.loader and return True
hasattr(base.cr.playGame.getPlace().loader.hood.loader, 'geom') and
base.cr.playGame.getPlace().loader.hood.loader.geom):
return True
else: else:
if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace(): if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace():
self.notify.debug('Failed Hood Check %s' % base.cr.playGame.getPlace()) self.notify.debug("Failed Hood Check %s" % base.cr.playGame.getPlace())
else: else:
self.notify.debug('Failed Hood Check') self.notify.debug("Failed Hood Check")
return False return False
#####################################################
# This function safely calls startSpookySky
# for the halloween holiday
#####################################################
def __startSpookySky(self): def __startSpookySky(self):
if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky: if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, "sky") \
and base.cr.playGame.hood.sky:
base.cr.playGame.hood.startSpookySky() base.cr.playGame.hood.startSpookySky()
####################################################
# This function safely calls stopSpookySky
# for the halloween holiday
####################################################
def __stopSpookySky(self): def __stopSpookySky(self):
if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky: if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, "sky") \
and base.cr.playGame.hood.sky:
base.cr.playGame.hood.endSpookySky() base.cr.playGame.hood.endSpookySky()
def decorate(self): def decorate(self):
# Load the specified seasonal storage file
self.updateHoodDNAStore() self.updateHoodDNAStore()
self.swapIval = self.getSwapVisibleIval() self.swapIval = self.getSwapVisibleIval()
if self.swapIval: if self.swapIval:
self.swapIval.start() self.swapIval.start()
def __lightDecorationOn__(): def __lightDecorationOn__():
# import pdb; pdb.set_trace()
place = base.cr.playGame.getPlace() place = base.cr.playGame.getPlace()
if hasattr(place, 'halloweenLights'): if hasattr(place, "halloweenLights"):
if not self.__checkStreetValidity(): if not self.__checkStreetValidity():
return return
else: else:
place.halloweenLights = place.loader.geom.findAllMatches('**/*light*') place.halloweenLights = place.loader.geom.findAllMatches("**/*light*")
place.halloweenLights += place.loader.geom.findAllMatches('**/*lamp*') place.halloweenLights += place.loader.geom.findAllMatches("**/*lamp*")
place.halloweenLights += place.loader.geom.findAllMatches('**/prop_snow_tree*') place.halloweenLights += place.loader.geom.findAllMatches("**/prop_snow_tree*")
for light in place.halloweenLights: for light in place.halloweenLights:
light.setColorScaleOff(0) light.setColorScaleOff(0)
elif not self.__checkHoodValidity():
return
else: else:
place.loader.hood.halloweenLights = place.loader.hood.loader.geom.findAllMatches('**/*light*') if not self.__checkHoodValidity():
place.loader.hood.halloweenLights += place.loader.hood.loader.geom.findAllMatches('**/*lamp*') return
place.loader.hood.halloweenLights += place.loader.hood.loader.geom.findAllMatches('**/prop_snow_tree*') else:
for light in place.loader.hood.halloweenLights: place.loader.hood.halloweenLights = place.loader.hood.loader.geom.findAllMatches("**/*light*")
light.setColorScaleOff(0) place.loader.hood.halloweenLights += place.loader.hood.loader.geom.findAllMatches("**/*lamp*")
place.loader.hood.halloweenLights += place.loader.hood.loader.geom.findAllMatches(
"**/prop_snow_tree*")
for light in place.loader.hood.halloweenLights:
light.setColorScaleOff(0)
holidayIds = base.cr.newsManager.getDecorationHolidayId() holidayIds = base.cr.newsManager.getDecorationHolidayId()
if ToontownGlobals.HALLOWEEN_COSTUMES not in holidayIds and ToontownGlobals.SPOOKY_COSTUMES not in holidayIds: if ToontownGlobals.HALLOWEEN_COSTUMES not in holidayIds:
return return
if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame, 'hood') and base.cr.playGame.hood and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky: # Fixes transition related crashes
preShow = Sequence(Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 1.5, Vec4(1, 1, 1, 0.25)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(0.55, 0.55, 0.65, 1)), Func(__lightDecorationOn__)), Func(self.__startSpookySky)) if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame, "hood") \
and base.cr.playGame.hood and hasattr(base.cr.playGame.hood, "sky") \
and base.cr.playGame.hood.sky:
preShow = Sequence(
Parallel(
LerpColorScaleInterval(
base.cr.playGame.hood.sky,
1.5, Vec4(1, 1, 1, 0.25)
),
LerpColorScaleInterval(
base.cr.playGame.hood.loader.geom,
2.5,
Vec4(0.55, 0.55, 0.65, 1)
),
Func(__lightDecorationOn__),
),
Func(self.__startSpookySky),
)
preShow.start() preShow.start()
distributedEstate = base.cr.doFind('DistributedEstate')
# Replace the plane with the witch in the estate
distributedEstate = base.cr.doFind("DistributedEstate")
if distributedEstate: if distributedEstate:
distributedEstate.loadWitch() distributedEstate.loadWitch()
def undecorate(self): def undecorate(self):
if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, 'sky') and base.cr.playGame.hood.sky:
postShow = Sequence(Parallel(LerpColorScaleInterval(base.cr.playGame.hood.sky, 1.5, Vec4(1, 1, 1, 1)), LerpColorScaleInterval(base.cr.playGame.hood.loader.geom, 2.5, Vec4(1, 1, 1, 1))), Func(self.__stopSpookySky)) # Fixes transition related crashes
if (self.__checkHoodValidity() or self.__checkStreetValidity()) and hasattr(base.cr.playGame.hood, "sky") \
and base.cr.playGame.hood.sky:
postShow = Sequence(
Parallel(
LerpColorScaleInterval(
base.cr.playGame.hood.sky,
1.5, Vec4(1, 1, 1, 1)
),
LerpColorScaleInterval(
base.cr.playGame.hood.loader.geom,
2.5,
Vec4(1, 1, 1, 1)
),
),
Func(self.__stopSpookySky),
)
postShow.start() postShow.start()
distributedEstate = base.cr.doFind('DistributedEstate')
# Replace the witch with the plane
distributedEstate = base.cr.doFind("DistributedEstate")
if distributedEstate: if distributedEstate:
distributedEstate.unloadWitch() distributedEstate.unloadWitch()
# if there are any other decoration holidays running
holidayIds = base.cr.newsManager.getDecorationHolidayId() holidayIds = base.cr.newsManager.getDecorationHolidayId()
if len(holidayIds) > 0: if len(holidayIds) > 0:
self.decorate() self.decorate()
return return
# Reload the regular storage file
storageFile = base.cr.playGame.hood.storageDNAFile storageFile = base.cr.playGame.hood.storageDNAFile
if storageFile: if storageFile:
loadDNAFile(self.dnaStore, storageFile, CSDefault) loadDNAFile(self.dnaStore, storageFile, CSDefault)

View File

@ -1,7 +1,3 @@
from direct.directnotify import DirectNotifyGlobal
import random
from direct.task import Task
from toontown.effects import DistributedFireworkShowAI
class HolidayBaseAI: class HolidayBaseAI:
""" """

View File

@ -1,30 +1,31 @@
from panda3d.core import CSDefault, NodePath, TransformState, TransparencyAttrib, Vec4 from panda3d.core import CSDefault, NodePath, TransformState, TransparencyAttrib, Vec4
from toontown.toonbase import ToontownGlobals
from direct.interval.IntervalGlobal import Parallel, Sequence, Func, Wait from direct.interval.IntervalGlobal import Parallel, Sequence, Func, Wait
class HolidayDecorator: class HolidayDecorator:
def __init__(self): def __init__(self):
self.dnaStore = base.cr.playGame.dnaStore self.dnaStore = base.cr.playGame.dnaStore
self.swapIval = None self.swapIval = None
return
def exit(self): def exit(self):
if self.swapIval is not None and self.swapIval.isPlaying(): if (self.swapIval is not None) and self.swapIval.isPlaying():
self.swapIval.finish() self.swapIval.finish()
return
def decorate(self): def decorate(self):
# Load the specified seasonal storage file
self.updateHoodDNAStore() self.updateHoodDNAStore()
self.swapIval = self.getSwapVisibleIval() self.swapIval = self.getSwapVisibleIval()
if self.swapIval: if self.swapIval:
self.swapIval.start() self.swapIval.start()
def undecorate(self): def undecorate(self):
# if there are any other decoration holidays running
holidayIds = base.cr.newsManager.getDecorationHolidayId() holidayIds = base.cr.newsManager.getDecorationHolidayId()
if len(holidayIds) > 0: if len(holidayIds) > 0:
self.decorate() self.decorate()
return return
# Reload the regular storage file
storageFile = base.cr.playGame.hood.storageDNAFile storageFile = base.cr.playGame.hood.storageDNAFile
if storageFile: if storageFile:
loadDNAFile(self.dnaStore, storageFile, CSDefault) loadDNAFile(self.dnaStore, storageFile, CSDefault)
@ -33,14 +34,17 @@ class HolidayDecorator:
self.swapIval.start() self.swapIval.start()
def updateHoodDNAStore(self): def updateHoodDNAStore(self):
# Load the specified storage files for this hood to overwrite
# DNA storage with seasonal specific files
hood = base.cr.playGame.hood hood = base.cr.playGame.hood
holidayIds = base.cr.newsManager.getDecorationHolidayId() holidayIds = base.cr.newsManager.getDecorationHolidayId()
for holiday in holidayIds: for holiday in holidayIds:
for storageFile in hood.holidayStorageDNADict.get(holiday, []): for storageFile in hood.holidayStorageDNADict.get(holiday, []):
loadDNAFile(self.dnaStore, storageFile, CSDefault) loadDNAFile(self.dnaStore, storageFile, CSDefault)
def getSwapVisibleIval(self, wait = 5.0, tFadeOut = 3.0, tFadeIn = 3.0): def getSwapVisibleIval(self, wait=5.0, tFadeOut=3.0, tFadeIn=3.0):
loader = base.cr.playGame.hood.loader loader = base.cr.playGame.hood.loader
# Update all visible holiday props
npl = render.findAllMatches('**/=DNARoot=holiday_prop;+s') npl = render.findAllMatches('**/=DNARoot=holiday_prop;+s')
p = Parallel() p = Parallel()
for i in range(npl.getNumPaths()): for i in range(npl.getNumPaths()):
@ -52,17 +56,31 @@ class HolidayDecorator:
dnaNode = self.dnaStore.findNode(dnaCode) dnaNode = self.dnaStore.findNode(dnaCode)
if dnaNode.isEmpty(): if dnaNode.isEmpty():
continue continue
# Add new
newNP = dnaNode.copyTo(np.getParent()) newNP = dnaNode.copyTo(np.getParent())
newNP.setTag('DNARoot', 'holiday_prop') newNP.setTag('DNARoot', 'holiday_prop')
newNP.setTag('DNACode', dnaCode) newNP.setTag('DNACode', dnaCode)
newNP.setColorScale(1, 1, 1, 0) newNP.setColorScale(1, 1, 1, 0)
newNP.setTransparency(TransparencyAttrib.MDual, 1) newNP.setTransparency(TransparencyAttrib.MDual, 1)
# Set transform to match old node paths transform
if np.hasTag('transformIndex'): if np.hasTag('transformIndex'):
index = int(np.getTag('transformIndex')) index = int(np.getTag('transformIndex'))
transform = loader.holidayPropTransforms.get(index, TransformState.makeIdentity()) transform = loader.holidayPropTransforms.get(index, TransformState.makeIdentity())
# Position relative to empty node path *just in case* render not top of scene graph
newNP.setTransform(NodePath(), transform) newNP.setTransform(NodePath(), transform)
newNP.setTag('transformIndex', repr(index))
s = Sequence(Wait(wait), np.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 0), startColorScale=Vec4(1, 1, 1, 1), blendType='easeInOut'), Func(np.detachNode), Func(np.clearTransparency), newNP.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 1), startColorScale=Vec4(1, 1, 1, 0), blendType='easeInOut'), Func(newNP.clearTransparency), Func(newNP.clearColorScale))
p.append(s)
newNP.setTag('transformIndex', index)
s = Sequence(Wait(wait),
np.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 0),
startColorScale=Vec4(1, 1, 1, 1),
blendType='easeInOut'),
Func(np.detachNode),
Func(np.clearTransparency),
newNP.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 1),
startColorScale=Vec4(1, 1, 1, 0),
blendType='easeInOut'),
Func(newNP.clearTransparency),
Func(newNP.clearColorScale),
)
p.append(s)
return p return p

View File

@ -5,7 +5,6 @@
################################################################# #################################################################
# Python Specific Modules # Python Specific Modules
################################################################# #################################################################
import random
import time import time
################################################################# #################################################################

View File

@ -11,7 +11,6 @@ from toontown.ai.HolidayInfo import *
################################################################# #################################################################
# Python Specific Modules # Python Specific Modules
################################################################# #################################################################
import random
import time import time
################################################################# #################################################################

View File

@ -54,7 +54,6 @@ from panda3d.core import ConfigVariableString
################################################################# #################################################################
# Python Specific Modules # Python Specific Modules
################################################################# #################################################################
import random
import time import time
import enum import enum

View File

@ -1,8 +1,5 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.ai import PropBuffHolidayAI from toontown.ai import PropBuffHolidayAI
from toontown.ai import DistributedPhaseEventMgrAI
from toontown.toonbase import ToontownGlobals
class HydrantBuffHolidayAI(PropBuffHolidayAI.PropBuffHolidayAI): class HydrantBuffHolidayAI(PropBuffHolidayAI.PropBuffHolidayAI):

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.ai import PhasedHolidayAI from toontown.ai import PhasedHolidayAI
from toontown.ai import DistributedHydrantZeroMgrAI from toontown.ai import DistributedHydrantZeroMgrAI
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals

View File

@ -1,8 +1,5 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.ai import PropBuffHolidayAI from toontown.ai import PropBuffHolidayAI
from toontown.ai import DistributedPhaseEventMgrAI
from toontown.toonbase import ToontownGlobals
class MailboxBuffHolidayAI(PropBuffHolidayAI.PropBuffHolidayAI): class MailboxBuffHolidayAI(PropBuffHolidayAI.PropBuffHolidayAI):

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.ai import PhasedHolidayAI from toontown.ai import PhasedHolidayAI
from toontown.ai import DistributedMailboxZeroMgrAI from toontown.ai import DistributedMailboxZeroMgrAI
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals

View File

@ -1,9 +1,6 @@
import datetime import datetime
import time
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
from toontown.ai import DistributedResistanceEmoteMgrAI
class StartAndEndTime: class StartAndEndTime:

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.ai import PhasedHolidayAI from toontown.ai import PhasedHolidayAI
from toontown.ai import DistributedPhaseEventMgrAI from toontown.ai import DistributedPhaseEventMgrAI
from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownGlobals

View File

@ -1,6 +1,5 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
from toontown.ai import DistributedResistanceEmoteMgrAI from toontown.ai import DistributedResistanceEmoteMgrAI
EVENT_ZONE = 9720 # 'Talking in Your Sleep Voiceover Training' interior EVENT_ZONE = 9720 # 'Talking in Your Sleep Voiceover Training' interior

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.toonbase import ToontownGlobals, TTLocalizer
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
class RoamingTrialerWeekendMgrAI(HolidayBaseAI.HolidayBaseAI): class RoamingTrialerWeekendMgrAI(HolidayBaseAI.HolidayBaseAI):

View File

@ -1,38 +1,42 @@
"""ServerEventBuffer: buffers up information for multiple server events and writes single event"""
class ServerEventBuffer: class ServerEventBuffer:
"""Buffers up events that you want to be logged in the server event log."""
def __init__(self, air, name, avId, period = None): def __init__(self, air, name, avId, period=None):
# name is the name of the event that we'll be writing to the server
# period in minutes
self.air = air self.air = air
self.name = name self.name = name
self.avId = avId self.avId = avId
if period is None: if period is None:
period = 6 * 60.0 # every 6 hours
period = 6*60.
self.period = period self.period = period
self.lastFlushTime = None self.lastFlushTime = None
return
def destroy(self): def destroy(self):
self.flush() self.flush()
def flush(self): def flush(self):
# subclasses, override this and call down
self.lastFlushTime = None self.lastFlushTime = None
return
def writeEvent(self, msg): def writeEvent(self, msg):
self.air.writeServerEvent(self.name, self.avId, msg) self.air.writeServerEvent(self.name, self.avId, msg)
def considerFlush(self): def considerFlush(self):
# if we haven't logged in a while, don't immediately flush out the
# first event
if self.lastFlushTime is None: if self.lastFlushTime is None:
self.lastFlushTime = globalClock.getFrameTime() self.lastFlushTime = globalClock.getFrameTime()
elif globalClock.getFrameTime() - self.lastFlushTime > self.period * 60.0: elif ((globalClock.getFrameTime() - self.lastFlushTime) >
(self.period*60.)):
self.flush() self.flush()
return
class ServerEventAccumulator(ServerEventBuffer): class ServerEventAccumulator(ServerEventBuffer):
# counts # of times a particular event occurs
def __init__(self, air, name, avId, period = None): def __init__(self, air, name, avId, period=None):
ServerEventBuffer.__init__(self, air, name, avId, period) ServerEventBuffer.__init__(self, air, name, avId, period)
self.count = 0 self.count = 0
@ -40,7 +44,7 @@ class ServerEventAccumulator(ServerEventBuffer):
ServerEventBuffer.flush(self) ServerEventBuffer.flush(self)
if not self.count: if not self.count:
return return
self.writeEvent('%s' % self.count) self.writeEvent("%s" % self.count)
self.count = 0 self.count = 0
def addEvent(self): def addEvent(self):
@ -49,23 +53,23 @@ class ServerEventAccumulator(ServerEventBuffer):
class ServerEventMultiAccumulator(ServerEventBuffer): class ServerEventMultiAccumulator(ServerEventBuffer):
# counts # of times multiple related events occur
def __init__(self, air, name, avId, period = None): def __init__(self, air, name, avId, period=None):
ServerEventBuffer.__init__(self, air, name, avId, period) ServerEventBuffer.__init__(self, air, name, avId, period)
# eventName:count
self.events = {} self.events = {}
def flush(self): def flush(self):
ServerEventBuffer.flush(self) ServerEventBuffer.flush(self)
if not len(self.events): if not len(self.events):
return return
msg = '' msg = ""
eventNames = list(self.events.keys()) eventNames = list(self.events.keys())
eventNames.sort() eventNames.sort()
for eventName in eventNames: for eventName in eventNames:
msg += '%s:%s' % (eventName, self.events[eventName]) msg += "%s:%s" % (eventName, self.events[eventName])
if eventName != eventNames[-1]: if eventName != eventNames[-1]:
msg += ',' msg += ','
self.writeEvent(msg) self.writeEvent(msg)
self.events = {} self.events = {}

View File

@ -1,5 +1,4 @@
from direct.directnotify import DirectNotifyGlobal from direct.directnotify import DirectNotifyGlobal
from toontown.toonbase import ToontownGlobals, TTLocalizer
from toontown.ai import HolidayBaseAI from toontown.ai import HolidayBaseAI
class ValentinesDayMgrAI(HolidayBaseAI.HolidayBaseAI): class ValentinesDayMgrAI(HolidayBaseAI.HolidayBaseAI):