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')