from direct.directnotify.DirectNotifyGlobal import directNotify from direct.distributed.ClockDelta import globalClockDelta from direct.distributed.DistributedObjectAI import DistributedObjectAI from direct.fsm import ClassicFSM, State from toontown.cogdominium import CogdoGameConsts from toontown.cogdominium.DistCogdoGameBase import DistCogdoGameBase from otp.ai.Barrier import Barrier class SadCallbackToken: pass class DistCogdoGameAI(DistCogdoGameBase, DistributedObjectAI): notify = directNotify.newCategory('DistCogdoGameAI') EndlessCogdoGames = simbase.config.GetBool('endless-cogdo-games', 0) def __init__(self, air, interior): DistributedObjectAI.__init__(self, air) self._interior = interior self.loadFSM = ClassicFSM.ClassicFSM('DistCogdoGameAI.loaded', [ State.State('NotLoaded', self.enterNotLoaded, self.exitNotLoaded, [ 'Loaded']), State.State('Loaded', self.enterLoaded, self.exitLoaded, [ 'NotLoaded'])], 'NotLoaded', 'NotLoaded') self.loadFSM.enterInitialState() self.fsm = ClassicFSM.ClassicFSM('DistCogdoGameAI', [ State.State('Visible', self.enterVisible, self.exitVisible, [ 'Intro']), State.State('Intro', self.enterIntro, self.exitIntro, [ 'Game']), State.State('Game', self.enterGame, self.exitGame, [ 'Finish']), State.State('Finish', self.enterFinish, self.exitFinish, [ 'Off']), State.State('Off', self.enterOff, self.exitOff, [ 'Visible'])], 'Off', 'Off') self.fsm.enterInitialState() self.difficultyOverride = None self.exteriorZoneOverride = None def setExteriorZone(self, exteriorZone): self.exteriorZone = exteriorZone def logSuspiciousEvent(self, avId, msg): self.air.writeServerEvent('suspicious', avId, msg) def generate(self): DistributedObjectAI.generate(self) self._sadToken2callback = {} self.notify.debug('difficulty: %s, safezoneId: %s' % (self.getDifficulty(), self.getSafezoneId())) def getInteriorId(self): return self._interior.doId def getExteriorZone(self): return self.exteriorZone def getDroneCogDNA(self): return self._interior.getDroneCogDNA() def getToonIds(self): toonIds = [] for toonId in self._interior.getToons()[0]: if toonId: toonIds.append(toonId) return toonIds def getNumPlayers(self): return len(self.getToonIds()) def requestDelete(self): self.fsm.requestFinalState() self.loadFSM.requestFinalState() self._sadToken2callback = None DistributedObjectAI.requestDelete(self) def delete(self): self._interior = None self.fsm = None self.loadFSM = None DistributedObjectAI.delete(self) def makeVisible(self): self.loadFSM.request('Loaded') self.fsm.request('Visible') def start(self): self.fsm.request('Intro') def markStartTime(self): self._startTime = globalClock.getRealTime() def getStartTime(self): return self._startTime def markFinishTime(self): self._finishTime = globalClock.getRealTime() def getFinishTime(self): return self._finishTime def setDifficultyOverrides(self, difficultyOverride, exteriorZoneOverride): self.difficultyOverride = difficultyOverride if self.difficultyOverride is not None: self.difficultyOverride = CogdoGameConsts.QuantizeDifficultyOverride(difficultyOverride) self.exteriorZoneOverride = exteriorZoneOverride def getDifficultyOverrides(self): response = [ self.difficultyOverride, self.exteriorZoneOverride] if response[0] is None: response[0] = CogdoGameConsts.NoDifficultyOverride else: response[0] *= CogdoGameConsts.DifficultyOverrideMult response[0] = int(response[0]) if response[1] is None: response[1] = CogdoGameConsts.NoExteriorZoneOverride return response def getDifficulty(self): if self.difficultyOverride is not None: return self.difficultyOverride if hasattr(self.air, 'cogdoGameDifficulty'): return float(self.air.cogdoGameDifficulty) return CogdoGameConsts.getDifficulty(self.getSafezoneId()) def getSafezoneId(self): if self.exteriorZoneOverride is not None: return self.exteriorZoneOverride if hasattr(self.air, 'cogdoGameSafezoneId'): return CogdoGameConsts.getSafezoneId(self.air.cogdoGameSafezoneId) return CogdoGameConsts.getSafezoneId(self.exteriorZone) def _validateSenderId(self, senderId): if senderId in self.getToonIds(): return True self._reportSuspiciousEvent(senderId, 'Not currently playing CogDo Game.') return False def _reportSuspiciousEvent(self, senderId, message): self.logSuspiciousEvent(senderId, message) def handleToonDisconnected(self, toonId): self.notify.debug('handleToonDisconnected: %s' % toonId) self.sendUpdate('setToonDisconnect', [ toonId]) def handleToonWentSad(self, toonId): self.notify.debug('handleToonWentSad: %s' % toonId) self.sendUpdate('setToonSad', [ toonId]) if self._sadToken2callback is not None: callbacks = list(self._sadToken2callback.values()) for callback in callbacks: callback(toonId) def _registerSadCallback(self, callback): token = SadCallbackToken() self._sadToken2callback[token] = callback return token def _unregisterSadCallback(self, token): self._sadToken2callback.pop(token) def enterNotLoaded(self): pass def exitNotLoaded(self): pass def enterLoaded(self): pass def exitLoaded(self): pass def enterOff(self): self.ignore('cogdoGameEnd') def exitOff(self): self._wasEnded = False self.accept('cogdoGameEnd', self._handleGameEnd) def enterVisible(self): self.sendUpdate('setVisible', []) def exitVisible(self): pass def enterIntro(self): self.sendUpdate('setIntroStart', []) self._introBarrier = Barrier('intro', self.uniqueName('intro'), self.getToonIds(), 1 << 20, doneFunc = self._handleIntroBarrierDone) self._sadToken = self._registerSadCallback(self._handleSadToonDuringIntro) def exitIntro(self): self._unregisterSadCallback(self._sadToken) self._sadToken = None self._introBarrier.cleanup() self._introBarrier = None def _handleSadToonDuringIntro(self, toonId): self._introBarrier.clear(toonId) def setAvatarReady(self): senderId = self.air.getAvatarIdFromSender() if senderId not in self.getToonIds(): self.logSuspiciousEvent(senderId, 'CogdoGameAI.setAvatarReady: unknown avatar') return if hasattr(self, '_introBarrier') and self._introBarrier: self._introBarrier.clear(senderId) def _handleIntroBarrierDone(self, avIds): self.fsm.request('Game') def enterGame(self): self.markStartTime() self.sendUpdate('setGameStart', [ globalClockDelta.localToNetworkTime(self.getStartTime())]) def exitGame(self): pass def _handleGameFinished(self, overrideEndless = False): if overrideEndless or not (self.EndlessCogdoGames): self.fsm.request('Finish') def _handleGameEnd(self): self._wasEnded = True if self.fsm.getCurrentState().getName() == 'Off': self.fsm.request('Intro') if self.fsm.getCurrentState().getName() == 'Intro': self.fsm.request('Game') self._handleGameFinished(overrideEndless = True) self.announceGameDone() def wasEnded(self): return self._wasEnded def enterFinish(self): self.markFinishTime() self.sendUpdate('setGameFinish', [ globalClockDelta.localToNetworkTime(self.getFinishTime())]) def exitFinish(self): pass def setScore(self, score): self._interior._setGameScore(score) def isDoorOpen(self): return True def isToonInDoor(self, toonId): return True def announceGameDone(self): self._interior._gameDone()