188 lines
6.6 KiB
Python
188 lines
6.6 KiB
Python
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.fsm.FSM import FSM
|
|
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
from TrolleyConstants import *
|
|
from toontown.minigame.MinigameCreatorAI import *
|
|
from toontown.quest import Quests
|
|
from otp.ai.MagicWordGlobal import *
|
|
|
|
doesntWantTrolleyTracks = {}
|
|
|
|
class DistributedTrolleyAI(DistributedObjectAI, FSM):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedTrolleyAI")
|
|
|
|
def __init__(self, air):
|
|
DistributedObjectAI.__init__(self, air)
|
|
FSM.__init__(self, 'DistributedTrolleyAI')
|
|
|
|
self.trolleyCountdownTime = config.GetFloat('trolley-countdown-time', TROLLEY_COUNTDOWN_TIME)
|
|
|
|
self.slots = [None, None, None, None]
|
|
self.boardable = False
|
|
|
|
def announceGenerate(self):
|
|
self.b_setState('WaitEmpty')
|
|
|
|
def setState(self, state):
|
|
self.request(state)
|
|
|
|
def d_setState(self, state):
|
|
state = state[:1].lower() + state[1:]
|
|
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
|
|
|
|
def b_setState(self, state):
|
|
self.setState(state)
|
|
self.d_setState(state)
|
|
|
|
def enterWaitEmpty(self):
|
|
self.boardable = True
|
|
|
|
def exitWaitEmpty(self):
|
|
self.boardable = False
|
|
|
|
def enterWaitCountdown(self):
|
|
self.boardable = True
|
|
self.departureTask = taskMgr.doMethodLater(self.trolleyCountdownTime, self.__depart, 'trolleyDepartureTask')
|
|
|
|
def __depart(self, task):
|
|
self.b_setState('Leaving')
|
|
return task.done
|
|
|
|
def exitWaitCountdown(self):
|
|
taskMgr.remove(self.departureTask)
|
|
self.boardable = False
|
|
|
|
def enterLeaving(self):
|
|
self.leavingTask = taskMgr.doMethodLater(TROLLEY_EXIT_TIME, self.__activateMinigame, 'trolleyLeaveTask')
|
|
|
|
def isNewbie(self, avId):
|
|
# Does avId have the "ride the Trolley" quest?
|
|
toon = self.air.doId2do.get(avId)
|
|
if not toon:
|
|
return False
|
|
|
|
return Quests.avatarHasTrolleyQuest(toon)
|
|
|
|
def __activateMinigame(self, task):
|
|
players = [player for player in self.slots if player is not None]
|
|
|
|
if players:
|
|
# If all players disconnected while the trolley was departing, the
|
|
# players array would be empty. Therefore, we should only attempt
|
|
# to create a minigame if there are still players.
|
|
|
|
newbieIds = []
|
|
|
|
for avId in players:
|
|
# noTravel = doesntWantTrolleyTracks.get(avId)
|
|
# aiNoTravel = doesntWantTrolleyTracks.get('everyone')
|
|
|
|
if self.isNewbie(avId):
|
|
newbieIds.append(avId)
|
|
|
|
#if len(players) > 1 and not noTravel and not aiNoTravel:
|
|
# mg = createMinigame(self.air, players, self.zoneId, metagameRound=0) #TODO: use holiday manager instead of this hardcoded shit
|
|
#else:
|
|
mg = createMinigame(self.air, players, self.zoneId, newbieIds=newbieIds)
|
|
for player in players:
|
|
self.sendUpdateToAvatarId(player, 'setMinigameZone', [mg['minigameZone'], mg['minigameId']])
|
|
self.removeFromTrolley(player)
|
|
|
|
self.b_setState('Entering')
|
|
return task.done
|
|
|
|
def exitLeaving(self):
|
|
taskMgr.remove(self.leavingTask)
|
|
|
|
def enterEntering(self):
|
|
self.enteringTask = taskMgr.doMethodLater(TROLLEY_ENTER_TIME, self.__doneEntering, 'trolleyEnterTask')
|
|
|
|
def __doneEntering(self, task):
|
|
self.b_setState('WaitEmpty')
|
|
return task.done
|
|
|
|
def exitEntering(self):
|
|
taskMgr.remove(self.enteringTask)
|
|
|
|
def getBoardingSlot(self):
|
|
if not self.boardable:
|
|
return -1
|
|
|
|
if None not in self.slots:
|
|
return -1
|
|
|
|
return self.slots.index(None)
|
|
|
|
def requestBoard(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
|
|
if avId in self.slots:
|
|
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon requested to board a trolley twice!')
|
|
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
|
return
|
|
|
|
slot = self.getBoardingSlot()
|
|
if slot == -1:
|
|
self.sendUpdateToAvatarId(avId, 'rejectBoard', [avId])
|
|
return
|
|
|
|
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.removeFromTrolley, extraArgs=[avId])
|
|
|
|
self.sendUpdate('emptySlot%d' % slot, [0, globalClockDelta.getRealNetworkTime()])
|
|
self.sendUpdate('fillSlot%d' % slot, [avId])
|
|
self.slots[slot] = avId
|
|
|
|
if self.state == 'WaitEmpty':
|
|
self.b_setState('WaitCountdown')
|
|
|
|
def requestExit(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
|
|
if avId not in self.slots:
|
|
self.air.writeServerEvent('suspicious', avId=avId, issue='Toon requested to exit a trolley they are not on!')
|
|
return
|
|
|
|
if not self.boardable:
|
|
# Trolley's leaving, can't hop off!
|
|
return
|
|
|
|
self.removeFromTrolley(avId, True)
|
|
|
|
def removeFromTrolley(self, avId, hopOff=False):
|
|
if avId not in self.slots:
|
|
return
|
|
|
|
self.ignore(self.air.getAvatarExitEvent(avId))
|
|
|
|
slot = self.slots.index(avId)
|
|
self.sendUpdate('fillSlot%d' % slot, [0])
|
|
if hopOff:
|
|
# FIXME: Is this the correct way to make sure that the emptySlot
|
|
# doesn't persist, yet still animate the avId hopping off? There
|
|
# should probably be a timer that sets the slot to 0 after the
|
|
# hopoff animation finishes playing. (And such a timer will have to
|
|
# be canceled if another Toon occpuies the same slot in that time.)
|
|
self.sendUpdate('emptySlot%d' % slot, [avId, globalClockDelta.getRealNetworkTime()])
|
|
self.sendUpdate('emptySlot%d' % slot, [0, globalClockDelta.getRealNetworkTime()])
|
|
self.slots[slot] = None
|
|
|
|
if self.state == 'WaitCountdown' and self.slots.count(None) == 4:
|
|
self.b_setState('WaitEmpty')
|
|
|
|
@magicWord(category=CATEGORY_OVERRIDE, types=[str])
|
|
def travel(target='self'):
|
|
if target=='everyone':
|
|
if 'everyone' in doesntWantTrolleyTracks:
|
|
del doesntWantTrolleyTracks['everyone']
|
|
return "Re-enabled Trolley Tracks in the current district."
|
|
else:
|
|
doesntWantTrolleyTracks['everyone'] = True
|
|
return "Disabled Trolley Tracks in the current district."
|
|
else:
|
|
if spellbook.getTarget().doId in doesntWantTrolleyTracks:
|
|
del doesntWantTrolleyTracks[spellbook.getTarget().doId]
|
|
return "Re-enabled Trolley Tracks."
|
|
else:
|
|
doesntWantTrolleyTracks[spellbook.getTarget().doId] = True
|
|
return "Disabled Trolley Tracks."
|