2019-11-02 17:27:54 -05:00
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
2019-12-30 00:07:56 -06:00
|
|
|
from . import DistributedRaceAI
|
2019-11-02 17:27:54 -05:00
|
|
|
from toontown.toonbase import ToontownGlobals, TTLocalizer
|
|
|
|
from toontown.coghq import MintLayout
|
|
|
|
from toontown.ai import HolidayBaseAI
|
|
|
|
from direct.showbase import DirectObject
|
2019-12-30 00:07:56 -06:00
|
|
|
import RaceGlobals, random, os, pickle
|
2019-11-02 17:27:54 -05:00
|
|
|
|
|
|
|
class RaceManagerAI(DirectObject.DirectObject):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('RaceManagerAI')
|
|
|
|
serverDataFolder = simbase.config.GetString('server-data-folder', '')
|
|
|
|
|
|
|
|
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):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def createRace(self, trackId, raceType, laps, players, circuitLoop, circuitPoints, circuitTimes, qualTimes=[], circuitTimeList={}, circuitTotalBonusTickets={}):
|
|
|
|
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)
|
|
|
|
race.playersFinished = []
|
|
|
|
race.lastTotalTime = 0
|
|
|
|
self.races.append(race)
|
|
|
|
return raceZone
|
|
|
|
|
|
|
|
def exitedRace(self, race, playerInfo):
|
|
|
|
self.notify.debug('exited race: %s' % playerInfo.avId)
|
|
|
|
totalTime = playerInfo.totalTime
|
|
|
|
entryFee = 0
|
|
|
|
bonus = 0
|
|
|
|
placeMultiplier = 0
|
|
|
|
qualify = 0
|
|
|
|
winnings = 0
|
|
|
|
trophies = []
|
|
|
|
points = []
|
|
|
|
newHistory = None
|
|
|
|
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)
|
|
|
|
if totalTime <= race.lastTotalTime:
|
|
|
|
totalTime = race.lastTotalTime + 0.01
|
|
|
|
race.lastTotalTime = totalTime
|
|
|
|
self.notify.debug('totalTime: %s, qualify: %s' % (totalTime, RaceGlobals.getQualifyingTime(race.trackId)))
|
|
|
|
circuitTime = totalTime + race.circuitTimes.get(playerInfo.avId, 0)
|
|
|
|
race.circuitTimes[playerInfo.avId] = circuitTime
|
|
|
|
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)
|
|
|
|
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 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)))
|
|
|
|
qualify = 1
|
|
|
|
self.checkPersonalBest(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
|
|
|
|
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:
|
|
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
|
|
else:
|
|
|
|
self.air.writeServerEvent('kartingPlaced', playerInfo.avId, '%s|%s' % (place, race.toonCount))
|
|
|
|
if race.raceType != RaceGlobals.Circuit:
|
|
|
|
entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
|
|
|
|
placeMultiplier = RaceGlobals.Winnings[place - 1 + (RaceGlobals.MaxRacers - race.toonCount)]
|
|
|
|
winnings = int(entryFee * placeMultiplier)
|
|
|
|
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)
|
|
|
|
trophies = self.checkForRaceTrophies(race, playerInfo.avId)
|
|
|
|
else:
|
|
|
|
trophies = self.checkForNonRaceTrophies(playerInfo.avId)
|
|
|
|
if trophies:
|
|
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
|
|
bonus = self.checkTimeRecord(race.trackId, totalTime, race.raceType, race.toonCount, playerInfo.avId)
|
2019-12-30 00:07:56 -06:00
|
|
|
if playerInfo.avId in race.circuitTotalBonusTickets:
|
2019-11-02 17:27:54 -05:00
|
|
|
race.circuitTotalBonusTickets[playerInfo.avId] += bonus
|
|
|
|
else:
|
|
|
|
race.circuitTotalBonusTickets[playerInfo.avId] = bonus
|
|
|
|
av = self.air.doId2do.get(playerInfo.avId)
|
|
|
|
if av:
|
|
|
|
oldTickets = av.getTickets()
|
|
|
|
self.notify.debug('old tickets: %s' % oldTickets)
|
|
|
|
newTickets = oldTickets + winnings + entryFee + bonus
|
|
|
|
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:
|
|
|
|
self.updateTrophiesFromList(playerInfo.avId, trophies)
|
|
|
|
if race in self.races:
|
|
|
|
race.d_setPlace(playerInfo.avId, totalTime, place, entryFee, qualify, winnings, bonus, trophies, points, circuitTime)
|
|
|
|
if race.isCircuit():
|
|
|
|
self.notify.debug('isCircuit')
|
|
|
|
if race.everyoneDone():
|
|
|
|
self.notify.debug('everyoneDone')
|
|
|
|
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')
|
|
|
|
return
|
|
|
|
|
|
|
|
def endCircuitRace(self, race, bonus=0):
|
|
|
|
self.notify.debug('endCircuitRace')
|
|
|
|
pointTotals = []
|
|
|
|
for avId in race.circuitPoints:
|
|
|
|
pointTotals.append([avId, sum(race.circuitPoints[avId])])
|
|
|
|
|
|
|
|
numVals = len(pointTotals)
|
|
|
|
finalStandings = []
|
|
|
|
|
|
|
|
def swap(x, y):
|
|
|
|
t = pointTotals[x]
|
|
|
|
pointTotals[x] = pointTotals[y]
|
|
|
|
pointTotals[y] = t
|
|
|
|
|
|
|
|
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]:
|
|
|
|
avId1 = pointTotals[j][0]
|
|
|
|
avId2 = pointTotals[j + 1][0]
|
|
|
|
if race.circuitTimes[avId1] > race.circuitTimes[avId2]:
|
|
|
|
swap(j, j + 1)
|
|
|
|
|
|
|
|
for i in range(numVals):
|
|
|
|
finalStandings.append(pointTotals[i][0])
|
|
|
|
|
|
|
|
self.notify.debug('Final standings %s' % finalStandings)
|
|
|
|
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')
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
|
|
if av and avId in race.playersFinished:
|
|
|
|
self.air.writeServerEvent('kartingCircuitFinished', avId, '%s|%s' % (place, places))
|
2019-12-30 00:07:56 -06:00
|
|
|
print('kartingCircuitFinished', avId, '%s|%s' % (place, places))
|
2019-11-02 17:27:54 -05:00
|
|
|
entryFee = RaceGlobals.getEntryFee(race.trackId, race.raceType)
|
|
|
|
placeMultiplier = RaceGlobals.Winnings[place - 1 + (RaceGlobals.MaxRacers - places)]
|
|
|
|
winnings = int(entryFee * placeMultiplier)
|
|
|
|
newHistory = self.getNewCircuitHistory(race, avId, place)
|
|
|
|
if newHistory:
|
|
|
|
self.notify.debug('history %s' % newHistory)
|
|
|
|
trophies = self.checkForCircuitTrophies(race, avId, newHistory)
|
|
|
|
av.b_setKartingHistory(newHistory)
|
|
|
|
if trophies:
|
|
|
|
self.updateTrophiesFromList(avId, trophies)
|
|
|
|
else:
|
|
|
|
self.notify.debug('no new history')
|
|
|
|
trophies = self.checkForNonRaceTrophies(avId)
|
|
|
|
oldTickets = av.getTickets()
|
|
|
|
self.notify.debug('endCircuitRace: old tickets: %s' % oldTickets)
|
|
|
|
newTickets = oldTickets + winnings + entryFee
|
|
|
|
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
|
2019-12-30 00:07:56 -06:00
|
|
|
if avId in race.circuitTotalBonusTickets:
|
2019-11-02 17:27:54 -05:00
|
|
|
finalBonus = race.circuitTotalBonusTickets[avId]
|
|
|
|
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):
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
|
|
if not av:
|
|
|
|
return []
|
|
|
|
trophies = av.getKartingTrophies()
|
|
|
|
if inHistory:
|
|
|
|
history = inHistory
|
|
|
|
else:
|
|
|
|
history = av.getKartingHistory()
|
|
|
|
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 = []
|
|
|
|
newTrophies.extend(self.checkHistoryForTrophy(trophies, history, winIndex, winReqList, winIndices))
|
|
|
|
newTrophies.extend(self.checkHistoryForTrophy(trophies, history, sweepIndex, sweepReqList, sweepIndices))
|
|
|
|
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):
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
|
|
if not av:
|
|
|
|
return []
|
|
|
|
trophies = av.getKartingTrophies()
|
|
|
|
if inHistory:
|
|
|
|
history = inHistory
|
|
|
|
else:
|
|
|
|
history = av.getKartingHistory()
|
|
|
|
newTrophies = []
|
|
|
|
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)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
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)
|
|
|
|
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):
|
|
|
|
self.notify.debug('CHECKING FOR NONRACE TROPHIES')
|
|
|
|
self.notify.debug('GrandTouring: Checking for non-race trophies %s' % avId)
|
|
|
|
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
|
|
|
|
if not trophies[RaceGlobals.GrandTouring]:
|
|
|
|
self.notify.debug('checking for grand touring')
|
|
|
|
self.notify.debug('GrandTouring: checking for grand touring %s' % trophies[RaceGlobals.GrandTouring])
|
|
|
|
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])
|
|
|
|
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]:
|
|
|
|
newTrophies.append(trophyIndex)
|
|
|
|
oldMaxHp = av.getMaxHp()
|
|
|
|
newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
|
|
|
|
self.notify.debug('cup awarded! new max laff : %s' % newMaxHp)
|
|
|
|
av.b_setMaxHp(newMaxHp)
|
|
|
|
av.toonUp(newMaxHp)
|
|
|
|
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):
|
|
|
|
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):
|
|
|
|
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
|
|
|
|
if history[winIndex] < winReqList[-1] and positionFinished == 1:
|
|
|
|
history[winIndex] += 1
|
|
|
|
self.notify.debug('New History Won!')
|
|
|
|
newHistory = 1
|
|
|
|
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))
|
|
|
|
if history[historyIndex] < trophyReqList[-1] and positionFinished == 1:
|
|
|
|
history[historyIndex] += 1
|
|
|
|
self.notify.debug('New History Won!')
|
|
|
|
newHistory = 1
|
|
|
|
swept = 0
|
|
|
|
totalPoints = sum(race.circuitPoints[avId])
|
|
|
|
if totalPoints == len(race.circuitPoints[avId]) * RaceGlobals.CircuitPoints[0]:
|
|
|
|
swept = 1
|
|
|
|
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
|
|
|
|
qualified = 0
|
|
|
|
self.notify.debug('qual times %s' % race.qualTimes)
|
|
|
|
self.notify.debug('avatar times %s' % 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')
|
|
|
|
|
|
|
|
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):
|
|
|
|
if race in self.races:
|
|
|
|
if normalExit and race.isCircuit() and not race.isLastRace():
|
|
|
|
nextTrackId = race.circuitLoop[0]
|
|
|
|
continuingAvs = []
|
|
|
|
for avId in race.avIds:
|
|
|
|
if avId not in race.kickedAvIds:
|
|
|
|
continuingAvs.append(avId)
|
|
|
|
|
|
|
|
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
|
|
|
|
self.races.remove(race)
|
|
|
|
race.requestDelete(lastRace)
|
|
|
|
else:
|
|
|
|
self.races.remove(race)
|
|
|
|
race.requestDelete()
|
|
|
|
|
|
|
|
def checkForTrophies(self, place, trackId, raceType, numRacers, avId):
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
|
|
outHistory = av.getKartingHistory()
|
|
|
|
trophies = av.getKartingTrophies()
|
|
|
|
trophiesWon = []
|
|
|
|
trackGenre = RaceGlobals.getTrackGenre(trackId)
|
|
|
|
if place == 1:
|
|
|
|
historyIndex = RaceGlobals.WinsList[trackGenre]
|
|
|
|
trophyIndices = RaceGlobals.AllWinsList[trackGenre]
|
|
|
|
trophyReqList = RaceGlobals.WonRaces
|
|
|
|
historyTotalList = RaceGlobals.WinsList
|
|
|
|
totalTrophyIndex = RaceGlobals.TotalWins
|
|
|
|
totalReq = RaceGlobals.TotalWonRaces
|
|
|
|
trophiesWon += self.checkForTrophy(place, trackId, raceType, numRacers, avId, historyIndex, trophyIndices, trophyReqList, historyTotalList, totalTrophyIndex, totalReq)
|
|
|
|
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)
|
|
|
|
if not trophies[RaceGlobals.GrandTouring]:
|
|
|
|
self.notify.debug('checking for grand touring')
|
|
|
|
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)
|
|
|
|
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):
|
|
|
|
av = self.air.doId2do.get(avId)
|
|
|
|
if not av:
|
|
|
|
return []
|
|
|
|
history = av.getKartingHistory()
|
|
|
|
newHistory = 0
|
|
|
|
trophies = av.getKartingTrophies()
|
|
|
|
newTrophies = []
|
|
|
|
if history[historyIndex] < trophyReqList[-1]:
|
|
|
|
history[historyIndex] += 1
|
|
|
|
newHistory = 1
|
|
|
|
for i in range(0, len(trophyReqList)):
|
|
|
|
if not trophies[trophyIndices[i]]:
|
|
|
|
if history[historyIndex] == trophyReqList[i]:
|
|
|
|
trophies[trophyIndices[i]] = 1
|
|
|
|
newTrophies.append(trophyIndices[i])
|
|
|
|
self.air.writeServerEvent('kartingTrophy', avId, '%s' % trophyIndices[i])
|
|
|
|
self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[trophyIndices[i]])
|
|
|
|
break
|
|
|
|
|
|
|
|
if not raceType == RaceGlobals.Circuit:
|
|
|
|
if not trophies[totalTrophyIndex]:
|
|
|
|
total = 0
|
|
|
|
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)
|
|
|
|
self.air.writeServerEvent('kartingTrophy', avId, '%s' % totalTrophyIndex)
|
|
|
|
self.notify.debug('trophy: ' + TTLocalizer.KartTrophyDescriptions[totalTrophyIndex])
|
|
|
|
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]:
|
|
|
|
trophies[trophyIndex] = 1
|
|
|
|
newTrophies.append(trophyIndex)
|
|
|
|
oldMaxHp = av.getMaxHp()
|
|
|
|
newMaxHp = min(ToontownGlobals.MaxHpLimit, oldMaxHp + 1)
|
|
|
|
self.notify.debug('cup awarded! new max laff : %s' % newMaxHp)
|
|
|
|
av.b_setMaxHp(newMaxHp)
|
|
|
|
av.toonUp(newMaxHp)
|
|
|
|
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)
|
|
|
|
if newHistory:
|
|
|
|
av.b_setKartingHistory(history)
|
|
|
|
return newTrophies
|
|
|
|
|
|
|
|
def checkPersonalBest(self, trackId, time, raceType, numRacers, avId):
|
|
|
|
av = simbase.air.doId2do.get(avId)
|
|
|
|
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)
|
|
|
|
|
|
|
|
def checkTimeRecord(self, trackId, time, raceType, numRacers, avId):
|
|
|
|
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
|
|
|
|
self.notify.debug('new %s record!' % TTLocalizer.RecordPeriodStrings[period])
|
|
|
|
av = simbase.air.doId2do.get(avId)
|
|
|
|
if av:
|
|
|
|
name = av.name
|
|
|
|
self.trackRecords[trackId][period].insert(record, (time, raceType, numRacers, name))
|
|
|
|
self.trackRecords[trackId][period] = self.trackRecords[trackId][period][:RaceGlobals.NumRecordsPerPeriod]
|
|
|
|
self.updateLeaderboards(trackId, period)
|
|
|
|
bonus = RaceGlobals.PeriodDict[period]
|
|
|
|
self.air.writeServerEvent('kartingRecord', avId, '%s|%s|%s' % (period, trackId, time))
|
|
|
|
else:
|
|
|
|
self.notify.warning('warning: av not logged in!')
|
|
|
|
break
|
|
|
|
|
|
|
|
if newRecord:
|
|
|
|
self.updateRecordFile()
|
|
|
|
return bonus
|
|
|
|
|
|
|
|
def updateRecordFile(self):
|
|
|
|
try:
|
|
|
|
backup = self.filename + '.bu'
|
|
|
|
if os.path.exists(self.filename):
|
|
|
|
os.rename(self.filename, backup)
|
|
|
|
file = open(self.filename, 'w')
|
|
|
|
file.seek(0)
|
2019-12-30 00:07:56 -06:00
|
|
|
pickle.dump(self.trackRecords, file)
|
2019-11-02 17:27:54 -05:00
|
|
|
file.close()
|
|
|
|
if os.path.exists(backup):
|
|
|
|
os.remove(backup)
|
|
|
|
except EnvironmentError:
|
|
|
|
self.notify.warning(str(sys.exc_info()[1]))
|
|
|
|
|
|
|
|
def getFilename(self):
|
|
|
|
return '%s%s.trackRecords' % (self.serverDataFolder, self.shard)
|
|
|
|
|
|
|
|
def loadRecords(self):
|
|
|
|
try:
|
|
|
|
file = open(self.filename + '.bu', 'r')
|
|
|
|
if os.path.exists(self.filename):
|
|
|
|
os.remove(self.filename)
|
|
|
|
except IOError:
|
|
|
|
try:
|
|
|
|
file = open(self.filename, 'r')
|
|
|
|
except IOError:
|
|
|
|
return self.getRecordTimes()
|
|
|
|
|
|
|
|
file.seek(0)
|
|
|
|
records = self.loadFrom(file)
|
|
|
|
file.close()
|
|
|
|
for trackId in RaceGlobals.TrackIds:
|
2019-12-30 00:07:56 -06:00
|
|
|
if trackId not in records:
|
2019-11-02 17:27:54 -05:00
|
|
|
records[trackId] = {}
|
|
|
|
for i in RaceGlobals.PeriodIds:
|
|
|
|
records[trackId][i] = []
|
|
|
|
for j in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
|
|
records[trackId][i].append(RaceGlobals.getDefaultRecord(trackId))
|
|
|
|
|
|
|
|
self.resetLeaderboards()
|
|
|
|
return records
|
|
|
|
|
|
|
|
def loadFrom(self, file):
|
|
|
|
records = {}
|
|
|
|
try:
|
|
|
|
while 1:
|
2019-12-30 00:07:56 -06:00
|
|
|
records = pickle.load(file)
|
2019-11-02 17:27:54 -05:00
|
|
|
|
|
|
|
except EOFError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
return records
|
|
|
|
|
|
|
|
def getRecordTimes(self):
|
|
|
|
records = {}
|
|
|
|
for trackId in RaceGlobals.TrackIds:
|
|
|
|
records[trackId] = {}
|
|
|
|
for i in RaceGlobals.PeriodIds:
|
|
|
|
records[trackId][i] = []
|
|
|
|
for j in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
|
|
records[trackId][i].append(RaceGlobals.getDefaultRecord(trackId))
|
|
|
|
|
|
|
|
return records
|
|
|
|
|
|
|
|
def resetRecordPeriod(self, period):
|
|
|
|
for trackId in RaceGlobals.TrackIds:
|
|
|
|
for i in range(0, RaceGlobals.NumRecordsPerPeriod):
|
|
|
|
self.trackRecords[trackId][period][i] = RaceGlobals.getDefaultRecord(trackId)
|
|
|
|
|
|
|
|
self.updateLeaderboards(trackId, period)
|
|
|
|
|
|
|
|
self.updateRecordFile()
|
|
|
|
|
|
|
|
def getRecords(self, trackId, period):
|
|
|
|
return self.trackRecords[trackId][period]
|
|
|
|
|
|
|
|
def updateLeaderboards(self, trackId, period):
|
|
|
|
messenger.send('UpdateRaceRecord', [(trackId, period)])
|
|
|
|
|
|
|
|
def resetLeaderboards(self):
|
|
|
|
for track in RaceGlobals.TrackIds:
|
|
|
|
for period in RaceGlobals.PeriodIds:
|
|
|
|
self.updateLeaderboards(track, period)
|
|
|
|
|
|
|
|
|
|
|
|
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):
|
|
|
|
bboard.post(KartRecordDailyResetter.PostName)
|
|
|
|
simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Daily)
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
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):
|
|
|
|
bboard.post(KartRecordWeeklyResetter.PostName)
|
|
|
|
simbase.air.raceMgr.resetRecordPeriod(RaceGlobals.Weekly)
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
bboard.remove(KartRecordWeeklyResetter.PostName)
|
|
|
|
|
|
|
|
|
|
|
|
class CircuitRaceHolidayMgr(HolidayBaseAI.HolidayBaseAI):
|
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('CircuitRaceHolidayMgr')
|
|
|
|
PostName = 'CircuitRaceHoliday'
|
|
|
|
StartStopMsg = 'CircuitRaceHolidayStartStop'
|
|
|
|
|
|
|
|
def __init__(self, air, holidayId):
|
|
|
|
HolidayBaseAI.HolidayBaseAI.__init__(self, air, holidayId)
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
bboard.post(CircuitRaceHolidayMgr.PostName, True)
|
|
|
|
simbase.air.newsManager.circuitRaceStart()
|
|
|
|
messenger.send(CircuitRaceHolidayMgr.StartStopMsg)
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
bboard.remove(CircuitRaceHolidayMgr.PostName)
|
|
|
|
simbase.air.newsManager.circuitRaceEnd()
|
|
|
|
messenger.send(CircuitRaceHolidayMgr.StartStopMsg)
|