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 toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
class BlackCatHolidayMgrAI(HolidayBaseAI.HolidayBaseAI):
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.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import *
from . import HolidayDecorator
from toontown.toonbase import ToontownGlobals
from toontown.hood import GSHood

View File

@ -3,18 +3,28 @@ from direct.distributed import DistributedObject
from direct.interval.IntervalGlobal import *
from toontown.effects import DustCloud
def getDustCloudIval(toon):
dustCloud = DustCloud.DustCloud(fBillboard=0)
dustCloud.setBillboardAxis(2.0)
dustCloud.setBillboardAxis(2)
dustCloud.setZ(3)
dustCloud.setScale(0.4)
dustCloud.createTrack()
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):
"""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')
ActivateEvent = 'DistributedBlackCatMgr-activate'
def __init__(self, cr):
@ -24,11 +34,11 @@ class DistributedBlackCatMgr(DistributedObject.DistributedObject):
self.avId = avId
def announceGenerate(self):
DistributedBlackCatMgr.notify.debug('announceGenerate')
self.notify.debug("announceGenerate()")
DistributedObject.DistributedObject.announceGenerate(self)
self.acceptOnce(DistributedBlackCatMgr.ActivateEvent, self.doBlackCatTransformation)
self.acceptOnce(DistributedBlackCatMgr.ActivateEvent,
self.doBlackCatTransformation)
self.dustCloudIval = None
return
def delete(self):
if self.dustCloudIval:
@ -38,14 +48,19 @@ class DistributedBlackCatMgr(DistributedObject.DistributedObject):
DistributedObject.DistributedObject.delete(self)
def doBlackCatTransformation(self):
DistributedBlackCatMgr.notify.debug('doBlackCatTransformation')
self.notify.debug("doBlackCatTransformation()")
toon = base.cr.doId2do[self.avId]
if not toon:
DistributedBlackCatMgr.notify.warning("couldn't find Toon %s" % self.avId)
self.notify.warning(f"Couldn't find Toon {self.avId}")
return
# are they a 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
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.start()

View File

@ -5,6 +5,8 @@ from otp.speedchat import SpeedChatGlobals
from toontown.toonbase import TTLocalizer
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')
def __init__(self, cr):
@ -19,14 +21,14 @@ class DistributedGreenToonEffectMgr(DistributedObject.DistributedObject):
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
DistributedGreenToonEffectMgr.notify.debug('announceGenerate')
self.notify.debug("announceGenerate()")
def delete(self):
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self)
def addGreenToonEffect(self):
DistributedGreenToonEffectMgr.notify.debug('addGreenToonEffect')
self.notify.debug("addGreenToonEffect()")
av = base.localAvatar
self.sendUpdate('addGreenToonEffect', [])
msgTrack = Sequence(Func(av.setSystemMessage, 0, TTLocalizer.GreenToonEffectMsg))

View File

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

View File

@ -1,30 +1,39 @@
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.ai import DistributedPhaseEventMgr
class DistributedMailboxZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the mailbox zero manager"""
neverDisable = 1
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):
DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr)
cr.mailboxZeroMgr = self
def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('mailboxZeroIsRunning', [self.isRunning])
def delete(self):
self.notify.debug('deleting mailboxzeromgr')
self.notify.debug("deleting mailboxzeromgr")
messenger.send('mailboxZeroIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'mailboxZeroMgr'):
if hasattr(self.cr, "mailboxZeroMgr"):
del self.cr.mailboxZeroMgr
def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the mailboxs."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('mailboxZeroPhase', [newPhase])
def setIsRunning(self, isRunning):
"""We've gotten a new phase lets, tell the mailboxs."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('mailboxZeroIsRunning', [isRunning])

View File

@ -2,7 +2,9 @@ from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
import datetime
class DistributedPhaseEventMgr(DistributedObject.DistributedObject):
"""Base Class to manage the hydrant/mailbox/trashcan zero manager"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPhaseEventMgr')
def __init__(self, cr):
@ -28,5 +30,10 @@ class DistributedPhaseEventMgr(DistributedObject.DistributedObject):
return self.curPhase
def setDates(self, holidayDates):
"""
Provide the client with the phase date information
"""
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 toontown.toonbase import TTLocalizer
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')
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(phraseId):
helpPhrase = 104
if phraseId == helpPhrase:
@ -19,15 +24,24 @@ class DistributedPolarPlaceEffectMgr(DistributedObject.DistributedObject):
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
DistributedPolarPlaceEffectMgr.notify.debug('announceGenerate')
self.notify.debug("announceGenerate()")
def delete(self):
# stop listening to speed chat
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self)
# do the event
def addPolarPlaceEffect(self):
DistributedPolarPlaceEffectMgr.notify.debug('addResitanceEffect')
self.notify.debug("addPolarPlaceEffect()")
av = base.localAvatar
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()

View File

@ -4,14 +4,19 @@ from direct.interval.IntervalGlobal import *
from otp.speedchat import SpeedChatGlobals
from otp.otpbase.OTPLocalizerEnglish import EmoteFuncDict
from toontown.toonbase import TTLocalizer
RESIST_INDEX = EmoteFuncDict['Resistance Salute']
RESIST_INDEX = EmoteFuncDict["Resistance Salute"]
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')
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(phraseId):
helpPhrase = 513
if phraseId == helpPhrase:
@ -21,16 +26,27 @@ class DistributedResistanceEmoteMgr(DistributedObject.DistributedObject):
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
DistributedResistanceEmoteMgr.notify.debug('announceGenerate')
self.notify.debug("announceGenerate()")
def delete(self):
# stop listening to speed chat
self.ignore(SpeedChatGlobals.SCStaticTextMsgEvent)
DistributedObject.DistributedObject.delete(self)
# do the event
def addResistanceEmote(self):
DistributedResistanceEmoteMgr.notify.debug('addResitanceEmote')
self.notify.debug("addResistanceEmote()")
av = base.localAvatar
# make sure they haven't already done this
if not av.emoteAccess[RESIST_INDEX]:
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()

View File

@ -2,7 +2,13 @@ from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from otp.speedchat import SpeedChatGlobals
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')
def __init__(self, cr):
@ -10,31 +16,38 @@ class DistributedScavengerHuntTarget(DistributedObject.DistributedObject):
def setupListenerDetails(self):
self.triggered = False
self.triggerDelay = 15
self.triggerDelay = 15 # Seconds to disable the listener
self.accept(SpeedChatGlobals.SCCustomMsgEvent, self.phraseSaid)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said')
helpPhrase = 10003
self.notify.debug("Checking if phrase was said")
helpPhrase = 10003 # 'Trick or Treat!'
def reset():
self.triggered = False
# self.accept(SpeedChatGlobals.SCCustomMsgEvent, phraseSaid)
if phraseId == helpPhrase and not self.triggered:
self.triggered = True
self.attemptScavengerHunt()
# self.ignore(SpeedChatGlobals.SCCustomMsgEvent)
taskMgr.doMethodLater(self.triggerDelay, reset, 'ScavengerHunt-phrase-reset', extraArgs=[])
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
DistributedScavengerHuntTarget.notify.debug('announceGenerate')
self.setupListenerDetails()
def delete(self):
# stop listening to speed chat
self.ignoreAll()
taskMgr.remove('ScavengerHunt-phrase-reset')
DistributedObject.DistributedObject.delete(self)
# do the event
def attemptScavengerHunt(self):
DistributedScavengerHuntTarget.notify.debug('attempScavengerHunt')
self.notify.debug("attemptScavengerHunt()")
self.sendUpdate('attemptScavengerHunt', [])

View File

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

View File

@ -1,29 +1,40 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.ai import DistributedPhaseEventMgr
class DistributedTrashcanZeroMgr(DistributedPhaseEventMgr.DistributedPhaseEventMgr):
"""Class to manage the trashcan zero manager"""
neverDisable = 1
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):
DistributedPhaseEventMgr.DistributedPhaseEventMgr.__init__(self, cr)
cr.trashcanZeroMgr = self
def announceGenerate(self):
"""Tell other objects we're here."""
DistributedPhaseEventMgr.DistributedPhaseEventMgr.announceGenerate(self)
messenger.send('trashcanZeroIsRunning', [self.isRunning])
def delete(self):
self.notify.debug('deleting trashcanzeromgr')
self.notify.debug("Deleting TrashcanZeroMgr")
messenger.send('trashcanZeroIsRunning', [False])
DistributedPhaseEventMgr.DistributedPhaseEventMgr.delete(self)
if hasattr(self.cr, 'trashcanZeroMgr'):
if hasattr(self.cr, "trashcanZeroMgr"):
del self.cr.trashcanZeroMgr
def setCurPhase(self, newPhase):
"""We've gotten a new phase lets, tell the trashcans."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setCurPhase(self, newPhase)
messenger.send('trashcanZeroPhase', [newPhase])
def setIsRunning(self, isRunning):
"""We've gotten a new phase lets, tell the trashcans."""
assert self.notify.debugStateCall(self)
DistributedPhaseEventMgr.DistributedPhaseEventMgr.setIsRunning(self, isRunning)
messenger.send('trashcanZeroIsRunning', [isRunning])

View File

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

View File

@ -1,15 +1,22 @@
from direct.directnotify import DirectNotifyGlobal
from . import 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')
def __init__(self, cr):
DistributedScavengerHuntTarget.DistributedScavengerHuntTarget.__init__(self, cr)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said')
helpPhrase = 10003
self.notify.debug("Checking if phrase was said")
helpPhrase = 10003 # 'Trick or Treat!'
def reset():
self.triggered = False

View File

@ -1,9 +1,14 @@
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
from toontown.speedchat.TTSCIndexedTerminal import TTSCIndexedMsgEvent
from . import 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')
def __init__(self, cr):
@ -11,14 +16,16 @@ class DistributedWinterCarolingTarget(DistributedScavengerHuntTarget.Distributed
def setupListenerDetails(self):
self.triggered = False
self.triggerDelay = 15
self.triggerDelay = 15 # Seconds to disable the listener
self.accept(TTSCIndexedMsgEvent, self.phraseSaid)
# go ahead and start listening to speedchat
def phraseSaid(self, phraseId):
self.notify.debug('Checking if phrase was said')
self.notify.debug("Checking if phrase was said")
helpPhrases = []
for i in range(6):
helpPhrases.append(30220 + i)
helpPhrases.append(60220 + i)
def reset():
self.triggered = False

View File

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

View File

@ -1,6 +1,5 @@
from direct.directnotify import DirectNotifyGlobal
from toontown.ai import HolidayBaseAI
from toontown.toonbase import ToontownGlobals
from toontown.ai import DistributedGreenToonEffectMgrAI
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.toontown import loadDNAFile
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.ClockDelta import *
from direct.interval.IntervalGlobal import *
from . import HolidayDecorator
from toontown.toonbase import ToontownGlobals
from toontown.safezone import Playground
from toontown.town import Street
from toontown.estate import Estate
class HalloweenHolidayDecorator(HolidayDecorator.HolidayDecorator):
notify = DirectNotifyGlobal.directNotify.newCategory('HalloweenHolidayDecorator')
def __init__(self):
HolidayDecorator.HolidayDecorator.__init__(self)
#####################################################
# Function that checks the validity of a street,
# it's loader and the geometry
#####################################################
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
else:
if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace():
self.notify.debug('Failed Street Check %s' % 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())
else:
self.notify.debug('Failed Street Check')
self.notify.debug("Failed Street Check")
return False
#####################################################
# Function that checks the validity of a hood,
# it's loader and the geometry
#####################################################
def __checkHoodValidity(self):
if (hasattr(base.cr.playGame, 'getPlace') and
base.cr.playGame.getPlace() and
(isinstance(base.cr.playGame.getPlace(), Playground.Playground) or
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, 'hood') and
base.cr.playGame.getPlace().loader.hood and
hasattr(base.cr.playGame.getPlace().loader.hood, 'loader') and
base.cr.playGame.getPlace().loader.hood.loader and
hasattr(base.cr.playGame.getPlace().loader.hood.loader, 'geom') and
base.cr.playGame.getPlace().loader.hood.loader.geom):
return True
if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and \
(isinstance(base.cr.playGame.getPlace(), Playground.Playground) or 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, "hood") and base.cr.playGame.getPlace().loader.hood and \
hasattr(base.cr.playGame.getPlace().loader.hood,
"loader") and base.cr.playGame.getPlace().loader.hood.loader \
and hasattr(base.cr.playGame.getPlace().loader.hood.loader,
"geom") and base.cr.playGame.getPlace().loader.hood.loader.geom:
return True
else:
if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace():
self.notify.debug('Failed Hood Check %s' % 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())
else:
self.notify.debug('Failed Hood Check')
self.notify.debug("Failed Hood Check")
return False
#####################################################
# This function safely calls startSpookySky
# for the halloween holiday
#####################################################
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()
####################################################
# This function safely calls stopSpookySky
# for the halloween holiday
####################################################
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()
def decorate(self):
# Load the specified seasonal storage file
self.updateHoodDNAStore()
self.swapIval = self.getSwapVisibleIval()
if self.swapIval:
self.swapIval.start()
def __lightDecorationOn__():
# import pdb; pdb.set_trace()
place = base.cr.playGame.getPlace()
if hasattr(place, 'halloweenLights'):
if hasattr(place, "halloweenLights"):
if not self.__checkStreetValidity():
return
else:
place.halloweenLights = place.loader.geom.findAllMatches('**/*light*')
place.halloweenLights += place.loader.geom.findAllMatches('**/*lamp*')
place.halloweenLights += place.loader.geom.findAllMatches('**/prop_snow_tree*')
place.halloweenLights = place.loader.geom.findAllMatches("**/*light*")
place.halloweenLights += place.loader.geom.findAllMatches("**/*lamp*")
place.halloweenLights += place.loader.geom.findAllMatches("**/prop_snow_tree*")
for light in place.halloweenLights:
light.setColorScaleOff(0)
elif not self.__checkHoodValidity():
return
else:
place.loader.hood.halloweenLights = place.loader.hood.loader.geom.findAllMatches('**/*light*')
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)
if not self.__checkHoodValidity():
return
else:
place.loader.hood.halloweenLights = place.loader.hood.loader.geom.findAllMatches("**/*light*")
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()
if ToontownGlobals.HALLOWEEN_COSTUMES not in holidayIds and ToontownGlobals.SPOOKY_COSTUMES not in holidayIds:
if ToontownGlobals.HALLOWEEN_COSTUMES not in holidayIds:
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:
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))
# Fixes transition related crashes
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()
distributedEstate = base.cr.doFind('DistributedEstate')
# Replace the plane with the witch in the estate
distributedEstate = base.cr.doFind("DistributedEstate")
if distributedEstate:
distributedEstate.loadWitch()
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()
distributedEstate = base.cr.doFind('DistributedEstate')
# Replace the witch with the plane
distributedEstate = base.cr.doFind("DistributedEstate")
if distributedEstate:
distributedEstate.unloadWitch()
# if there are any other decoration holidays running
holidayIds = base.cr.newsManager.getDecorationHolidayId()
if len(holidayIds) > 0:
self.decorate()
return
# Reload the regular storage file
storageFile = base.cr.playGame.hood.storageDNAFile
if storageFile:
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:
"""

View File

@ -1,30 +1,31 @@
from panda3d.core import CSDefault, NodePath, TransformState, TransparencyAttrib, Vec4
from toontown.toonbase import ToontownGlobals
from direct.interval.IntervalGlobal import Parallel, Sequence, Func, Wait
class HolidayDecorator:
def __init__(self):
self.dnaStore = base.cr.playGame.dnaStore
self.swapIval = None
return
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()
return
def decorate(self):
# Load the specified seasonal storage file
self.updateHoodDNAStore()
self.swapIval = self.getSwapVisibleIval()
if self.swapIval:
self.swapIval.start()
def undecorate(self):
# if there are any other decoration holidays running
holidayIds = base.cr.newsManager.getDecorationHolidayId()
if len(holidayIds) > 0:
self.decorate()
return
# Reload the regular storage file
storageFile = base.cr.playGame.hood.storageDNAFile
if storageFile:
loadDNAFile(self.dnaStore, storageFile, CSDefault)
@ -33,14 +34,17 @@ class HolidayDecorator:
self.swapIval.start()
def updateHoodDNAStore(self):
# Load the specified storage files for this hood to overwrite
# DNA storage with seasonal specific files
hood = base.cr.playGame.hood
holidayIds = base.cr.newsManager.getDecorationHolidayId()
for holiday in holidayIds:
for storageFile in hood.holidayStorageDNADict.get(holiday, []):
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
# Update all visible holiday props
npl = render.findAllMatches('**/=DNARoot=holiday_prop;+s')
p = Parallel()
for i in range(npl.getNumPaths()):
@ -52,17 +56,31 @@ class HolidayDecorator:
dnaNode = self.dnaStore.findNode(dnaCode)
if dnaNode.isEmpty():
continue
# Add new
newNP = dnaNode.copyTo(np.getParent())
newNP.setTag('DNARoot', 'holiday_prop')
newNP.setTag('DNACode', dnaCode)
newNP.setColorScale(1, 1, 1, 0)
newNP.setTransparency(TransparencyAttrib.MDual, 1)
# Set transform to match old node paths transform
if np.hasTag('transformIndex'):
index = int(np.getTag('transformIndex'))
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.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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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