1109 lines
48 KiB
Python
1109 lines
48 KiB
Python
from direct.directnotify import DirectNotifyGlobal
|
|
from . import DistributedRaceAI
|
|
from toontown.toonbase import ToontownGlobals, TTLocalizer
|
|
from toontown.coghq import MintLayout
|
|
from toontown.ai import HolidayBaseAI
|
|
from direct.showbase import DirectObject
|
|
from . import RaceGlobals
|
|
import random
|
|
import os
|
|
import pickle
|
|
|
|
def getDefaultRecord(trackId):
|
|
"""
|
|
Get the default record for this track. Used for reseting records.
|
|
"""
|
|
# format: time, race type, num racers, racer name
|
|
return (RaceGlobals.getDefaultRecordTime(trackId), 0, 1, TTLocalizer.Goofy)
|
|
|
|
class RaceManagerAI(DirectObject.DirectObject):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('RaceManagerAI')
|
|
|
|
serverDataFolder = simbase.config.GetString('server-data-folder', "")
|
|
|
|
SuspiciousPercent = 0.15 # what percent of qualifying time counts as suspicious
|
|
|
|
def __init__(self, air):
|
|
DirectObject.DirectObject.__init__(self)
|
|
self.air = air
|
|
self.races = []
|
|
self.shard = str(air.districtId)
|
|
self.filename = self.getFilename()
|
|
self.trackRecords = self.loadRecords()
|
|
|
|
def getDoId(self):
|
|
# DistributedElevatorAI needs this
|
|
return 0
|
|
|
|
def createRace(self, trackId, raceType, laps, players, circuitLoop, circuitPoints, circuitTimes, qualTimes = [], circuitTimeList = {}, circuitTotalBonusTickets = {}):
|
|
#print('Creating Race: circuit Points %s' % circuitPoints)
|
|
assert self.notify.debug("createRace: players = %s" % players)
|
|
raceZone = self.air.allocateZone()
|
|
race = DistributedRaceAI.DistributedRaceAI(
|
|
self.air, trackId, raceZone, players, laps, raceType,
|
|
self.exitedRace, self.raceOver,
|
|
circuitLoop, circuitPoints, circuitTimes, qualTimes, circuitTimeList, circuitTotalBonusTickets)
|
|
race.generateWithRequired(raceZone)
|
|
# TODO: where should this be stored?
|
|
race.playersFinished = []
|
|
race.lastTotalTime = 0
|
|
self.races.append(race)
|
|
return raceZone
|
|
|
|
def exitedRace(self, race, playerInfo):
|
|
# The Object returned here, playerInfo, is a Racer object,
|
|
# and can be found in Racer.py
|
|
|
|
self.notify.debug("exited race: %s" % playerInfo.avId)
|
|
|
|
# calculate total race time
|
|
totalTime=playerInfo.totalTime
|
|
|
|
entryFee = 0
|
|
bonus = 0
|
|
placeMultiplier=0
|
|
qualify = 0
|
|
winnings = 0
|
|
trophies = []
|
|
points = []
|
|
newHistory = None
|
|
suspicious = False # if True, his time is suspiciously low
|
|
|
|
# determine their place
|
|
race.playersFinished.append(playerInfo.avId)
|
|
place = len(race.playersFinished)
|
|
self.notify.debug( "place: %s of %s" % (place, race.toonCount) )
|
|
|
|
self.notify.debug("pre-tie totalTime: %s" % totalTime)
|
|
|
|
# HACK: make sure they don't tie
|
|
if totalTime <= race.lastTotalTime:
|
|
totalTime = race.lastTotalTime + 0.01
|
|
race.lastTotalTime = totalTime
|
|
|
|
self.notify.debug("totalTime: %s, qualify: %s" % (totalTime, RaceGlobals.getQualifyingTime(race.trackId) ))
|
|
|
|
# update this player's total time for this set of races
|
|
circuitTime = totalTime + race.circuitTimes.get(playerInfo.avId, 0)
|
|
race.circuitTimes[playerInfo.avId] = circuitTime
|
|
|
|
# keep track of the players time
|
|
if not race.circuitTimeList.get(playerInfo.avId):
|
|
race.circuitTimeList[playerInfo.avId] = []
|
|
race.circuitTimeList[playerInfo.avId].append([totalTime, 0])
|
|
self.notify.debug("CircuitTimeList %s" % (race.circuitTimeList))
|
|
|
|
# update circuit points
|
|
if race.raceType == RaceGlobals.Circuit:
|
|
points = race.circuitPoints.get(playerInfo.avId, [])
|
|
points.append(RaceGlobals.CircuitPoints[place-1])
|
|
race.circuitPoints[playerInfo.avId] = points
|
|
|
|
currentTimeIndex = len(race.circuitTimeList[playerInfo.avId]) -1
|
|
# if they qualified
|
|
if totalTime <= RaceGlobals.getQualifyingTime(race.trackId):
|
|
race.circuitTimeList[playerInfo.avId][currentTimeIndex][1] = 1
|
|
self.notify.debug("Racer Qualified time: %s required: %s" % (totalTime, RaceGlobals.getQualifyingTime(race.trackId)))
|
|
# set the flag for the gui
|
|
qualify = 1
|
|
|
|
# see if the broke a personal record
|
|
self.checkPersonalBest(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
|
|
|
|
# check for suspiciousTime
|
|
qualTime = RaceGlobals.getQualifyingTime(race.trackId)
|
|
threshold = qualTime * self.SuspiciousPercent
|
|
if totalTime < threshold:
|
|
self.air.writeServerEvent("kartingSuspiciousRacer", playerInfo.avId, "%s|%s" % (race.trackId,totalTime))
|
|
suspicious = True
|
|
|
|
# you can only place if you beat qualifying time and you are NOT practicing
|
|
if race.raceType == RaceGlobals.Practice:
|
|
winnings = RaceGlobals.PracticeWinnings
|
|
self.notify.debug("GrandTouring: Checking from branch: practice %s" % (playerInfo.avId))
|
|
trophies = self.checkForNonRaceTrophies(playerInfo.avId)
|
|
|
|
if trophies:
|
|
# need to update the history from a list of trophiesWon
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
else:
|
|
# keep track of placemnet for contests
|
|
self.air.writeServerEvent("kartingPlaced", playerInfo.avId, "%s|%s" % (place, race.toonCount))
|
|
|
|
if race.raceType != RaceGlobals.Circuit:
|
|
# calculate their winnings
|
|
entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
|
|
placeMultiplier = RaceGlobals.Winnings[(place - 1) + (RaceGlobals.MaxRacers - race.toonCount)]
|
|
winnings = int(entryFee * placeMultiplier)
|
|
|
|
# win any trophies?
|
|
#trophies = self.checkForTrophies(place, race.trackId, race.raceType, race.toonCount, playerInfo.avId)
|
|
# update history
|
|
newHistory = self.getNewSingleRaceHistory(race, playerInfo.avId, place)
|
|
av = self.air.doId2do.get(playerInfo.avId)
|
|
if newHistory:
|
|
self.notify.debug("history %s" % (newHistory))
|
|
av.b_setKartingHistory(newHistory)
|
|
# win any trophies?
|
|
trophies = self.checkForRaceTrophies(race, playerInfo.avId)
|
|
else:
|
|
trophies = self.checkForNonRaceTrophies(playerInfo.avId)
|
|
|
|
if trophies:
|
|
# need to update the history from a list of trophiesWon
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
|
|
|
|
# see if they broke a server record
|
|
if not suspicious:
|
|
bonus = self.checkTimeRecord(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
|
|
if (race.circuitTotalBonusTickets.has_key(playerInfo.avId)):
|
|
race.circuitTotalBonusTickets[playerInfo.avId] += bonus
|
|
else:
|
|
race.circuitTotalBonusTickets[playerInfo.avId] = bonus
|
|
|
|
# set the tickets on the toon
|
|
av = self.air.doId2do.get(playerInfo.avId)
|
|
if av:
|
|
oldTickets = av.getTickets()
|
|
self.notify.debug( "old tickets: %s" % oldTickets )
|
|
newTickets = oldTickets + winnings + entryFee + bonus
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTicketsWon", playerInfo.avId, "%s" % (newTickets - oldTickets))
|
|
self.notify.debug( "entry fee: %s" % entryFee )
|
|
self.notify.debug( "place mult: %s" % placeMultiplier )
|
|
self.notify.debug( "winnings: %s" % winnings )
|
|
self.notify.debug( "bonus: %s" % bonus )
|
|
self.notify.debug( "new tickets: %s" % newTickets )
|
|
self.notify.debug( "circuit points: %s" % points )
|
|
self.notify.debug( "circuit time: %s" % circuitTime )
|
|
self.notify.debug( "circuitTotalBonusTickets: %s" % race.circuitTotalBonusTickets)
|
|
av.b_setTickets(newTickets)
|
|
|
|
else:
|
|
race.circuitTimeList[playerInfo.avId][currentTimeIndex][1] = -1
|
|
self.notify.debug("GrandTouring: Checking from branch: Not Qualified %s" % (playerInfo.avId))
|
|
trophies = self.checkForNonRaceTrophies(playerInfo.avId)
|
|
|
|
if trophies:
|
|
# need to update the history from a list of trophiesWon
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
|
|
# report the good news!
|
|
if(race in self.races):
|
|
race.d_setPlace(playerInfo.avId,
|
|
totalTime,
|
|
place,
|
|
entryFee,
|
|
qualify,
|
|
winnings,
|
|
bonus,
|
|
trophies,
|
|
points,
|
|
circuitTime)
|
|
|
|
# handle the end of a circuit race
|
|
if race.isCircuit():
|
|
self.notify.debug("isCircuit")
|
|
if race.everyoneDone():
|
|
self.notify.debug("everyoneDone")
|
|
#doing this immediately kills showing the breaking a record sequence.
|
|
#it's a problem only when the last player in the 3rd race breaks a record
|
|
if race.isLastRace():
|
|
taskMgr.doMethodLater(10,self.endCircuitRace,"DelayEndCircuitRace=%d" % race.doId , (race,bonus))
|
|
else:
|
|
self.endCircuitRace(race, bonus)
|
|
else:
|
|
self.notify.debug("not isCircuit")
|
|
|
|
|
|
#trophies.extend(self.checkForNonRaceTrophies(playerInfo.avId, newHistory))
|
|
|
|
|
|
|
|
def endCircuitRace(self, race, bonus = 0):
|
|
self.notify.debug("endCircuitRace")
|
|
# look at all the points and decide the standings
|
|
pointTotals = []
|
|
for avId in race.circuitPoints:
|
|
pointTotals.append([avId, sum(race.circuitPoints[avId])])
|
|
|
|
# do a quick n dirty bubble sort (first place -> last place)
|
|
numVals = len(pointTotals)
|
|
finalStandings = []
|
|
|
|
def swap(x, y):
|
|
t = pointTotals[x]
|
|
pointTotals[x] = pointTotals[y]
|
|
pointTotals[y] = t
|
|
|
|
# the old bubble sort seemed wonky - grabbed this one from wikisource! =]
|
|
|
|
for i in range(numVals-1,0,-1):
|
|
for j in range(i):
|
|
if pointTotals[j][1] < pointTotals[j+1][1]:
|
|
swap(j, j+1)
|
|
elif pointTotals[j][1] == pointTotals[j+1][1]:
|
|
# ties are resolved via totalTimes
|
|
avId1 = pointTotals[j][0]
|
|
avId2 = pointTotals[j+1][0]
|
|
if race.circuitTimes[avId1] > race.circuitTimes[avId2]:
|
|
swap(j,j+1)
|
|
|
|
# don't trust grabbing them out while sorting
|
|
for i in range(numVals):
|
|
finalStandings.append(pointTotals[i][0])
|
|
|
|
self.notify.debug("Final standings %s" % (finalStandings))
|
|
# check for trophies, apply winnings, etc.
|
|
for avId in finalStandings:
|
|
self.notify.debug("avId %s" % (avId))
|
|
|
|
place = finalStandings.index(avId) + 1
|
|
places = len(finalStandings)
|
|
winnings = 0
|
|
trophies = []
|
|
|
|
if race.isLastRace():
|
|
self.notify.debug("isLastRace")
|
|
# make sure we don't reward any disconnected racers
|
|
av = self.air.doId2do.get(avId)
|
|
if av and (avId in race.playersFinished):
|
|
# keep track of placement for contests
|
|
self.air.writeServerEvent("kartingCircuitFinished", avId, "%s|%s|%s|%s" % (place, places, race.circuitTimes[avId], race.trackId))
|
|
print("kartingCircuitFinished", avId, "%s|%s|%s|%s" % (place, places, race.circuitTimes[avId], race.trackId))
|
|
|
|
# calculate their winnings
|
|
entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
|
|
placeMultiplier = RaceGlobals.Winnings[(place - 1) + (RaceGlobals.MaxRacers - places)]
|
|
winnings = int(entryFee * placeMultiplier)
|
|
|
|
# update history
|
|
newHistory = self.getNewCircuitHistory(race, avId, place)
|
|
if newHistory:
|
|
self.notify.debug("history %s" % (newHistory))
|
|
# win any trophies?
|
|
trophies = self.checkForCircuitTrophies(race, avId, newHistory)
|
|
av.b_setKartingHistory(newHistory)
|
|
|
|
else:
|
|
self.notify.debug("no new history")
|
|
trophies = self.checkForNonRaceTrophies(avId)
|
|
|
|
if trophies:
|
|
# need to update the history from a list of trophiesWon
|
|
self.updateTrophiesFromList(avId, trophies)
|
|
|
|
oldTickets = av.getTickets()
|
|
self.notify.debug( "endCircuitRace: old tickets: %s" % oldTickets )
|
|
newTickets = oldTickets + winnings + entryFee
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTicketsWonCircuit", avId, "%s" % (newTickets - oldTickets))
|
|
self.notify.debug( "entry fee: %s" % entryFee )
|
|
self.notify.debug( "place mult: %s" % placeMultiplier )
|
|
self.notify.debug( "winnings: %s" % winnings )
|
|
self.notify.debug( "new tickets: %s" % newTickets )
|
|
self.notify.debug( "trophies: %s" % trophies )
|
|
self.notify.debug( "bonus: %s" % bonus)
|
|
av.b_setTickets(newTickets)
|
|
|
|
finalBonus = 0
|
|
if (race.circuitTotalBonusTickets.has_key(avId)):
|
|
finalBonus = race.circuitTotalBonusTickets[avId]
|
|
|
|
#race.d_setCircuitPlace(avId, place, entryFee, winnings, bonus, trophies)
|
|
race.d_setCircuitPlace(avId, place, entryFee, winnings, finalBonus, trophies)
|
|
|
|
race.playersFinished = finalStandings
|
|
race.d_endCircuitRace()
|
|
|
|
def updateTrophiesFromList(self, avId, trophies):
|
|
self.air.writeServerEvent("Writing Trophies: Updating trophies from list", avId, "%s" % (trophies))
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return
|
|
if not trophies:
|
|
return
|
|
trophyField = av.getKartingTrophies()
|
|
for trophy in trophies:
|
|
trophyField[trophy] = 1
|
|
av.b_setKartingTrophies(trophyField)
|
|
|
|
|
|
def checkForCircuitTrophies(self, race, avId, inHistory = None):
|
|
#checks for qualify, win, and sweep trophies for curcuit races
|
|
#returns a list of new trophies
|
|
|
|
#check and retrieve the needed data
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return []
|
|
|
|
trophies = av.getKartingTrophies()
|
|
if inHistory:
|
|
history = inHistory
|
|
else:
|
|
history = av.getKartingHistory()
|
|
|
|
#trackGenre = RaceGlobals.getTrackGenre(race.trackId)
|
|
|
|
#setup the test groups: wins, sweeps, and qualifies
|
|
|
|
winIndex = RaceGlobals.CircuitWins
|
|
winReqList = RaceGlobals.WonCircuitRaces
|
|
winIndices = RaceGlobals.CircuitWinsList
|
|
|
|
sweepIndex = RaceGlobals.CircuitSweeps
|
|
sweepReqList = RaceGlobals.SweptCircuitRaces
|
|
sweepIndices = RaceGlobals.CircuitSweepsList
|
|
|
|
qualIndex = RaceGlobals.CircuitQuals
|
|
qualReqList = RaceGlobals.QualifiedCircuitRaces
|
|
qualIndices = RaceGlobals.CircuitQualList
|
|
|
|
trophies = av.getKartingTrophies()
|
|
newTrophies = []
|
|
|
|
#check to see which win trophies are won
|
|
newTrophies.extend(self.checkHistoryForTrophy(trophies, history, winIndex, winReqList, winIndices))
|
|
|
|
#check to see which sweep trophies are won
|
|
newTrophies.extend(self.checkHistoryForTrophy(trophies, history, sweepIndex, sweepReqList, sweepIndices))
|
|
|
|
#check to see which qualify trophies are won
|
|
newTrophies.extend(self.checkHistoryForTrophy(trophies, history, qualIndex, qualReqList, qualIndices))
|
|
self.notify.debug("GrandTouring: Checking from branch: Circuit %s" % (avId))
|
|
newTrophies.extend(self.checkForNonRaceTrophies(avId, history))
|
|
newTrophies.sort()
|
|
|
|
return newTrophies
|
|
|
|
def checkForRaceTrophies(self, race, avId, inHistory = None):
|
|
#checks for single race win and qualified trophies
|
|
|
|
#check and retrieve the needed data
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return []
|
|
|
|
trophies = av.getKartingTrophies()
|
|
if inHistory:
|
|
history = inHistory
|
|
else:
|
|
history = av.getKartingHistory()
|
|
|
|
newTrophies = []
|
|
|
|
#check for genre wins trophies
|
|
numTrackGenres = len(RaceGlobals.WinsList)
|
|
for genre in range(numTrackGenres):
|
|
singleGenreNewTrophies = self.checkHistoryForTrophy(trophies,
|
|
history,
|
|
RaceGlobals.WinsList[genre],
|
|
RaceGlobals.WonRaces,
|
|
RaceGlobals.AllWinsList[genre])
|
|
newTrophies.extend(singleGenreNewTrophies)
|
|
|
|
#check for genre quals trophies
|
|
numTrackGenres = len(RaceGlobals.QualsList)
|
|
for genre in range(numTrackGenres):
|
|
singleGenreNewTrophies = self.checkHistoryForTrophy(trophies,
|
|
history,
|
|
RaceGlobals.QualsList[genre],
|
|
RaceGlobals.QualifiedRaces,
|
|
RaceGlobals.AllQualsList[genre])
|
|
newTrophies.extend(singleGenreNewTrophies)
|
|
|
|
#check for total wins trophy
|
|
totalWins = 0
|
|
for genre in range(numTrackGenres):
|
|
totalWins += history[RaceGlobals.WinsList[genre]]
|
|
|
|
singleGenreNewTrophies = self.checkHistoryForTrophyByValue(trophies,
|
|
history,
|
|
totalWins,
|
|
[RaceGlobals.TotalWonRaces],
|
|
[RaceGlobals.TotalWins])
|
|
newTrophies.extend(singleGenreNewTrophies)
|
|
|
|
#check for total quals trophy
|
|
totalQuals = 0
|
|
for genre in range(numTrackGenres):
|
|
totalQuals += history[RaceGlobals.QualsList[genre]]
|
|
|
|
singleGenreNewTrophies = self.checkHistoryForTrophyByValue(trophies,
|
|
history,
|
|
totalQuals,
|
|
[RaceGlobals.TotalQualifiedRaces],
|
|
[RaceGlobals.TotalQuals])
|
|
newTrophies.extend(singleGenreNewTrophies)
|
|
self.notify.debug("GrandTouring: Checking from branch: Race %s " % (avId))
|
|
newTrophies.extend(self.checkForNonRaceTrophies(avId, history))
|
|
newTrophies.sort()
|
|
|
|
return newTrophies
|
|
|
|
def checkForNonRaceTrophies(self, avId, inHistory = None):
|
|
#checks for race independent trophies like laff cups
|
|
self.notify.debug("CHECKING FOR NONRACE TROPHIES")
|
|
self.notify.debug("GrandTouring: Checking for non-race trophies %s" % (avId))
|
|
|
|
#check and retrieve the needed data
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
self.notify.debug("NO AV %s" % (avId))
|
|
self.notify.debug("GrandTouring: can't convert avId to Av %s" % (avId))
|
|
return []
|
|
|
|
trophies = av.getKartingTrophies()
|
|
if inHistory:
|
|
history = inHistory
|
|
else:
|
|
history = av.getKartingHistory()
|
|
|
|
newTrophies = []
|
|
self.notify.debug("GrandTouring: history-- %s" % (history))
|
|
self.notify.debug("GrandTouring: trophies- %s" % (trophies))
|
|
|
|
addTrophyCount = 0
|
|
|
|
#check for grandtouring
|
|
if not trophies[RaceGlobals.GrandTouring]:
|
|
self.notify.debug("checking for grand touring")
|
|
self.notify.debug("GrandTouring: checking for grand touring %s" % (trophies[RaceGlobals.GrandTouring]))
|
|
#import pdb; pdb.set_trace()
|
|
best = av.getKartingPersonalBestAll()
|
|
self.notify.debug("personal best %s" % (best))
|
|
self.notify.debug("GrandTouring: checking personal best %s" % (best))
|
|
counter = 0
|
|
for time in best:
|
|
if not time == 0:
|
|
counter +=1
|
|
self.notify.debug("counter %s tracks %s" % (counter, len(RaceGlobals.TrackDict)))
|
|
self.notify.debug("GrandTouring: bests comparison counter: %s tracks: %s" % (counter, len(RaceGlobals.TrackDict)))
|
|
if counter >= len(RaceGlobals.TrackDict):
|
|
newTrophies.append(RaceGlobals.GrandTouring)
|
|
addTrophyCount += 1
|
|
self.air.writeServerEvent("kartingTrophy", avId, "%s" % (RaceGlobals.GrandTouring))
|
|
self.notify.debug( "trophy: " + TTLocalizer.KartTrophyDescriptions[RaceGlobals.GrandTouring] )
|
|
self.notify.debug("GrandTouring: awarding grand touring new trophies %s" % (newTrophies))
|
|
else:
|
|
self.notify.debug("already has grandtouring")
|
|
self.notify.debug("trophies %s" % (trophies))
|
|
self.notify.debug("GrandTouring: already has grand touring %s" % (trophies[RaceGlobals.GrandTouring]))
|
|
|
|
# check to see if we need a laff point
|
|
for i in range(1, RaceGlobals.NumTrophies/RaceGlobals.TrophiesPerCup + 1):
|
|
cupNum = (trophies[:RaceGlobals.NumTrophies].count(1) + addTrophyCount) / (i * RaceGlobals.TrophiesPerCup)
|
|
self.notify.debug( "cupNum: %s" % cupNum)
|
|
trophyIndex = RaceGlobals.TrophyCups[i - 1]
|
|
if cupNum and not trophies[trophyIndex]:
|
|
# award the cup!
|
|
#trophies[trophyIndex] = 1
|
|
newTrophies.append(trophyIndex)
|
|
# laff point boost!
|
|
oldMaxHp = av.getMaxHp()
|
|
newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
|
|
self.notify.debug( "cup awarded! new max laff : %s" % newMaxHp)
|
|
av.b_setMaxHp(newMaxHp)
|
|
# Also, give them a full heal
|
|
av.toonUp(newMaxHp)
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTrophy", avId, "%s" % (trophyIndex))
|
|
self.notify.debug( "trophy: " + TTLocalizer.KartTrophyDescriptions[trophyIndex] )
|
|
|
|
self.notify.debug("NONRACE TROPHIES %s" % (newTrophies))
|
|
return newTrophies
|
|
|
|
def checkHistoryForTrophyByValue(self, trophies, history, historyIndexValue, trophyReqList, trophyIndices):
|
|
#takes the index of the history we are interested in "number of wins etc.."
|
|
#compares it to a list of required wins for each stage
|
|
#and returns the new trophy indices won at each stage
|
|
|
|
newTrophies = []
|
|
self.notify.debug("Checking History for Trophy")
|
|
self.notify.debug("Index %s Num %s ReqList %s Indices %s" % (0, historyIndexValue, trophyReqList, trophyIndices))
|
|
for index in range(len(trophyIndices)):
|
|
if not trophies[trophyIndices[index]]:
|
|
if historyIndexValue >= trophyReqList[index]:
|
|
trophies[trophyIndices[index]] = 1
|
|
newTrophies.append(trophyIndices[index])
|
|
return newTrophies
|
|
|
|
|
|
def checkHistoryForTrophy(self, trophies, history, historyIndex, trophyReqList, trophyIndices):
|
|
#takes the index of the history we are interested in "number of wins etc.."
|
|
#compares it to a list of required wins for each stage
|
|
#and returns the new trophy indices won at each stage
|
|
|
|
newTrophies = []
|
|
self.notify.debug("Checking History for Trophy")
|
|
self.notify.debug("Index %s Num %s ReqList %s Indices %s" % (historyIndex, history[historyIndex], trophyReqList, trophyIndices))
|
|
for index in range(len(trophyIndices)):
|
|
if not trophies[trophyIndices[index]]:
|
|
if history[historyIndex] >= trophyReqList[index]:
|
|
trophies[trophyIndices[index]] = 1
|
|
newTrophies.append(trophyIndices[index])
|
|
return newTrophies
|
|
|
|
def mergeHistories(self, historyA, historyB):
|
|
newHistorySize = len(historyA)
|
|
if len(historyB) > len(historyA):
|
|
newHistorySize = historyB
|
|
|
|
mergedHistory = []
|
|
|
|
for index in range(newHistorySize):
|
|
mergedHistory[index] = 0
|
|
|
|
if len(historyA) > index:
|
|
if historyA[index] > mergedHistory[index]:
|
|
historyA[index] = mergedHistory[index]
|
|
|
|
if len(historyB) > index:
|
|
if historyB[index] > mergedHistory[index]:
|
|
historyB[index] = mergedHistory[index]
|
|
|
|
return mergedHistory
|
|
|
|
def getNewSingleRaceHistory(self, race, avId, positionFinished):
|
|
newHistory = 0
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return []
|
|
history = av.getKartingHistory()
|
|
trackGenre = RaceGlobals.getTrackGenre(race.trackId)
|
|
|
|
winIndex = RaceGlobals.WinsList[trackGenre]
|
|
winReqList = RaceGlobals.WonRaces
|
|
|
|
qualIndex = RaceGlobals.QualsList[trackGenre]
|
|
qualReqList = RaceGlobals.QualifiedRaces
|
|
|
|
#win history
|
|
if history[winIndex] < winReqList[-1] and positionFinished == 1:
|
|
history[winIndex] += 1
|
|
self.notify.debug("New History Won!")
|
|
newHistory = 1
|
|
|
|
#qual history
|
|
if history[qualIndex] < qualReqList[-1]:
|
|
history[qualIndex] += 1
|
|
self.notify.debug("New History Qualified!")
|
|
newHistory = 1
|
|
|
|
if newHistory:
|
|
return history
|
|
|
|
def getNewCircuitHistory(self, race, avId, positionFinished):
|
|
newHistory = 0
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return []
|
|
history = av.getKartingHistory()
|
|
|
|
trackGenre = RaceGlobals.getTrackGenre(race.trackId)
|
|
historyIndex = RaceGlobals.CircuitWins
|
|
trophyReqList = RaceGlobals.WonCircuitRaces
|
|
sweepIndices = RaceGlobals.CircuitSweepsList
|
|
sweepReqList = RaceGlobals.SweptCircuitRaces
|
|
|
|
self.notify.debug("getNewCircuitHistory: avId=%d positionFinished=%d history =%s" % (avId, positionFinished, history))
|
|
|
|
#win history
|
|
if history[historyIndex] < trophyReqList[-1] and positionFinished == 1:
|
|
history[historyIndex] += 1
|
|
self.notify.debug("New History Won!")
|
|
newHistory = 1
|
|
|
|
|
|
#sweep history
|
|
#first determine if a sweep occured ~ if the player has maximum points
|
|
swept = 0
|
|
totalPoints = sum(race.circuitPoints[avId])
|
|
if totalPoints == len(race.circuitPoints[avId]) * RaceGlobals.CircuitPoints[0]:
|
|
swept = 1
|
|
|
|
#increment the sweep history if it's not maxed ~ reached the highest requirement
|
|
if swept:
|
|
if history[RaceGlobals.CircuitSweeps] < sweepReqList[-1]:
|
|
if not history[RaceGlobals.CircuitSweeps]:
|
|
history[RaceGlobals.CircuitSweeps] = 0
|
|
history[RaceGlobals.CircuitSweeps] += 1
|
|
self.notify.debug("New History Swept!")
|
|
newHistory = 1
|
|
|
|
#qual history
|
|
#first determine if the player qualified for all their circuit races
|
|
qualified = 0
|
|
#check to see if the avatar has a time for each race
|
|
self.notify.debug("qual times %s" % (race.qualTimes))
|
|
self.notify.debug("avatar times %s" % (race.circuitTimeList[avId]))
|
|
#if len(race.qualTimes) <= len(race.circuitTimeList[avId]):
|
|
qualified = 1
|
|
self.notify.debug("End Race Circuit Time List %s" % (race.circuitTimeList))
|
|
self.notify.debug("check for qualify")
|
|
for qual in race.circuitTimeList[avId]:
|
|
self.notify.debug("qual %s" % (qual))
|
|
if qual[1] == -1:
|
|
qualified = 0
|
|
self.notify.debug("not qualified")
|
|
|
|
#increment the qualify history if it's not maxed ~ reached the highest requirement
|
|
if qualified:
|
|
self.notify.debug("qualified has %s needs %s" % (history[RaceGlobals.CircuitQuals], RaceGlobals.QualifiedCircuitRaces[-1]))
|
|
if history[RaceGlobals.CircuitQuals] < RaceGlobals.QualifiedCircuitRaces[-1]:
|
|
history[RaceGlobals.CircuitQuals] += 1
|
|
self.notify.debug("New History qualified!")
|
|
newHistory = 1
|
|
|
|
if newHistory:
|
|
return history
|
|
|
|
|
|
def raceOver(self, race, normalExit = True):
|
|
assert self.notify.debug("raceOver: race.doId=%d normalExit=%s" % (race.doId, normalExit))
|
|
if(race in self.races):
|
|
if normalExit and race.isCircuit() and not race.isLastRace():
|
|
nextTrackId = race.circuitLoop[0]
|
|
assert self.notify.debug("raceOver: creating a new race %d" % nextTrackId)
|
|
continuingAvs = []
|
|
for avId in race.avIds:
|
|
if not avId in race.kickedAvIds:
|
|
continuingAvs.append(avId)
|
|
|
|
assert self.notify.debug("race.kickedAvIds=%s continuingAvs = %s" % (race.kickedAvIds,continuingAvs))
|
|
lastRace = False
|
|
if len(continuingAvs) > 0:
|
|
raceZone = self.createRace( nextTrackId,
|
|
race.raceType,
|
|
race.lapCount,
|
|
continuingAvs,
|
|
race.circuitLoop[1:],
|
|
race.circuitPoints,
|
|
race.circuitTimes,
|
|
race.qualTimes,
|
|
race.circuitTimeList,
|
|
race.circuitTotalBonusTickets)
|
|
|
|
race.sendToonsToNextCircuitRace(raceZone, nextTrackId)
|
|
else:
|
|
lastRace = True
|
|
assert self.notify.debug("no avatars to continue race, not creating a new one")
|
|
|
|
|
|
assert self.notify.debug("removing race %d" % race.doId)
|
|
self.races.remove(race)
|
|
|
|
|
|
race.requestDelete(lastRace)
|
|
else:
|
|
assert self.notify.debug("removing race %d" % race.doId)
|
|
self.races.remove(race)
|
|
race.requestDelete()
|
|
|
|
def checkForTrophies(self, place, trackId, raceType, numRacers, avId):
|
|
"""Update race history and award trophies if necessary"""
|
|
|
|
# I have tried my best to abstract this so that checking for all trophies can be done
|
|
# by this one for loop. By maintaining some strategic lists of indices in RaceGlobals
|
|
# I avoided a ridiculously long cascade of if-else statements. I apologize if it
|
|
# seems obtuse - grw
|
|
|
|
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
outHistory = av.getKartingHistory()
|
|
trophies = av.getKartingTrophies()
|
|
trophiesWon = []
|
|
|
|
# determine track type
|
|
trackGenre = RaceGlobals.getTrackGenre(trackId)
|
|
# win
|
|
if place == 1:
|
|
historyIndex = RaceGlobals.WinsList[trackGenre]
|
|
trophyIndices = RaceGlobals.AllWinsList[trackGenre]
|
|
trophyReqList = RaceGlobals.WonRaces
|
|
historyTotalList = RaceGlobals.WinsList
|
|
totalTrophyIndex = RaceGlobals.TotalWins
|
|
totalReq = RaceGlobals.TotalWonRaces
|
|
# check for win trophies
|
|
trophiesWon += self.checkForTrophy(place, trackId, raceType, numRacers, avId,
|
|
historyIndex, trophyIndices, trophyReqList,
|
|
historyTotalList, totalTrophyIndex, totalReq)
|
|
|
|
# quals
|
|
#circuit quals cannot use checkfortrophy because it assumes you get a qual if you get anything
|
|
|
|
historyIndex = RaceGlobals.QualsList[trackGenre]
|
|
trophyIndices = RaceGlobals.AllQualsList[trackGenre]
|
|
trophyReqList = RaceGlobals.QualifiedRaces
|
|
historyTotalList = RaceGlobals.QualsList
|
|
totalTrophyIndex = RaceGlobals.TotalQuals
|
|
totalReq = RaceGlobals.TotalQualifiedRaces
|
|
trophiesWon += self.checkForTrophy(place, trackId, raceType, numRacers, avId,
|
|
historyIndex, trophyIndices, trophyReqList,
|
|
historyTotalList, totalTrophyIndex, totalReq)
|
|
|
|
# check for qual trophies
|
|
|
|
#check for grandtouring
|
|
if not trophies[RaceGlobals.GrandTouring]:
|
|
self.notify.debug("checking for grand touring")
|
|
#import pdb; pdb.set_trace()
|
|
best = av.getKartingPersonalBestAll()
|
|
self.notify.debug("personal best %s" % (best))
|
|
counter = 0
|
|
for time in best:
|
|
if not time == 0:
|
|
counter +=1
|
|
self.notify.debug("counter %s tracks %s" % (counter, len(RaceGlobals.TrackDict)))
|
|
if counter >= len(RaceGlobals.TrackDict):
|
|
trophiesWon.append(RaceGlobals.GrandTouring)
|
|
|
|
# set the new trophies and history if changed
|
|
|
|
if outHistory:
|
|
av.b_setKartingHistory(outHistory)
|
|
if len(trophiesWon):
|
|
for trophy in trophiesWon:
|
|
trophies[trophy] = 1
|
|
av.b_setKartingTrophies(trophies)
|
|
|
|
trophiesWon.sort()
|
|
return trophiesWon
|
|
|
|
def checkForTrophy(self, place, trackId, raceType, numRacers, avId, historyIndex, trophyIndices, trophyReqList,
|
|
historyTotalList, totalTrophyIndex, totalReq):
|
|
"""Update race history and award trophies if necessary"""
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
if not av:
|
|
return []
|
|
history = av.getKartingHistory()
|
|
newHistory = 0
|
|
trophies = av.getKartingTrophies()
|
|
newTrophies = []
|
|
|
|
# If the number of races the player has completed is less than the most needed for any trophy,
|
|
# then add this race to players race history (keeps us from adding up to infinity)
|
|
if history[historyIndex] < trophyReqList[-1]:
|
|
history[historyIndex] += 1
|
|
newHistory = 1
|
|
|
|
# check for all three laff point trophies
|
|
for i in range(0, len(trophyReqList)):
|
|
if not trophies[trophyIndices[i]]:
|
|
#self.notify.debug( "checking for trophy: %s == %s" % (history[historyIndex], trophyReqList[i]))
|
|
if history[historyIndex] == trophyReqList[i]:
|
|
trophies[trophyIndices[i]] = 1
|
|
newTrophies.append(trophyIndices[i])
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTrophy", avId, "%s" % (trophyIndices[i]))
|
|
self.notify.debug( "trophy: " + TTLocalizer.KartTrophyDescriptions[trophyIndices[i]] )
|
|
break
|
|
|
|
# if this is not tourney, count toward total wins
|
|
if not raceType == RaceGlobals.Circuit:
|
|
# now check for total wins style trophies
|
|
if not trophies[totalTrophyIndex]:
|
|
total = 0
|
|
# calculate total since its not stored explicitly
|
|
for i in historyTotalList:
|
|
total += history[i]
|
|
self.notify.debug( "checking for total trophy: %s >= %s" % (total, totalReq))
|
|
if total >= totalReq:
|
|
trophies[totalTrophyIndex] = 1
|
|
newTrophies.append(totalTrophyIndex)
|
|
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTrophy", avId, "%s" % (totalTrophyIndex))
|
|
self.notify.debug( "trophy: " + TTLocalizer.KartTrophyDescriptions[totalTrophyIndex] )
|
|
|
|
# check to see if we need a laff point
|
|
for i in range(1, RaceGlobals.NumTrophies/RaceGlobals.TrophiesPerCup + 1):
|
|
cupNum = trophies[:RaceGlobals.NumTrophies].count(1) / (i * RaceGlobals.TrophiesPerCup)
|
|
self.notify.debug( "cupNum: %s" % cupNum)
|
|
trophyIndex = RaceGlobals.TrophyCups[i - 1]
|
|
if cupNum and not trophies[trophyIndex]:
|
|
# award the cup!
|
|
trophies[trophyIndex] = 1
|
|
newTrophies.append(trophyIndex)
|
|
# laff point boost!
|
|
oldMaxHp = av.getMaxHp()
|
|
newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
|
|
self.notify.debug( "cup awarded! new max laff : %s" % newMaxHp)
|
|
av.b_setMaxHp(newMaxHp)
|
|
# Also, give them a full heal
|
|
av.toonUp(newMaxHp)
|
|
# Write to the server log
|
|
self.air.writeServerEvent("kartingTrophy", avId, "%s" % (trophyIndex))
|
|
self.notify.debug( "trophy: " + TTLocalizer.KartTrophyDescriptions[trophyIndex] )
|
|
|
|
self.notify.debug( "newTrophies: %s" % newTrophies )
|
|
self.notify.debug( "trophies: %s" % trophies )
|
|
self.notify.debug( "kartingHistory: %s" % history )
|
|
|
|
## set the new trophies and history if changed
|
|
if newHistory:
|
|
av.b_setKartingHistory(history)
|
|
|
|
return newTrophies
|
|
|
|
#
|
|
# personal best methods
|
|
#
|
|
def checkPersonalBest(self, trackId, time, raceType, numRacers, avId):
|
|
"""Check time against top three personal best times for each track."""
|
|
av = simbase.air.doId2do.get(avId)
|
|
# TODO: what do we do if the av goes away?
|
|
if av:
|
|
bestTimes = av.getKartingPersonalBestAll()
|
|
trackIndex = RaceGlobals.TrackIds.index(trackId)
|
|
bestTime = bestTimes[trackIndex]
|
|
self.notify.debug( "thisTime: %s, bestTime: %s" % (time, bestTime) )
|
|
if (bestTime == 0.0) or (time < bestTime):
|
|
bestTimes[trackIndex] = time
|
|
self.notify.debug( "new personal best!" )
|
|
av.b_setKartingPersonalBest(bestTimes)
|
|
self.notify.debug( "personal best: %s" % bestTimes )
|
|
|
|
#
|
|
# high score file writing/reading methods
|
|
#
|
|
|
|
def checkTimeRecord(self, trackId, time, raceType, numRacers, avId):
|
|
"""Check a time against current shard record. Returns bonus tickets won if any."""
|
|
bonus = 0
|
|
newRecord = 0
|
|
|
|
for period in RaceGlobals.PeriodIds:
|
|
for record in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
recordTime = self.trackRecords[trackId][period][record][0]
|
|
if time < recordTime:
|
|
newRecord = 1
|
|
# new record!
|
|
self.notify.debug( "new %s record!" % TTLocalizer.RecordPeriodStrings[period] )
|
|
# TODO: alert player
|
|
# format: time, race type, num racers, racer name
|
|
av = simbase.air.doId2do.get(avId)
|
|
# TODO: what do we do if the av goes away?
|
|
if av:
|
|
name = av.name
|
|
# insert new record in this spot
|
|
self.trackRecords[trackId][period].insert(record, (time, raceType, numRacers, name))
|
|
# make sure we haven't gone over record list length
|
|
self.trackRecords[trackId][period] = self.trackRecords[trackId][period][:RaceGlobals.NumRecordsPerPeriod]
|
|
# notify the leaderboards of the update
|
|
self.updateLeaderboards(trackId, period)
|
|
bonus = RaceGlobals.PeriodDict[period]
|
|
|
|
# keep a log for contests, etc.
|
|
self.air.writeServerEvent("kartingRecord", avId, "%s|%s|%s" % (period, trackId, time))
|
|
else:
|
|
self.notify.warning("warning: av not logged in!")
|
|
# no need to keep checking times
|
|
break
|
|
|
|
if newRecord:
|
|
# write new record out to disk
|
|
# TODO: does this need to be cached?
|
|
self.updateRecordFile()
|
|
|
|
return bonus
|
|
|
|
def updateRecordFile(self):
|
|
"""Update current track record in this shard's record file"""
|
|
# notify the leader boards that there has been an update
|
|
try:
|
|
backup = self.filename + '.bu'
|
|
if os.path.exists(self.filename):
|
|
os.rename(self.filename, backup)
|
|
file = open(self.filename, 'w')
|
|
file.seek(0)
|
|
pickle.dump(self.trackRecords, file)
|
|
file.close()
|
|
if os.path.exists(backup):
|
|
os.remove(backup)
|
|
except EnvironmentError:
|
|
self.notify.warning(str(sys.exc_info()[1]))
|
|
|
|
def getFilename(self):
|
|
"""Compose the track record filename"""
|
|
return "%s%s.trackRecords" % (self.serverDataFolder, self.shard)
|
|
|
|
def loadRecords(self):
|
|
"""Load track record data from default location"""
|
|
try:
|
|
# Try to open the backup file:
|
|
file = open(self.filename + '.bu', 'r')
|
|
# Remove the (assumed) broken file:
|
|
if os.path.exists(self.filename):
|
|
os.remove(self.filename)
|
|
except IOError:
|
|
# OK, there's no backup file, good.
|
|
try:
|
|
# Open the real file:
|
|
file = open(self.filename, 'r')
|
|
except IOError:
|
|
# OK, there's no file. Grab the default times.
|
|
return self.getRecordTimes()
|
|
file.seek(0)
|
|
records = self.loadFrom(file)
|
|
file.close()
|
|
|
|
#check for new tracks
|
|
for trackId in RaceGlobals.TrackIds:
|
|
if not records.has_key(trackId):
|
|
records[trackId] = {}
|
|
# for each recording period (daily, etc.)
|
|
for i in RaceGlobals.PeriodIds:
|
|
records[trackId][i] = []
|
|
# for each top score
|
|
for j in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
records[trackId][i].append(getDefaultRecord(trackId))
|
|
|
|
# update all leaderboards
|
|
self.resetLeaderboards()
|
|
return records
|
|
|
|
def loadFrom(self, file):
|
|
"""Load track record data from specified file"""
|
|
records = {}
|
|
try:
|
|
while 1:
|
|
records = pickle.load(file)
|
|
except EOFError:
|
|
pass
|
|
return records
|
|
|
|
def getRecordTimes(self):
|
|
"""
|
|
Create a set of track records from default times.
|
|
Used when no record file can be found.
|
|
"""
|
|
records = {}
|
|
# for each track
|
|
for trackId in RaceGlobals.TrackIds:
|
|
records[trackId] = {}
|
|
# for each recording period (daily, etc.)
|
|
for i in RaceGlobals.PeriodIds:
|
|
records[trackId][i] = []
|
|
# for each top score
|
|
for j in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
records[trackId][i].append(getDefaultRecord(trackId))
|
|
return records
|
|
|
|
# TODO: who will call this? HolidayMgrAI?
|
|
def resetRecordPeriod(self, period):
|
|
"""
|
|
Reset the records for a given period.
|
|
"""
|
|
# for each track
|
|
for trackId in RaceGlobals.TrackIds:
|
|
# for each top score
|
|
for i in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
self.trackRecords[trackId][period][i] = getDefaultRecord(trackId)
|
|
# notify the leaderboards that the records have changed
|
|
self.updateLeaderboards(trackId, period)
|
|
|
|
# save new records to disk
|
|
self.updateRecordFile()
|
|
|
|
#
|
|
# leaderboard methods
|
|
#
|
|
|
|
def getRecords(self, trackId, period):
|
|
return self.trackRecords[trackId][period]
|
|
|
|
def updateLeaderboards(self, trackId, period):
|
|
# notify the leaderboards of the update
|
|
messenger.send("UpdateRaceRecord", [(trackId, period)])
|
|
|
|
def resetLeaderboards(self):
|
|
# usually done at startup
|
|
for track in RaceGlobals.TrackIds:
|
|
for period in RaceGlobals.PeriodIds:
|
|
self.updateLeaderboards(track, period)
|
|
|
|
|
|
# classes for the HolidayManagerAI
|
|
class KartRecordDailyResetter(HolidayBaseAI.HolidayBaseAI):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
|
'ResistanceEventMgrAI')
|
|
|
|
PostName = 'kertRecordDailyReset'
|
|
|
|
def __init__(self, air, holidayId):
|
|
HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)
|
|
|
|
def start(self):
|
|
# let the holiday system know we started
|
|
bboard.post(KartRecordDailyResetter.PostName)
|
|
simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Daily)
|
|
|
|
def stop(self):
|
|
# let the holiday system know we stopped
|
|
bboard.remove(KartRecordDailyResetter.PostName)
|
|
|
|
class KartRecordWeeklyResetter(HolidayBaseAI.HolidayBaseAI):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
|
'ResistanceEventMgrAI')
|
|
|
|
PostName = 'kartRecordWeeklyReset'
|
|
|
|
def __init__(self, air, holidayId):
|
|
HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)
|
|
|
|
def start(self):
|
|
# let the holiday system know we started
|
|
bboard.post(KartRecordWeeklyResetter.PostName)
|
|
simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Weekly)
|
|
|
|
def stop(self):
|
|
# let the holiday system know we stopped
|
|
bboard.remove(KartRecordWeeklyResetter.PostName)
|
|
|
|
class CircuitRaceHolidayMgr(HolidayBaseAI.HolidayBaseAI):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
|
'CircuitRaceHolidayMgr')
|
|
|
|
PostName = 'CircuitRaceHoliday'
|
|
StartStopMsg = 'CircuitRaceHolidayStartStop'
|
|
|
|
def __init__(self, air, holidayId):
|
|
# Because of Silly Saturday and the Circuit Racing Event, these holidays can overlap.
|
|
# We will use a counter to determine when to actually stop and start these events so
|
|
# the two holidays don't stomp on each other.
|
|
HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)
|
|
|
|
def start(self):
|
|
# let the holiday system know we started
|
|
# note: the circuit race holidays can overlap, so we use a counter to control start/stop
|
|
bboard.post(CircuitRaceHolidayMgr.PostName, bboard.get(CircuitRaceHolidayMgr.PostName, 0) + 1)
|
|
|
|
if bboard.get(CircuitRaceHolidayMgr.PostName) == 1:
|
|
# tell everyone race night is starting
|
|
simbase.air.newsManager.circuitRaceStart()
|
|
messenger.send(CircuitRaceHolidayMgr.StartStopMsg)
|
|
|
|
def stop(self):
|
|
# let the holiday system know we stopped
|
|
# note: the circuit race holidays can overlap, so we use a counter to control start/stop
|
|
bboard.post(CircuitRaceHolidayMgr.PostName, bboard.get(CircuitRaceHolidayMgr.PostName) - 1)
|
|
|
|
if bboard.get(CircuitRaceHolidayMgr.PostName) == 0:
|
|
# tell everyone race night is stopping
|
|
simbase.air.newsManager.circuitRaceEnd()
|
|
messenger.send(CircuitRaceHolidayMgr.StartStopMsg)
|