334 lines
12 KiB
Python
334 lines
12 KiB
Python
from otp.ai.AIBase import *
|
|
from toontown.toonbase.ToontownGlobals import *
|
|
from direct.distributed.ClockDelta import *
|
|
from TrolleyConstants import *
|
|
from direct.distributed import DistributedObjectAI
|
|
from direct.fsm import ClassicFSM, State
|
|
from direct.fsm import State
|
|
from direct.task import Task
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from toontown.minigame import MinigameCreatorAI
|
|
from toontown.quest import Quests
|
|
from toontown.golf import GolfGlobals
|
|
from toontown.golf.DistributedGolfCourseAI import DistributedGolfCourseAI
|
|
import random
|
|
|
|
from toontown.dna.DNASpawnerAI import *
|
|
from toontown.dna.DNANode import DNANode
|
|
|
|
class DistributedGolfKartAI(DistributedObjectAI.DistributedObjectAI):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfKartAI')
|
|
|
|
def __init__(self, air, golfCourse, x, y, z, h, p, r):
|
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
|
self.seats = [None,
|
|
None,
|
|
None,
|
|
None]
|
|
self.golfCourse = golfCourse
|
|
self.posHpr = (x,
|
|
y,
|
|
z,
|
|
h,
|
|
p,
|
|
r)
|
|
self.color = (random.randint(GolfGlobals.KartColors[self.golfCourse][0][0], GolfGlobals.KartColors[self.golfCourse][0][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][1][0], GolfGlobals.KartColors[self.golfCourse][1][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][2][0], GolfGlobals.KartColors[self.golfCourse][2][1]))
|
|
if self.golfCourse == 1:
|
|
if self.color[0] + self.color[1] <= 255:
|
|
self.color = (self.color[0], self.color[0] + self.color[1], self.color[2])
|
|
else:
|
|
self.color = (self.color[0], 255, self.color[2])
|
|
self.accepting = 0
|
|
self.trolleyCountdownTime = config.GetFloat('trolley-countdown-time', TROLLEY_COUNTDOWN_TIME)
|
|
self.fsm = ClassicFSM.ClassicFSM('DistributedGolfKartAI', [State.State('off', self.enterOff, self.exitOff, ['entering']),
|
|
State.State('entering', self.enterEntering, self.exitEntering, ['waitEmpty']),
|
|
State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']),
|
|
State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty', 'allAboard']),
|
|
State.State('allAboard', self.enterAllAboard, self.exitAllAboard, ['leaving', 'waitEmpty']),
|
|
State.State('leaving', self.enterLeaving, self.exitLeaving, ['entering'])], 'off', 'off')
|
|
self.fsm.enterInitialState()
|
|
return
|
|
|
|
def delete(self):
|
|
self.fsm.requestFinalState()
|
|
del self.fsm
|
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
|
|
|
def findAvailableSeat(self):
|
|
for i in range(len(self.seats)):
|
|
if self.seats[i] == None:
|
|
return i
|
|
|
|
return
|
|
|
|
def findAvatar(self, avId):
|
|
for i in range(len(self.seats)):
|
|
if self.seats[i] == avId:
|
|
return i
|
|
|
|
return None
|
|
|
|
def countFullSeats(self):
|
|
avCounter = 0
|
|
for i in self.seats:
|
|
if i:
|
|
avCounter += 1
|
|
|
|
return avCounter
|
|
|
|
def rejectingBoardersHandler(self, avId):
|
|
self.rejectBoarder(avId)
|
|
|
|
def rejectBoarder(self, avId):
|
|
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
|
|
|
def acceptingBoardersHandler(self, avId):
|
|
self.notify.debug('acceptingBoardersHandler')
|
|
seatIndex = self.findAvailableSeat()
|
|
if seatIndex == None:
|
|
self.rejectBoarder(avId)
|
|
else:
|
|
self.acceptBoarder(avId, seatIndex)
|
|
return
|
|
|
|
def acceptBoarder(self, avId, seatIndex):
|
|
self.notify.debug('acceptBoarder')
|
|
if self.findAvatar(avId) != None:
|
|
return
|
|
self.seats[seatIndex] = avId
|
|
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
|
|
self.timeOfBoarding = globalClock.getRealTime()
|
|
self.sendUpdate('fillSlot' + str(seatIndex), [avId])
|
|
self.waitCountdown()
|
|
return
|
|
|
|
def __handleUnexpectedExit(self, avId):
|
|
self.notify.warning('Avatar: ' + str(avId) + ' has exited unexpectedly')
|
|
seatIndex = self.findAvatar(avId)
|
|
if seatIndex == None:
|
|
pass
|
|
else:
|
|
self.clearFullNow(seatIndex)
|
|
self.clearEmptyNow(seatIndex)
|
|
if self.countFullSeats() == 0:
|
|
self.waitEmpty()
|
|
return
|
|
|
|
def rejectingExitersHandler(self, avId):
|
|
self.rejectExiter(avId)
|
|
|
|
def rejectExiter(self, avId):
|
|
pass
|
|
|
|
def acceptingExitersHandler(self, avId):
|
|
self.acceptExiter(avId)
|
|
|
|
def acceptExiter(self, avId):
|
|
seatIndex = self.findAvatar(avId)
|
|
if seatIndex == None:
|
|
pass
|
|
else:
|
|
self.clearFullNow(seatIndex)
|
|
self.sendUpdate('emptySlot' + str(seatIndex), [avId, globalClockDelta.getRealNetworkTime()])
|
|
if self.countFullSeats() == 0:
|
|
self.waitEmpty()
|
|
taskMgr.doMethodLater(TOON_EXIT_TIME, self.clearEmptyNow, self.uniqueName('clearEmpty-%s' % seatIndex), extraArgs=(seatIndex,))
|
|
return
|
|
|
|
def clearEmptyNow(self, seatIndex):
|
|
self.sendUpdate('emptySlot' + str(seatIndex), [0, globalClockDelta.getRealNetworkTime()])
|
|
|
|
def clearFullNow(self, seatIndex):
|
|
avId = self.seats[seatIndex]
|
|
if avId == 0 or avId == None:
|
|
self.notify.warning('Clearing an empty seat index: ' + str(seatIndex) + ' ... Strange...')
|
|
else:
|
|
self.seats[seatIndex] = None
|
|
self.sendUpdate('fillSlot' + str(seatIndex), [0])
|
|
self.ignore(self.air.getAvatarExitEvent(avId))
|
|
return
|
|
|
|
def d_setState(self, state):
|
|
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
|
|
|
|
def getState(self):
|
|
return self.fsm.getCurrentState().getName()
|
|
|
|
def requestBoard(self, *args):
|
|
self.notify.debug('requestBoard')
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if self.findAvatar(avId) != None:
|
|
self.notify.warning('Ignoring multiple requests from %s to board.' % avId)
|
|
return
|
|
av = self.air.doId2do.get(avId)
|
|
if av:
|
|
newArgs = (avId,) + args
|
|
if av.hp > 0 and self.accepting:
|
|
self.acceptingBoardersHandler(*newArgs)
|
|
else:
|
|
self.rejectingBoardersHandler(*newArgs)
|
|
else:
|
|
self.notify.warning('avid: %s does not exist, but tried to board a trolley' % avId)
|
|
return
|
|
|
|
def requestExit(self, *args):
|
|
self.notify.debug('requestExit')
|
|
avId = self.air.getAvatarIdFromSender()
|
|
av = self.air.doId2do.get(avId)
|
|
if av:
|
|
newArgs = (avId,) + args
|
|
if self.accepting:
|
|
self.acceptingExitersHandler(*newArgs)
|
|
else:
|
|
self.rejectingExitersHandler(*newArgs)
|
|
else:
|
|
self.notify.warning('avId: %s does not exist, but tried to exit a trolley' % avId)
|
|
|
|
def start(self):
|
|
self.enter()
|
|
|
|
def enterOff(self):
|
|
self.accepting = 0
|
|
if hasattr(self, 'doId'):
|
|
for seatIndex in range(4):
|
|
taskMgr.remove(self.uniqueName('clearEmpty-' + str(seatIndex)))
|
|
|
|
def exitOff(self):
|
|
self.accepting = 0
|
|
|
|
def enter(self):
|
|
self.fsm.request('entering')
|
|
|
|
def enterEntering(self):
|
|
self.d_setState('entering')
|
|
self.accepting = 0
|
|
self.seats = [None,
|
|
None,
|
|
None,
|
|
None]
|
|
taskMgr.doMethodLater(TROLLEY_ENTER_TIME, self.waitEmptyTask, self.uniqueName('entering-timer'))
|
|
return
|
|
|
|
def exitEntering(self):
|
|
self.accepting = 0
|
|
taskMgr.remove(self.uniqueName('entering-timer'))
|
|
|
|
def waitEmptyTask(self, task):
|
|
self.waitEmpty()
|
|
return Task.done
|
|
|
|
def waitEmpty(self):
|
|
self.fsm.request('waitEmpty')
|
|
|
|
def enterWaitEmpty(self):
|
|
self.d_setState('waitEmpty')
|
|
self.accepting = 1
|
|
|
|
def exitWaitEmpty(self):
|
|
self.accepting = 0
|
|
|
|
def waitCountdown(self):
|
|
self.fsm.request('waitCountdown')
|
|
|
|
def enterWaitCountdown(self):
|
|
self.d_setState('waitCountdown')
|
|
self.accepting = 1
|
|
taskMgr.doMethodLater(self.trolleyCountdownTime, self.timeToGoTask, self.uniqueName('countdown-timer'))
|
|
|
|
def timeToGoTask(self, task):
|
|
if self.countFullSeats() > 0:
|
|
self.allAboard()
|
|
else:
|
|
self.waitEmpty()
|
|
return Task.done
|
|
|
|
def exitWaitCountdown(self):
|
|
self.accepting = 0
|
|
taskMgr.remove(self.uniqueName('countdown-timer'))
|
|
|
|
def allAboard(self):
|
|
self.fsm.request('allAboard')
|
|
|
|
def enterAllAboard(self):
|
|
self.accepting = 0
|
|
currentTime = globalClock.getRealTime()
|
|
elapsedTime = currentTime - self.timeOfBoarding
|
|
self.notify.debug('elapsed time: ' + str(elapsedTime))
|
|
waitTime = max(TOON_BOARD_TIME - elapsedTime, 0)
|
|
taskMgr.doMethodLater(waitTime, self.leaveTask, self.uniqueName('waitForAllAboard'))
|
|
|
|
def exitAllAboard(self):
|
|
self.accepting = 0
|
|
taskMgr.remove(self.uniqueName('waitForAllAboard'))
|
|
|
|
def leaveTask(self, task):
|
|
if self.countFullSeats() > 0:
|
|
self.leave()
|
|
else:
|
|
self.waitEmpty()
|
|
return Task.done
|
|
|
|
def leave(self):
|
|
self.fsm.request('leaving')
|
|
|
|
def enterLeaving(self):
|
|
self.d_setState('leaving')
|
|
self.accepting = 0
|
|
taskMgr.doMethodLater(TROLLEY_EXIT_TIME, self.trolleyLeftTask, self.uniqueName('leaving-timer'))
|
|
|
|
def trolleyLeftTask(self, task):
|
|
self.trolleyLeft()
|
|
return Task.done
|
|
|
|
def trolleyLeft(self):
|
|
numPlayers = self.countFullSeats()
|
|
avIdList = []
|
|
if numPlayers > 0:
|
|
for seatIndex in range(len(self.seats)):
|
|
avId = self.seats[seatIndex]
|
|
if avId != None and avId != 0:
|
|
avIdList.append(avId)
|
|
self.clearFullNow(seatIndex)
|
|
|
|
golfZone = self.air.allocateZone()
|
|
course = DistributedGolfCourseAI(golfZone, avIdList, self.golfCourse)
|
|
course.generateWithRequired(golfZone)
|
|
for avId in avIdList:
|
|
if avId:
|
|
self.sendUpdateToAvatarId(avId, 'setGolfZone', [golfZone, 0])
|
|
|
|
else:
|
|
self.notify.warning('The trolley left, but was empty.')
|
|
self.enter()
|
|
|
|
def exitLeaving(self):
|
|
self.accepting = 0
|
|
self.color = (random.randint(GolfGlobals.KartColors[self.golfCourse][0][0], GolfGlobals.KartColors[self.golfCourse][0][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][1][0], GolfGlobals.KartColors[self.golfCourse][1][1]), random.randint(GolfGlobals.KartColors[self.golfCourse][2][0], GolfGlobals.KartColors[self.golfCourse][2][1]))
|
|
if self.golfCourse == 1:
|
|
if self.color[0] + self.color[1] <= 255:
|
|
self.color = (self.color[0], self.color[0] + self.color[1], self.color[2])
|
|
else:
|
|
self.color = (self.color[0], 255, self.color[2])
|
|
self.sendUpdate('setColor', [self.color[0], self.color[1], self.color[2]])
|
|
taskMgr.remove(self.uniqueName('leaving-timer'))
|
|
|
|
def getGolfCourse(self):
|
|
return self.golfCourse
|
|
|
|
def getPosHpr(self):
|
|
return self.posHpr
|
|
|
|
def getColor(self):
|
|
return self.color
|
|
|
|
@dnaSpawn(DNANode, 'golf_kart_([0-9]+)_([0-9]+)')
|
|
def spawn(air, zone, element, match):
|
|
if config.GetBool('want-golf', True):
|
|
index = int(match.group(1))
|
|
dest = int(match.group(2))
|
|
for child in element.children:
|
|
x, y, z = child.getPos()
|
|
h, p, r = child.getHpr()
|
|
kart = DistributedGolfKartAI(air, index, x, y, z, h, p, r)
|
|
kart.generateWithRequired(zone)
|
|
kart.start()
|