141 lines
5.6 KiB
Python
141 lines
5.6 KiB
Python
|
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:
|
||
|
def __init__(self, startTime, endTime):
|
||
|
"""Keep track of start and end datetimes, in a struct."""
|
||
|
self.start = startTime
|
||
|
self.end = endTime
|
||
|
|
||
|
def isInBetween(self, phaseTime):
|
||
|
"""Returns true if phaseTime is in between start and end times.
|
||
|
Note that it returns false if it is equal."""
|
||
|
result = False
|
||
|
if self.start < phaseTime and phaseTime < self.end:
|
||
|
result = True
|
||
|
return result
|
||
|
|
||
|
def isInBetweenInclusive(self, phaseTime):
|
||
|
"""Returns true if phaseTime is in between start and end times.
|
||
|
Note that it returns true if it is equal."""
|
||
|
result = False
|
||
|
if self.start <= phaseTime and phaseTime <= self.end:
|
||
|
result = True
|
||
|
return True
|
||
|
|
||
|
def __repr__(self):
|
||
|
return self.__str__()
|
||
|
|
||
|
def __str__(self):
|
||
|
return ("(%s %s)" % (self.start, self.end))
|
||
|
|
||
|
class PhasedHolidayAI(HolidayBaseAI.HolidayBaseAI):
|
||
|
"""This is the base class for holidays which have different phases.
|
||
|
|
||
|
They ramp up over time, such as hydrant zero, silly meter.
|
||
|
While each phase could have been implemented as a different holiday,
|
||
|
this makes sure the start and end times for each phase match up."""
|
||
|
|
||
|
# WARNING phased holidays with multiple start and end times have not been fully tested
|
||
|
# RAU coded with it in mind, but edge cases can easily slip through
|
||
|
|
||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||
|
'PhasedHolidayAI')
|
||
|
|
||
|
def __init__(self, air, holidayId, startAndEndTupleList, phaseDates):
|
||
|
HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)
|
||
|
self.oldPhase = 0
|
||
|
self.curPhase = 0
|
||
|
self.phaseDates = phaseDates
|
||
|
self.startAndEndTimes = self.convertStartAndEndListToDateTimes(startAndEndTupleList)
|
||
|
self.sanityCheckPhaseDates()
|
||
|
# we assume phase 0 is before phaseDates[0],
|
||
|
# phase 1 is between phaseDates[0], phaseDates[1]
|
||
|
# the last phase is after phaseDates[-1]
|
||
|
# TODO should we have the FSM here or in the child class?
|
||
|
# Lets leave it in the child class in case it's really simple
|
||
|
|
||
|
def convertStartAndEndListToDateTimes(self, startAndEndTupleList):
|
||
|
"""Convert start and end times to a more manageable class."""
|
||
|
result = []
|
||
|
for startAndEnd in startAndEndTupleList:
|
||
|
startInfo = startAndEnd[0]
|
||
|
startTime = datetime.datetime(startInfo[0], startInfo[1], startInfo[2],
|
||
|
startInfo[3], startInfo[4], startInfo[5])
|
||
|
endInfo = startAndEnd[1]
|
||
|
endTime = datetime.datetime(endInfo[0], endInfo[1], endInfo[2],
|
||
|
endInfo[3], endInfo[4], endInfo[5])
|
||
|
result.append(StartAndEndTime(startTime, endTime))
|
||
|
return result
|
||
|
|
||
|
|
||
|
def sanityCheckPhaseDates(self):
|
||
|
"""Do some sanity checking on our phase dates."""
|
||
|
#Check phase dates are between end and start times."""
|
||
|
for phaseDate in self.phaseDates:
|
||
|
foundInBetween = False
|
||
|
for startAndEnd in self.startAndEndTimes:
|
||
|
if startAndEnd.isInBetween(phaseDate):
|
||
|
foundInBetween = True
|
||
|
break
|
||
|
if not foundInBetween:
|
||
|
self.notify.error("holiday %d, phaseDate=%s not in between start and end times" %
|
||
|
(self.holidayId, phaseDate))
|
||
|
# check the phase dates are ascending
|
||
|
for index in range( len(self.phaseDates) -1):
|
||
|
if not (self.phaseDates[index] < self.phaseDates[index +1]):
|
||
|
self.notify.error("phaseDate=%s coming before phaseDate=%s" %
|
||
|
(self.phaseDates[index], self.phaseDates[index+1]))
|
||
|
|
||
|
def calcPhase(self, myTime):
|
||
|
"""Return which phase we should be given parameter time.
|
||
|
|
||
|
Will return 0 if it's way before the start time,
|
||
|
and return the last phase if its way after the end time
|
||
|
"""
|
||
|
result = self.getNumPhases()
|
||
|
for index, phaseDate in enumerate( self.phaseDates):
|
||
|
if myTime < phaseDate:
|
||
|
result = index
|
||
|
break
|
||
|
return result
|
||
|
|
||
|
def getNumPhases(self):
|
||
|
"""Return how many phases we have."""
|
||
|
result = len(self.phaseDates) + 1
|
||
|
return result
|
||
|
|
||
|
def isValidStart(self, curStartTime):
|
||
|
"""Print out a message if we're starting at a valid time.
|
||
|
|
||
|
We could start early or later if it's forced by magic words."""
|
||
|
result = False
|
||
|
for startAndEnd in self.startAndEndTimes:
|
||
|
if startAndEnd.isInBetweenInclusive(curStartTime):
|
||
|
result = True
|
||
|
break
|
||
|
|
||
|
def start(self):
|
||
|
"""Start the holiday and set us to the correct phase."""
|
||
|
# start the holiday
|
||
|
# this equivalent to the same bit of code we use in HolidayManagerAI.createHolidays
|
||
|
curTime = datetime.datetime.today()
|
||
|
isValidStart = self.isValidStart(curTime)
|
||
|
if not isValidStart:
|
||
|
self.notify.warning("starting holiday %d at %s but self.startAndEndTimes= %s " %
|
||
|
(self.holidayId, curTime, self.startAndEndTimes))
|
||
|
|
||
|
pass
|
||
|
|
||
|
|
||
|
def stop(self):
|
||
|
pass
|
||
|
|
||
|
def forcePhase(self, newPhase):
|
||
|
self.notify.warning("Child class must defined forcePhase")
|