216 lines
No EOL
8 KiB
Python
216 lines
No EOL
8 KiB
Python
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed.ClockDelta import globalClockDelta
|
|
|
|
from DistributedPartyActivityAI import DistributedPartyActivityAI
|
|
from activityFSMs import TeamActivityAIFSM
|
|
import PartyGlobals
|
|
|
|
'''
|
|
dclass DistributedPartyTeamActivity : DistributedPartyActivity {
|
|
toonJoinRequest(uint8(0-1)) airecv clsend;
|
|
toonExitRequest(uint8(0-1)) airecv clsend;
|
|
toonSwitchTeamRequest() airecv clsend;
|
|
setPlayersPerTeam(uint8, uint8) broadcast required;
|
|
setDuration(uint8) broadcast required;
|
|
setCanSwitchTeams(bool) broadcast required;
|
|
setState(string, int16, uint32) broadcast ram;
|
|
setToonsPlaying(uint32 [0-8], uint32 [0-8]) required broadcast ram;
|
|
setAdvantage(uint16/100);
|
|
switchTeamRequestDenied(uint8);
|
|
};
|
|
'''
|
|
|
|
'''self.defaultTransitions = {'WaitForEnough': ['WaitToStart'],
|
|
'WaitToStart': ['WaitForEnough', 'WaitClientsReady'],
|
|
'WaitClientsReady': ['WaitForEnough', 'Active'],
|
|
'Active': ['WaitForEnough', 'Conclusion'],
|
|
'Conclusion': ['WaitForEnough']}'''
|
|
|
|
class DistributedPartyTeamActivityAI(DistributedPartyActivityAI):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPartyTeamActivityAI")
|
|
forbidTeamChanges = False
|
|
startDelay = PartyGlobals.TeamActivityStartDelay
|
|
|
|
def __init__(self, air, parent, activityTuple):
|
|
self.toonIds = ([], [])
|
|
self.responses = set()
|
|
self.fsm = TeamActivityAIFSM(self)
|
|
|
|
DistributedPartyActivityAI.__init__(self, air, parent, activityTuple)
|
|
|
|
def announceGenerate(self):
|
|
self.b_setState('WaitForEnough')
|
|
DistributedPartyActivityAI.announceGenerate(self)
|
|
|
|
def toonJoinRequest(self, team):
|
|
av = self._getCaller()
|
|
if not av:
|
|
return
|
|
|
|
if not self.fsm.state in ('WaitForEnough', 'WaitToStart'):
|
|
self.sendUpdateToAvatarId(av.doId, 'joinTeamRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
if len(self.toonIds[team]) >= self.getPlayersPerTeam()[1]:
|
|
self.sendUpdateToAvatarId(av.doId, 'joinTeamRequestDenied', [PartyGlobals.DenialReasons.Full])
|
|
return
|
|
|
|
if av.doId in self.toonsPlaying:
|
|
self.air.writeServerEvent('suspicious', av.doId, 'tried to join party team activity again!')
|
|
self.sendUpdateToAvatarId(av.doId, 'joinTeamRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
# idgaf if they exit unexpectedly in this case
|
|
self.toonIds[team].append(av.doId)
|
|
DistributedPartyActivityAI.toonJoinRequest(self)
|
|
self.__update()
|
|
|
|
def toonExitRequest(self, team):
|
|
av = self._getCaller()
|
|
if not av:
|
|
return
|
|
|
|
if not self.fsm.state in ('WaitForEnough', 'WaitToStart'):
|
|
self.sendUpdateToAvatarId(av.doId, 'exitRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
if not (av.doId in self.toonIds[0] or av.doId in self.toonIds[1]):
|
|
self.air.writeServerEvent('suspicious', avId, 'tried to switch DistributedPartyActivityAI team, but not in one')
|
|
self.sendUpdateToAvatarId(av.doId, 'exitRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
currentTeam = (1, 0)[av.doId in self.toonIds[0]]
|
|
self.toonIds[currentTeam].remove(av.doId)
|
|
|
|
DistributedPartyActivityAI.toonExitRequest(self)
|
|
self.__update()
|
|
|
|
def toonSwitchTeamRequest(self):
|
|
av = self._getCaller()
|
|
if not av:
|
|
return
|
|
|
|
if not self.getCanSwitchTeams():
|
|
self.air.writeServerEvent('suspicious', avId, 'tried to switch DistributedPartyActivityAI team in bad time')
|
|
self.sendUpdateToAvatarId(av.doId, 'switchTeamRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
if not (av.doId in self.toonIds[0] or av.doId in self.toonIds[1]):
|
|
self.air.writeServerEvent('suspicious', avId, 'tried to switch DistributedPartyActivityAI team, but not in one')
|
|
self.sendUpdateToAvatarId(av.doId, 'switchTeamRequestDenied', [PartyGlobals.DenialReasons.Default])
|
|
return
|
|
|
|
currentTeam = (1, 0)[av.doId in self.toonIds[0]]
|
|
otherTeam = (1, 0)[currentTeam]
|
|
|
|
if len(self.toonIds[otherTeam]) >= self.getPlayersPerTeam()[1]:
|
|
self.sendUpdateToAvatarId(av.doId, 'switchTeamRequestDenied', [PartyGlobals.DenialReasons.Full])
|
|
return
|
|
|
|
self.toonIds[currentTeam].remove(av.doId)
|
|
self.toonIds[otherTeam].append(av.doId)
|
|
|
|
self.__update()
|
|
|
|
def getPlayersPerTeam(self):
|
|
return (PartyGlobals.CogActivityMinPlayersPerTeam,
|
|
PartyGlobals.CogActivityMaxPlayersPerTeam)
|
|
|
|
def __areTeamsCorrect(self):
|
|
minPlayers = self.getPlayersPerTeam()[0]
|
|
return all(len(self.toonIds[i]) >= minPlayers for i in xrange(2))
|
|
|
|
def getDuration(self):
|
|
raise NotImplementedError('getDuration() -- pure virtual')
|
|
|
|
def getCanSwitchTeams(self):
|
|
return self.fsm.state in ('Off', 'WaitForEnough', 'WaitToStart') and not self.forbidTeamChanges
|
|
|
|
def updateToonsPlaying(self):
|
|
self.sendUpdate('setToonsPlaying', self.getToonsPlaying())
|
|
|
|
def getToonsPlaying(self):
|
|
return self.toonIds
|
|
|
|
def setAdvantage(self, todo0):
|
|
pass
|
|
|
|
def b_setState(self, state, data=0):
|
|
self.fsm.request(state, data)
|
|
self.d_setState(state, data)
|
|
|
|
def d_setState(self, state, data=0):
|
|
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime(), data])
|
|
|
|
def _getCaller(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if avId not in self.air.doId2do:
|
|
self.air.writeServerEvent('suspicious', avId, 'called some DistributedPartyActivityAI method outside shard')
|
|
return None
|
|
|
|
return self.air.doId2do[avId]
|
|
|
|
def __update(self):
|
|
self.updateToonsPlaying()
|
|
|
|
if self.fsm.state == 'WaitForEnough':
|
|
if self.__areTeamsCorrect():
|
|
self.b_setState('WaitToStart')
|
|
|
|
elif self.fsm.state == 'WaitToStart':
|
|
if not self.__areTeamsCorrect():
|
|
self.b_setState('WaitForEnough')
|
|
|
|
def startWaitForEnough(self, data):
|
|
pass
|
|
|
|
def finishWaitForEnough(self):
|
|
pass
|
|
|
|
def startWaitToStart(self, data):
|
|
def advance(task):
|
|
self.fsm.request('WaitClientsReady')
|
|
self.d_setState('Rules')
|
|
return task.done
|
|
|
|
taskMgr.doMethodLater(self.startDelay, advance, self.taskName('dostart'))
|
|
|
|
def finishWaitToStart(self):
|
|
taskMgr.remove(self.taskName('dostart'))
|
|
|
|
def __doStart(self, task = None):
|
|
self.b_setState('Active')
|
|
if task: return task.done
|
|
|
|
def startWaitClientsReady(self):
|
|
self.responses = set()
|
|
taskMgr.doMethodLater(15, self.__doStart, self.taskName('clientready'))
|
|
|
|
def finishWaitClientsReady(self):
|
|
taskMgr.remove(self.taskName('clientready'))
|
|
|
|
def toonReady(self):
|
|
self.responses.add(self.air.getAvatarIdFromSender())
|
|
if self.responses == set(self.toonsPlaying):
|
|
self.__doStart()
|
|
|
|
def startActive(self, data):
|
|
taskMgr.doMethodLater(self.getDuration(), self.__finish, self.taskName('finish'))
|
|
|
|
def finishActive(self):
|
|
taskMgr.remove(self.taskName('finish'))
|
|
|
|
def __finish(self, task):
|
|
self.calcReward()
|
|
self.b_setState('Conclusion')
|
|
return task.done
|
|
|
|
def calcReward(self):
|
|
raise NotImplementedError('calcReward() -- pure virtual')
|
|
|
|
def startConclusion(self, data):
|
|
raise NotImplementedError('startConclusion() -- pure virtual')
|
|
|
|
def finishConclusion(self):
|
|
raise NotImplementedError('finishConclusion() -- pure virtual')
|
|
|