import copy import random from direct.directnotify import DirectNotifyGlobal from direct.distributed import DistributedObjectAI from direct.distributed.ClockDelta import * from direct.fsm import ClassicFSM, State from direct.task import Timer from toontown.toon import NPCToons from otp.ai.AIBaseGlobal import * from toontown.ai import ToonBarrier from toontown.battle import BattleBase from toontown.cogdominium import DistributedCogdoBattleBldgAI from toontown.building.ElevatorConstants import * from toontown.suit.SuitDNA import SuitDNA from toontown.toonbase.ToontownBattleGlobals import * from toontown.hood import ZoneUtil from toontown.minigame.MinigameGlobals import SafeZones from toontown.toon import NPCToons from DistributedCogdoElevatorIntAI import DistributedCogdoElevatorIntAI from toontown.cogdominium import CogdoBarrelRoomConsts from toontown.cogdominium import CogdoBarrelRoomAI from DistCogdoBoardroomGameAI import DistCogdoBoardroomGameAI from toontown.cogdominium.DistCogdoCraneGameAI import DistCogdoCraneGameAI from toontown.cogdominium.DistCogdoMazeGameAI import DistCogdoMazeGameAI from toontown.cogdominium.DistCogdoFlyingGameAI import DistCogdoFlyingGameAI from toontown.cogdominium import CogdoGameConsts CogdoGames = { 'boardroom': DistCogdoBoardroomGameAI, 'crane': DistCogdoCraneGameAI, 'maze': DistCogdoMazeGameAI, 'flying': DistCogdoFlyingGameAI} IntGames = set([ 'boardroom', 'crane', 'flying', 'defense']) simbase.forcedCogdoGame = config.GetString('cogdo-game', '') GameRequests = {} class DistributedCogdoInteriorAI(DistributedObjectAI.DistributedObjectAI): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCogdoInteriorAI') def __init__(self, air, elevator): self.air = air DistributedObjectAI.DistributedObjectAI.__init__(self, air) (self.extZoneId, self.zoneId) = elevator.bldg.getExteriorAndInteriorZoneId() self._numFloors = elevator.bldg.planner.numFloors self.layout = elevator.bldg._cogdoLayout self.avatarExitEvents = [] self.toons = [] self.toonSkillPtsGained = {} self.toonExp = {} self.toonOrigQuests = {} self.toonItems = {} self.toonOrigMerits = {} self.toonMerits = {} self.toonParts = {} self.helpfulToons = [] self.shopOwnerNpcId = 0 npcDesc = NPCToons.zone2NpcDict.get(self.zoneId) if npcDesc: self.shopOwnerNpcId = npcDesc[0] if not self.shopOwnerNpcId: self.notify.warning('No npcs found for current cogdo building') self.currentFloor = 0 self.bldg = elevator.bldg self.elevator = elevator self._game = None self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0) self.suits = [] self.activeSuits = [] self.reserveSuits = [] self.joinedReserves = [] self.suitsKilled = [] self.suitsKilledPerFloor = [] self.battle = None self.timer = Timer.Timer() self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1) self.barrelRoom = None self.responses = {} self.ignoreResponses = 0 self.ignoreElevatorDone = 0 self.ignoreReserveJoinDone = 0 self.toonIds = copy.copy(elevator.seats) for toonId in self.toonIds: if toonId != None: self.__addToon(toonId) self.savedByMap = {} self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInteriorAI', [ State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, [ 'Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, [ 'Game']), State.State('Game', self.enterGame, self.exitGame, [ 'Resting', 'Failed', 'BattleIntro', 'Off']), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, [ 'CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, [ 'BarrelRoomReward', 'Off']), State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, [ 'Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, [ 'Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, [ 'ReservesJoining', 'BattleDone', 'Off']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, [ 'Battle', 'Off']), State.State('BattleDone', self.enterBattleDone, self.exitBattleDone, [ 'Resting', 'Reward', 'Off']), State.State('Resting', self.enterResting, self.exitResting, [ 'Elevator', 'Off', 'BarrelRoomIntro']), State.State('Reward', self.enterReward, self.exitReward, [ 'Off']), State.State('Failed', self.enterFailed, self.exitFailed, [ 'Off']), State.State('Off', self.enterOff, self.exitOff, [ 'WaitForAllToonsInside'])], 'Off', 'Off', onUndefTransition = ClassicFSM.ClassicFSM.ALLOW) self.fsm.enterInitialState() safeZone = ZoneUtil.getCanonicalHoodId(self.extZoneId) self.difficulty = SafeZones.index(safeZone) self.SOSCard = self.chooseSOSCard(self.difficulty) self.barrelRoomDone = False self.intElevator = None self.memoCount = 0 def generateWithRequired(self, zoneId): self._disCleanupTask = None self._sadCleanupTask = None DistributedObjectAI.DistributedObjectAI.generateWithRequired(self, zoneId) def delete(self): self.ignoreAll() self.toons = [] self.toonIds = [] self.fsm.requestFinalState() del self.fsm del self.bldg del self.elevator self.timer.stop() del self.timer self._cogdoLayout = None self.__cleanupFloorBattle() if self.barrelRoom: self.barrelRoom.destroy() self.barrelRoom = None taskName = self.taskName('deleteInterior') taskMgr.remove(taskName) if self._disCleanupTask: taskMgr.remove(self._disCleanupTask) if self._sadCleanupTask: taskMgr.remove(self._sadCleanupTask) DistributedObjectAI.DistributedObjectAI.delete(self) def requestDelete(self): if self._game: self._game.requestDelete() DistributedObjectAI.DistributedObjectAI.requestDelete(self) def getShopOwnerNpcId(self): return self.shopOwnerNpcId def getSOSNpcId(self): return self.SOSCard def __handleUnexpectedExit(self, toonId): self.notify.warning('toon: %d exited unexpectedly' % toonId) self.__removeToon(toonId) if self._game: self._game.handleToonDisconnected(toonId) if len(self.toons) == 0: self.timer.stop() if self.fsm.getCurrentState().getName() == 'Resting': pass elif self.battle == None: self.fsm.requestFinalState() self._disCleanupTask = taskMgr.doMethodLater(20, self._cleanupAfterLastToonWentDis, self.uniqueName('discleanup')) def _cleanupAfterLastToonWentDis(self, task): self._disCleanupTask = None self.bldg.deleteCogdoInterior() return task.done def _handleToonWentSad(self, toonId): self.notify.info('toon: %d went sad' % toonId) self.__removeToon(toonId) toon = self.air.getDo(toonId) if toon: self.ignore(toon.getGoneSadMessage()) if self._game: self._game.handleToonWentSad(toonId) if len(self.toons) == 0: self.timer.stop() if self.fsm.getCurrentState().getName() == 'Resting': pass elif self.battle == None: self._sadCleanupTask = taskMgr.doMethodLater(20, self._cleanupAfterLastToonWentSad, self.uniqueName('sadcleanup')) def _cleanupAfterLastToonWentSad(self, task): self._sadCleanupTask = None self.bldg.deleteCogdoInterior() return task.done def __addToon(self, toonId): if toonId not in self.air.doId2do: self.notify.warning('addToon() - no toon for doId: %d' % toonId) return event = self.air.getAvatarExitEvent(toonId) self.avatarExitEvents.append(event) self.accept(event, self.__handleUnexpectedExit, extraArgs = [ toonId]) self.toons.append(toonId) self.responses[toonId] = 0 def __removeToon(self, toonId): if self.toons.count(toonId): self.toons.remove(toonId) if self.toonIds.count(toonId): self.toonIds[self.toonIds.index(toonId)] = None if toonId in self.responses: del self.responses[toonId] event = self.air.getAvatarExitEvent(toonId) if self.avatarExitEvents.count(event): self.avatarExitEvents.remove(event) self.ignore(event) def __resetResponses(self): self.responses = {} for toon in self.toons: self.responses[toon] = 0 self.ignoreResponses = 0 def __allToonsResponded(self): for toon in self.toons: if self.responses[toon] == 0: return 0 self.ignoreResponses = 1 return 1 def getZoneId(self): return self.zoneId def getExtZoneId(self): return self.extZoneId def getDistBldgDoId(self): return self.bldg.getDoId() def getNumFloors(self): return self._numFloors def d_setToons(self): self.sendUpdate('setToons', self.getToons()) def getToons(self): sendIds = [] for toonId in self.toonIds: if toonId == None: sendIds.append(0) else: sendIds.append(toonId) return [ sendIds, 0] def getDroneCogDNA(self): dna = SuitDNA() dna.newSuitRandom(level = 2) return dna def d_setSuits(self): self.sendUpdate('setSuits', self.getSuits()) def getSuits(self): suitIds = [] for suit in self.activeSuits: suitIds.append(suit.doId) reserveIds = [] values = [] for info in self.reserveSuits: reserveIds.append(info[0].doId) values.append(info[1]) return [ suitIds, reserveIds, values] def b_setState(self, state): self.d_setState(state) self.setState(state) def d_setState(self, state): stime = globalClock.getRealTime() + BattleBase.SERVER_BUFFER_TIME self.sendUpdate('setState', [ state, globalClockDelta.localToNetworkTime(stime)]) def setState(self, state): self.fsm.request(state) def getState(self): return [ self.fsm.getCurrentState().getName(), globalClockDelta.getRealNetworkTime()] def setAvatarJoined(self): avId = self.air.getAvatarIdFromSender() if self.toons.count(avId) == 0: self.air.writeServerEvent('suspicious', avId, 'DistributedCogdoInteriorAI.setAvatarJoined from toon not in %s.' % self.toons) self.notify.warning('setAvatarJoined() - av: %d not in list' % avId) return if self.fsm.getCurrentState().getName() != 'WaitForAllToonsInside': self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.setAvatarJoined: not in wait state') return avatar = self.air.doId2do.get(avId) if avatar == None: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.setAvatarJoined: avatar not present') return else: self.savedByMap[avId] = (avatar.getName(), avatar.dna.makeNetString(), avatar.isGM()) if avId not in self.responses: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.setAvatarJoined: avId not in responses') self.notify.warning('CogdoInteriorAI.setAvatarJoined: avId not in responses') return if self.responses[avId] > 0: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.setAvatarJoined: av already responded') return self.responses[avId] += 1 if self.__allToonsResponded(): self.fsm.request('Elevator') def elevatorDone(self): toonId = self.air.getAvatarIdFromSender() if self.ignoreResponses == 1: return elif self.toons.count(toonId) == 0: self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.elevatorDone: toon not in participant list') self.notify.warning('elevatorDone() - toon not in toon list: %d' % toonId) return if self.fsm.getCurrentState().getName() != 'Elevator': self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.elevatorDone: not in Elevator state') return if toonId not in self.responses: self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.elevatorDone: toon not in responses') self.notify.warning('CogdoInteriorAI.elevatorDone: avId not in responses') return self.responses[toonId] += 1 if self.__allToonsResponded() and self.ignoreElevatorDone == 0: self.b_setState('Game') def reserveJoinDone(self): toonId = self.air.getAvatarIdFromSender() if self.ignoreResponses == 1: return elif self.toons.count(toonId) == 0: self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.reserveJoinDone: toon not in participant list') self.notify.warning('reserveJoinDone() - toon not in list: %d' % toonId) return if self.fsm.getCurrentState().getName() != 'ReservesJoining': self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.reserveJoinDone: not in ReservesJoining state') return if toonId not in self.responses: self.air.writeServerEvent('suspicious', toonId, 'CogdoInteriorAI.reserveJoinDone: toon not in responses') self.notify.warning('CogdoInteriorAI.reserveJoinDone: avId not in responses') return self.responses[toonId] += 1 if self.__allToonsResponded() and self.ignoreReserveJoinDone == 0: self.b_setState('Battle') def isBossFloor(self, floorNum): if self.layout.hasBossBattle(): if self.layout.getBossBattleFloor() == floorNum: return True return False def isTopFloor(self, floorNum): return self.layout.getNumFloors() - 1 == floorNum def enterOff(self): return None def exitOff(self): return None def enterWaitForAllToonsInside(self): self.__resetResponses() return None def exitWaitForAllToonsInside(self): self.__resetResponses() return None def enterElevator(self): if self.isBossFloor(self.currentFloor): self._populateFloorSuits() else: self.d_setToons() self.__resetResponses() if self._wantBarrelRoom: if self.barrelRoom: self.barrelRoom.reset() else: self.barrelRoom = CogdoBarrelRoomAI.CogdoBarrelRoomAI(self) self._game = self._createGame() if self._game: self._game.makeVisible() self.d_setState('Elevator') self.timer.startCallback(BattleBase.ELEVATOR_T + ElevatorData[ELEVATOR_NORMAL]['openTime'] + BattleBase.SERVER_BUFFER_TIME, self.__serverElevatorDone) return None def _createGame(self): game = None if not self.isBossFloor(self.currentFloor): for toonId in self.toonIds: if toonId: toon = self.air.getDo(toonId) if toon: self.accept(toon.getGoneSadMessage(), Functor(self._handleToonWentSad, toonId)) forcedGame = simbase.forcedCogdoGame diff = None pgId = None for toonId in self.toonIds: if toonId: if toonId in GameRequests: (forcedGame, keep, diff, pgId) = GameRequests[toonId] if not keep: GameRequests.pop(toonId) if forcedGame: gameCtor = CogdoGames[forcedGame] else: if self.bldg.track == 's': gameCtor = CogdoGames['maze'] elif self.bldg.track == 'l': gameCtor = CogdoGames['flying'] else: name = None while name is None or name in IntGames: name = random.choice(CogdoGames.keys()) gameCtor = CogdoGames[name] game = gameCtor(self.air, self) game.setExteriorZone(self.extZoneId) game.setDifficultyOverrides(diff, pgId) game.generateWithRequired(self.zoneId) return game def __serverElevatorDone(self): self.ignoreElevatorDone = 1 self.b_setState('Game') def exitElevator(self): self.timer.stop() self.__resetResponses() return None def enterGame(self): if self.currentFloor == 0: if self.bldg.track == 'l': self.notify.info('Entering Flying Game') else: self.notify.info('Entering Maze Game') self._gameScore = None self._rewardedLaff = {} self._penaltyLaff = {} self.d_setState('Game') self.elevator.d_setFloor(self.currentFloor) if self._game: self._game.start() else: self._gameDone() def _populateFloorSuits(self): suitHandles = self.bldg.planner.genFloorSuits(self.currentFloor) self.suits = suitHandles['activeSuits'] self.activeSuits = [] for suit in self.suits: self.activeSuits.append(suit) self.reserveSuits = suitHandles['reserveSuits'] self.d_setToons() self.d_setSuits() def _setGameScore(self, score): self._gameScore = score def getGameScore(self): return self._gameScore def _gameDone(self): self.__calcLaff() for (toonId, reward) in self._rewardedLaff.iteritems(): if reward: av = self.air.doId2do.get(toonId) av.toonUp(reward) for (toonId, penalty) in self._penaltyLaff.iteritems(): if penalty: av = self.air.doId2do.get(toonId) if config.GetBool('want-cogdo-maze-no-sad', 1): avHp = av.getHp() if avHp < 1: avHp = 1 if penalty >= avHp: penalty = avHp - 1 if penalty: av.takeDamage(penalty, quietly = 0) if self._game and self._game.wasEnded(): self.b_setState('Resting') elif self._game and self._game.isDoorOpen(): self.b_setState('Resting') elif self._game and not self._game.isDoorOpen(): self.b_setState('Failed') else: self.b_setState('BattleIntro') def exitGame(self): self.sendUpdate('setSOSNpcId', [ self.SOSCard]) self.sendUpdate('setFOType', [ ord(self.bldg.track)]) def __calcLaff(self): self.notify.debug('__calcLaff()') self._rewardedLaff = {} self._penaltyLaff = {} if self._game: score = self.getGameScore() if score: maxToAward = self._game.getDifficulty() * CogdoGameConsts.LaffRewardRange + CogdoGameConsts.LaffRewardMin reward = score * maxToAward for toonId in self.toons: if self._game.isToonInDoor(toonId): self._rewardedLaff[toonId] = reward if self._rewardedLaff: self.air.writeServerEvent('CogdoLaffReward', self._rewardedLaff.keys(), 'Awarded %s Laff for difficulty %s and score %s' % (reward, self._game.getDifficulty(), score)) penalty = self._game.getDifficulty() * CogdoGameConsts.LaffPenalty for toonId in self.toons: if not self._game.isToonInDoor(toonId): self._penaltyLaff[toonId] = penalty if self._penaltyLaff: self.air.writeServerEvent('CogdoLaffPenalty', self._penaltyLaff.keys(), 'Penalized %s Laff for difficulty %s (did not reach exit)' % (penalty, self._game.getDifficulty())) def toonBarrelRoomIntroDone(self): avId = self.air.getAvatarIdFromSender() if self.fsm.getCurrentState().getName() != 'BarrelRoomIntro': self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonBarrelRoomIntroDone: not in BarrelRoomIntro state') return if avId not in self.responses: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonBarrelRoomIntroDone: unknown avId') return if hasattr(self, 'brBarrier'): self.brBarrier.clear(avId) else: self.notify.warning('toonBarrelRoomIntroDone from %s in invalid state' % avId) def __brIntroDone(self, clearedAvIds = []): self.b_setState('CollectBarrels') def enterBarrelRoomIntro(self): if not self._wantBarrelRoom: pass if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.barrelRoom.setScore(1.0) self.brBarrier = ToonBarrier.ToonBarrier('waitBrIntroDone', self.uniqueName('waitBrIntroDone'), self.toons, CogdoBarrelRoomConsts.BarrelRoomIntroTimeout, doneFunc = self.__brIntroDone) else: self.__brIntroDone() def exitBarrelRoomIntro(self): if hasattr(self, 'brBarrier'): self.brBarrier.cleanup() del self.brBarrier def __endCollectBarrels(self): if len(self.toons) > 0: self.notify.info('%d toons in barrel room.' % len(self.toons)) self.b_setState('BarrelRoomReward') else: self.notify.warning('0 toons in barrel room.') self.bldg.deleteCogdoInterior() def toonLeftBarrelRoom(self): avId = self.air.getAvatarIdFromSender() self.notify.info('avId=%s left the barrel room via teleport' % avId) if self.fsm.getCurrentState().getName() != 'CollectBarrels': self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonLeftBarrelRoom called outside of CollectBarrels state') return if avId not in self.responses: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonLeftBarrelRoom: unknown avId') return self.__removeToon(avId) self.notify.info('%d toon(s) remaining in barrel room.' % len(self.toons)) if len(self.toons) == 0: self.notify.warning('0 toons in barrel room.') self.bldg.deleteCogdoInterior() def enterCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.acceptOnce(self.barrelRoom.collectionDoneEvent, self.__endCollectBarrels) self.barrelRoom.activate() else: self.__endCollectBarrels() def exitCollectBarrels(self): if self.barrelRoom: self.ignore(self.barrelRoom.collectionDoneEvent) self.barrelRoom.deactivate() def toonBarrelRoomRewardDone(self): avId = self.air.getAvatarIdFromSender() if self.fsm.getCurrentState().getName() != 'BarrelRoomReward': self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonBarrelRoomIntroDone: not in BarrelRoomReward state') return if avId not in self.responses: self.air.writeServerEvent('suspicious', avId, 'CogdoInteriorAI.toonBarrelRoomRewardDone: unknown avId') return if hasattr(self, 'brBarrier'): self.brBarrier.clear(avId) else: self.notify.warning('toonBarrelRoomRewardDone from %s in invalid state' % avId) def __brRewardDone(self, clearedAvIds = []): self.barrelRoomDone = True if len(self.toons) > 0: if not self.isBossFloor(self.currentFloor): self._populateFloorSuits() self.b_setState('Battle') else: self.b_setState('BattleIntro') else: self.notify.warning('0 toons in barrel room.') self.bldg.deleteCogdoInterior() def enterBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.sendUpdate('setBarrelRoomReward', self.barrelRoom.results) self.brBarrier = ToonBarrier.ToonBarrier('waitBrRewardDone', self.uniqueName('waitBrRewardDone'), self.toons, CogdoBarrelRoomConsts.RewardUiTime + 5.0, doneFunc = self.__brRewardDone) else: self.__brRewardDone() def exitBarrelRoomReward(self): if hasattr(self, 'brBarrier'): self.brBarrier.cleanup() del self.brBarrier def __createFloorBattle(self): if self.isBossFloor(self.currentFloor): self.notify.info('%d toon(s) in boss battle' % len(self.toons)) bossBattle = 1 else: self.notify.info('%d toon(s) in barrel battle' % len(self.toons)) bossBattle = 0 self.battle = DistributedCogdoBattleBldgAI.DistributedCogdoBattleBldgAI(self.air, self.zoneId, self.__handleRoundDone, self.__handleBattleDone, bossBattle = bossBattle) self.battle.suitsKilled = self.suitsKilled self.battle.suitsKilledPerFloor = self.suitsKilledPerFloor self.battle.battleCalc.toonSkillPtsGained = self.toonSkillPtsGained self.battle.toonExp = self.toonExp self.battle.toonOrigQuests = self.toonOrigQuests self.battle.toonItems = self.toonItems self.battle.toonOrigMerits = self.toonOrigMerits self.battle.toonMerits = self.toonMerits self.battle.toonParts = self.toonParts self.battle.helpfulToons = self.helpfulToons self.battle.setInitialMembers(self.toons, self.suits) self.battle.generateWithRequired(self.zoneId) mult = getCreditMultiplier(self.currentFloor) if self.air.suitInvasionManager.getInvading(): mult *= getInvasionMultiplier() self.battle.battleCalc.setSkillCreditMultiplier(mult) def __cleanupFloorBattle(self): for suit in self.suits: self.notify.debug('cleaning up floor suit: %d' % suit.doId) if suit.isDeleted(): self.notify.debug('whoops, suit %d is deleted.' % suit.doId) else: suit.requestDelete() self.suits = [] self.reserveSuits = [] self.activeSuits = [] if self.battle != None: self.battle.requestDelete() self.battle = None def __handleRoundDone(self, toonIds, totalHp, deadSuits): totalMaxHp = 0 for suit in self.suits: totalMaxHp += suit.maxHP for suit in deadSuits: self.activeSuits.remove(suit) if len(self.reserveSuits) > 0 and len(self.activeSuits) < 4: self.joinedReserves = [] hpPercent = 100 - (totalHp / totalMaxHp) * 100.0 for info in self.reserveSuits: if info[1] <= hpPercent and len(self.activeSuits) < 4: self.suits.append(info[0]) self.activeSuits.append(info[0]) self.joinedReserves.append(info) for info in self.joinedReserves: self.reserveSuits.remove(info) if len(self.joinedReserves) > 0: self.fsm.request('ReservesJoining') self.d_setSuits() return if len(self.activeSuits) == 0: self.fsm.request('BattleDone', [ toonIds]) else: self.battle.resume() def __handleBattleDone(self, zoneId, toonIds): if len(toonIds) == 0: self.notify.info('handleBattleDone() - last toon gone') taskName = self.taskName('deleteInterior') taskMgr.doMethodLater(10, self.__doDeleteInterior, taskName) elif self.isTopFloor(self.currentFloor): self.setState('Reward') else: self.b_setState('Resting') def __doDeleteInterior(self, task): self.bldg.deleteCogdoInterior() def enterBattleIntro(self): timeLeft = 7.0 self._battleIntroTaskName = self.taskName('BattleIntro') taskMgr.doMethodLater(timeLeft, self._battleIntroDone, self._battleIntroTaskName) def _battleIntroDone(self, task): self.b_setState('Battle') return task.done def exitBattleIntro(self): taskMgr.remove(self._battleIntroTaskName) self._battleIntroTaskName = None def enterBattle(self): if self.battle == None: self.__createFloorBattle() def exitBattle(self): return None def enterReservesJoining(self): self.__resetResponses() self.timer.startCallback(ElevatorData[ELEVATOR_NORMAL]['openTime'] + SUIT_HOLD_ELEVATOR_TIME + BattleBase.SERVER_BUFFER_TIME, self.__serverReserveJoinDone) return None def __serverReserveJoinDone(self): self.ignoreReserveJoinDone = 1 self.b_setState('Battle') def exitReservesJoining(self): self.timer.stop() self.__resetResponses() for info in self.joinedReserves: self.battle.suitRequestJoin(info[0]) self.battle.resume() self.joinedReserves = [] return None def enterBattleDone(self, toonIds): if len(toonIds) != len(self.toons): deadToons = [] for toon in self.toons: if toonIds.count(toon) == 0: deadToons.append(toon) for toon in deadToons: self.__removeToon(toon) self.d_setToons() if len(self.toons) == 0: self.bldg.deleteCogdoInterior() elif self.isTopFloor(self.currentFloor): self.notify.info('%d Toon(s) beat the executive suite building' % len(self.toons)) self.battle.resume(self.currentFloor, topFloor = 1) else: self.battle.resume(self.currentFloor, topFloor = 0) return None def exitBattleDone(self): self.__cleanupFloorBattle() self.d_setSuits() return None def __handleEnterElevator(self): self.fsm.request('Elevator') def enterResting(self): if self._game: if hasattr(self._game, 'memoCount'): self.memoCount = self._game.memoCount self._game.requestDelete() self._game = None for toonId in self.toonIds: if toonId: toon = self.air.getDo(toonId) if toon: self.ignore(toon.getGoneSadMessage()) if not self.barrelRoomDone: self.handleAllAboard() else: self.currentFloor += 1 self.intElevator = DistributedCogdoElevatorIntAI(self.air, self, self.toons) self.intElevator.generateWithRequired(self.zoneId) def handleAllAboard(self, seats = None): if seats == None: seats = copy.copy(self.toonIds) if not hasattr(self, 'fsm'): return None numOfEmptySeats = seats.count(None) if numOfEmptySeats == 4: self.bldg.deleteCogdoInterior() return None elif numOfEmptySeats >= 0 and numOfEmptySeats <= 3: pass else: self.error('Bad number of empty seats: %s' % numOfEmptySeats) for toon in self.toons: if seats.count(toon) == 0: self.__removeToon(toon) self.toonIds = copy.copy(seats) self.toons = [] for toonId in self.toonIds: if toonId != None: self.toons.append(toonId) self.d_setToons() if not self._CogdoGameRepeat: if self.bldg.track in ('s', 'l') and self.currentFloor != 2: self.currentFloor += 1 if self.bldg.track == 'l' and self.currentFloor != 2: self.b_setState('BarrelRoomIntro') else: self.fsm.request('Elevator') def exitResting(self): if self.intElevator: self.intElevator.requestDelete() return None def enterReward(self): victors = self.toonIds[:] savedBy = [] for v in victors: tuple = self.savedByMap.get(v) if tuple: savedBy.append([ v, tuple[0], tuple[1], tuple[2]]) toon = self.air.doId2do.get(v) if toon: self.notify.info('Reward State: toonId:%d laff:%d/%d get ready for the victors to come outside' % (toon.doId, toon.hp, toon.maxHp)) if self.bldg.track == 'l': emblemReward = self.getEmblemReward() toon.addEmblems(emblemReward) else: if not toon.attemptAddNPCFriend(self.SOSCard, numCalls = 1): self.notify.info('%s.unable to add NPCFriend %s to %s.' % (self.doId, self.SOSCard, v)) self.bldg.fsm.request('waitForVictorsFromCogdo', [ victors, savedBy]) self.d_setState('Reward') return None def exitReward(self): return None def enterFailed(self): victors = self.toonIds[:] savedBy = [] anyVictors = victors.count(None) < 4 if anyVictors: self.bldg.fsm.request('waitForVictorsFromCogdo', [ victors, savedBy]) def exitFailed(self): return None def chooseSOSCard(self, difficulty): if difficulty < 0 or difficulty > 5: return None if difficulty <= 1: card = random.choice(NPCToons.npcFriendsMinMaxStars(0, 1)) elif difficulty <= 3: card = random.choice(NPCToons.npcFriendsMinMaxStars(1, 1)) else: card = random.choice(NPCToons.npcFriendsMinMaxStars(2, 2)) return card def getEmblemReward(self): hoodIdMap = { 2: 0.5, # TTC 1: 1.0, # DD 5: 1.5, # DG 4: 2.0, # MML 3: 2.7, # TB 9: 3.5 # DDL } hoodValue = hoodIdMap[int(self.extZoneId // 1000)] diff = max(self.difficulty, 1) memos = self.memoCount E = (hoodValue * max(memos, 1) * diff) / 2.5 return divmod(E, 100)[::-1]