from direct.directnotify import DirectNotifyGlobal from direct.distributed.ClockDelta import globalClockDelta from direct.fsm import FSM from direct.interval.IntervalGlobal import LerpPosInterval import math from pandac.PandaModules import Point3 import random from otp.ai.MagicWordGlobal import * from toontown.battle import BattleExperienceAI from toontown.battle import DistributedBattleDinersAI from toontown.battle import DistributedBattleWaitersAI from toontown.building import SuitBuildingGlobals from toontown.coghq import DistributedBanquetTableAI from toontown.coghq import DistributedFoodBeltAI from toontown.coghq import DistributedGolfSpotAI from toontown.suit import DistributedBossCogAI from toontown.suit import DistributedSuitAI from toontown.suit import SuitDNA from toontown.toonbase import ToontownBattleGlobals from toontown.toonbase import ToontownGlobals class DistributedBossbotBossAI(DistributedBossCogAI.DistributedBossCogAI, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBossbotBossAI') maxToonLevels = 77 toonUpLevels = [1, 2, 3, 4] def __init__(self, air): DistributedBossCogAI.DistributedBossCogAI.__init__(self, air, 'c') FSM.FSM.__init__(self, 'DistributedBossbotBossAI') self.battleOneBattlesMade = False self.battleThreeBattlesMade = False self.battleFourSetup = False self.foodBelts = [] self.numTables = 1 self.numDinersPerTable = 3 self.tables = [] self.numGolfSpots = 4 self.golfSpots = [] self.toonFoodStatus = {} self.bossMaxDamage = ToontownGlobals.BossbotBossMaxDamage self.threatDict = {} self.keyStates.append('BattleFour') self.battleFourStart = 0 self.battleDifficulty = 0 self.movingToTable = False self.tableDest = -1 self.curTable = -1 self.speedDamage = 0 self.maxSpeedDamage = ToontownGlobals.BossbotMaxSpeedDamage self.speedRecoverRate = ToontownGlobals.BossbotSpeedRecoverRate self.speedRecoverStartTime = 0 self.battleFourTimeStarted = 0 self.numDinersExploded = 0 self.numMoveAttacks = 0 self.numGolfAttacks = 0 self.numGearAttacks = 0 self.numGolfAreaAttacks = 0 self.numToonupGranted = 0 self.totalLaffHealed = 0 self.toonupsGranted = [] self.doneOvertimeOneAttack = False self.doneOvertimeTwoAttack = False self.overtimeOneTime = simbase.air.config.GetInt('overtime-one-time', 1200) self.battleFourDuration = simbase.air.config.GetInt('battle-four-duration', 1800) self.overtimeOneStart = float(self.overtimeOneTime) / self.battleFourDuration self.moveAttackAllowed = True def delete(self): self.notify.debug('DistributedBossbotBossAI.delete') self.deleteBanquetTables() self.deleteFoodBelts() self.deleteGolfSpots() return DistributedBossCogAI.DistributedBossCogAI.delete(self) def enterElevator(self): DistributedBossCogAI.DistributedBossCogAI.enterElevator(self) self.makeBattleOneBattles() def enterIntroduction(self): self.arenaSide = None self.makeBattleOneBattles() self.barrier = self.beginBarrier('Introduction', self.involvedToons, 45, self.doneIntroduction) return def makeBattleOneBattles(self): if not self.battleOneBattlesMade: self.postBattleState = 'PrepareBattleTwo' self.initializeBattles(1, ToontownGlobals.BossbotBossBattleOnePosHpr) self.battleOneBattlesMade = True def getHoodId(self): return ToontownGlobals.LawbotHQ def generateSuits(self, battleNumber): if battleNumber == 1: weakenedValue = ((1, 1), (2, 2), (2, 2), (1, 1), (1, 1, 1, 1, 1)) listVersion = list(SuitBuildingGlobals.SuitBuildingInfo) if simbase.config.GetBool('bossbot-boss-cheat', 0): listVersion[14] = weakenedValue SuitBuildingGlobals.SuitBuildingInfo = tuple(listVersion) retval = self.invokeSuitPlanner(14, 0) return retval else: suits = self.generateDinerSuits() return suits def invokeSuitPlanner(self, buildingCode, skelecog): suits = DistributedBossCogAI.DistributedBossCogAI.invokeSuitPlanner(self, buildingCode, skelecog) activeSuits = suits['activeSuits'][:] reserveSuits = suits['reserveSuits'][:] if len(activeSuits) + len(reserveSuits) >= 4: while len(activeSuits) < 4: activeSuits.append(reserveSuits.pop()[0]) retval = {'activeSuits': activeSuits, 'reserveSuits': reserveSuits} return retval def makeBattle(self, bossCogPosHpr, battlePosHpr, roundCallback, finishCallback, battleNumber, battleSide): if battleNumber == 1: battle = DistributedBattleWaitersAI.DistributedBattleWaitersAI(self.air, self, roundCallback, finishCallback, battleSide) else: battle = DistributedBattleDinersAI.DistributedBattleDinersAI(self.air, self, roundCallback, finishCallback, battleSide) self.setBattlePos(battle, bossCogPosHpr, battlePosHpr) battle.suitsKilled = self.suitsKilled battle.battleCalc.toonSkillPtsGained = self.toonSkillPtsGained battle.toonExp = self.toonExp battle.toonOrigQuests = self.toonOrigQuests battle.toonItems = self.toonItems battle.toonOrigMerits = self.toonOrigMerits battle.toonMerits = self.toonMerits battle.toonParts = self.toonParts battle.helpfulToons = self.helpfulToons mult = ToontownBattleGlobals.getBossBattleCreditMultiplier(battleNumber) battle.battleCalc.setSkillCreditMultiplier(mult) activeSuits = self.activeSuitsA if battleSide: activeSuits = self.activeSuitsB for suit in activeSuits: battle.addSuit(suit) battle.generateWithRequired(self.zoneId) return battle def initializeBattles(self, battleNumber, bossCogPosHpr): self.resetBattles() if not self.involvedToons: self.notify.warning('initializeBattles: no toons!') return self.battleNumber = battleNumber suitHandles = self.generateSuits(battleNumber) self.suitsA = suitHandles['activeSuits'] self.activeSuitsA = self.suitsA[:] self.reserveSuits = suitHandles['reserveSuits'] if battleNumber == 3: if self.toonsB: movedSuit = self.suitsA.pop() self.suitsB = [movedSuit] self.activeSuitsB = [movedSuit] self.activeSuitsA.remove(movedSuit) else: self.suitsB = [] self.activeSuitsB = [] else: suitHandles = self.generateSuits(battleNumber) self.suitsB = suitHandles['activeSuits'] self.activeSuitsB = self.suitsB[:] self.reserveSuits += suitHandles['reserveSuits'] if self.toonsA: if battleNumber == 1: self.battleA = self.makeBattle(bossCogPosHpr, ToontownGlobals.WaiterBattleAPosHpr, self.handleRoundADone, self.handleBattleADone, battleNumber, 0) self.battleAId = self.battleA.doId else: self.battleA = self.makeBattle(bossCogPosHpr, ToontownGlobals.DinerBattleAPosHpr, self.handleRoundADone, self.handleBattleADone, battleNumber, 0) self.battleAId = self.battleA.doId else: self.moveSuits(self.activeSuitsA) self.suitsA = [] self.activeSuitsA = [] if self.arenaSide == None: self.b_setArenaSide(0) if self.toonsB: if battleNumber == 1: self.battleB = self.makeBattle(bossCogPosHpr, ToontownGlobals.WaiterBattleBPosHpr, self.handleRoundBDone, self.handleBattleBDone, battleNumber, 1) self.battleBId = self.battleB.doId else: self.battleB = self.makeBattle(bossCogPosHpr, ToontownGlobals.DinerBattleBPosHpr, self.handleRoundBDone, self.handleBattleBDone, battleNumber, 1) self.battleBId = self.battleB.doId else: self.moveSuits(self.activeSuitsB) self.suitsB = [] self.activeSuitsB = [] if self.arenaSide == None: self.b_setArenaSide(1) self.sendBattleIds() return def enterPrepareBattleTwo(self): self.barrier = self.beginBarrier('PrepareBattleTwo', self.involvedToons, 45, self.__donePrepareBattleTwo) self.createFoodBelts() self.createBanquetTables() def __donePrepareBattleTwo(self, avIds): self.b_setState('BattleTwo') def exitPrepareBattleTwo(self): self.ignoreBarrier(self.barrier) def createFoodBelts(self): if self.foodBelts: return for i in xrange(2): newBelt = DistributedFoodBeltAI.DistributedFoodBeltAI(self.air, self, i) self.foodBelts.append(newBelt) newBelt.generateWithRequired(self.zoneId) def deleteFoodBelts(self): for belt in self.foodBelts: belt.requestDelete() self.foodBelts = [] def createBanquetTables(self): if self.tables: return self.calcAndSetBattleDifficulty() diffInfo = ToontownGlobals.BossbotBossDifficultySettings[self.battleDifficulty] self.diffInfo = diffInfo self.numTables = diffInfo[0] self.numDinersPerTable = diffInfo[1] dinerLevel = diffInfo[2] for i in xrange(self.numTables): newTable = DistributedBanquetTableAI.DistributedBanquetTableAI(self.air, self, i, self.numDinersPerTable, dinerLevel) self.tables.append(newTable) newTable.generateWithRequired(self.zoneId) def deleteBanquetTables(self): for table in self.tables: table.requestDelete() self.tables = [] def enterBattleTwo(self): self.resetBattles() self.createFoodBelts() self.createBanquetTables() for belt in self.foodBelts: belt.turnOn() for table in self.tables: table.turnOn() self.barrier = self.beginBarrier('BattleTwo', self.involvedToons, ToontownGlobals.BossbotBossServingDuration + 1, self.__doneBattleTwo) def exitBattleTwo(self): self.ignoreBarrier(self.barrier) for table in self.tables: table.goInactive() for belt in self.foodBelts: belt.goInactive() def __doneBattleTwo(self, avIds): self.b_setState('PrepareBattleThree') def requestGetFood(self, beltIndex, foodIndex, foodNum): grantRequest = False avId = self.air.getAvatarIdFromSender() if self.state != 'BattleTwo': grantRequest = False elif (beltIndex, foodNum) not in self.toonFoodStatus.values(): if avId not in self.toonFoodStatus: grantRequest = True elif self.toonFoodStatus[avId] == None: grantRequest = True if grantRequest: self.toonFoodStatus[avId] = (beltIndex, foodNum) self.sendUpdate('toonGotFood', [avId, beltIndex, foodIndex, foodNum]) return def requestServeFood(self, tableIndex, chairIndex): grantRequest = False avId = self.air.getAvatarIdFromSender() if self.state != 'BattleTwo': grantRequest = False elif tableIndex < len(self.tables): table = self.tables[tableIndex] dinerStatus = table.getDinerStatus(chairIndex) if dinerStatus in (table.HUNGRY, table.ANGRY): if self.toonFoodStatus[avId]: grantRequest = True if grantRequest: self.toonFoodStatus[avId] = None table.foodServed(chairIndex) self.sendUpdate('toonServeFood', [avId, tableIndex, chairIndex]) return def enterPrepareBattleThree(self): self.barrier = self.beginBarrier('PrepareBattleThree', self.involvedToons, ToontownGlobals.BossbotBossServingDuration + 1, self.__donePrepareBattleThree) self.divideToons() self.makeBattleThreeBattles() def exitPrepareBattleThree(self): self.ignoreBarrier(self.barrier) def __donePrepareBattleThree(self, avIds): self.b_setState('BattleThree') def makeBattleThreeBattles(self): if not self.battleThreeBattlesMade: if not self.tables: self.createBanquetTables() for table in self.tables: table.turnOn() table.goInactive() notDeadList = [] for table in self.tables: tableInfo = table.getNotDeadInfo() notDeadList += tableInfo self.notDeadList = notDeadList self.postBattleState = 'PrepareBattleFour' self.initializeBattles(3, ToontownGlobals.BossbotBossBattleThreePosHpr) self.battleThreeBattlesMade = True def generateDinerSuits(self): diners = [] for i in xrange(len(self.notDeadList)): if simbase.config.GetBool('bossbot-boss-cheat', 0): suit = self.__genSuitObject(self.zoneId, 2, 'c', 2, 0) else: info = self.notDeadList[i] suitType = info[2] - 4 suitLevel = info[2] suit = self.__genSuitObject(self.zoneId, suitType, 'c', suitLevel, 1) diners.append((suit, 100)) active = [] for i in xrange(2): if simbase.config.GetBool('bossbot-boss-cheat', 0): suit = self.__genSuitObject(self.zoneId, 2, 'c', 2, 0) else: suitType = 8 suitLevel = 12 suit = self.__genSuitObject(self.zoneId, suitType, 'c', suitLevel, 1) active.append(suit) return {'activeSuits': active, 'reserveSuits': diners} def __genSuitObject(self, suitZone, suitType, bldgTrack, suitLevel, revives = 0): newSuit = DistributedSuitAI.DistributedSuitAI(simbase.air, None) skel = self.__setupSuitInfo(newSuit, bldgTrack, suitLevel, suitType) if skel: newSuit.setSkelecog(1) newSuit.setSkeleRevives(revives) newSuit.generateWithRequired(suitZone) newSuit.node().setName('suit-%s' % newSuit.doId) return newSuit def __setupSuitInfo(self, suit, bldgTrack, suitLevel, suitType): dna = SuitDNA.SuitDNA() dna.newSuitRandom(suitType, bldgTrack) suit.dna = dna self.notify.debug('Creating suit type ' + suit.dna.name + ' of level ' + str(suitLevel) + ' from type ' + str(suitType) + ' and track ' + str(bldgTrack)) suit.setLevel(suitLevel) return False def enterBattleThree(self): self.makeBattleThreeBattles() self.notify.debug('self.battleA = %s' % self.battleA) if self.battleA: self.battleA.startBattle(self.toonsA, self.suitsA) if self.battleB: self.battleB.startBattle(self.toonsB, self.suitsB) def exitBattleThree(self): self.resetBattles() def enterPrepareBattleFour(self): self.resetBattles() self.setupBattleFourObjects() self.barrier = self.beginBarrier('PrepareBattleFour', self.involvedToons, 45, self.__donePrepareBattleFour) def __donePrepareBattleFour(self, avIds): self.b_setState('BattleFour') def exitPrepareBattleFour(self): self.ignoreBarrier(self.barrier) def enterBattleFour(self): self.battleFourTimeStarted = globalClock.getFrameTime() self.numToonsAtStart = len(self.involvedToons) self.resetBattles() self.setupBattleFourObjects() self.battleFourStart = globalClock.getFrameTime() self.waitForNextAttack(5) def exitBattleFour(self): self.recordCeoInfo() for belt in self.foodBelts: belt.goInactive() def recordCeoInfo(self): didTheyWin = 0 if self.bossDamage == self.bossMaxDamage: didTheyWin = 1 self.battleFourTimeInMin = globalClock.getFrameTime() - self.battleFourTimeStarted self.battleFourTimeInMin /= 60.0 self.numToonsAtEnd = 0 toonHps = [] for toonId in self.involvedToons: toon = simbase.air.doId2do.get(toonId) if toon: self.numToonsAtEnd += 1 toonHps.append(toon.hp) self.air.writeServerEvent('ceoInfo', self.doId, '%d|%.2f|%d|%d|%d|%d|%d|%d|%s|%s|%.1f|%d|%d|%d|%d|%d}%d|%s|' % (didTheyWin, self.battleFourTimeInMin, self.battleDifficulty, self.numToonsAtStart, self.numToonsAtEnd, self.numTables, self.numTables * self.numDinersPerTable, self.numDinersExploded, toonHps, self.involvedToons, self.speedDamage, self.numMoveAttacks, self.numGolfAttacks, self.numGearAttacks, self.numGolfAreaAttacks, self.numToonupGranted, self.totalLaffHealed, 'ceoBugfixes')) def setupBattleFourObjects(self): if self.battleFourSetup: return if not self.tables: self.createBanquetTables() for table in self.tables: table.goFree() if not self.golfSpots: self.createGolfSpots() self.createFoodBelts() for belt in self.foodBelts: belt.goToonup() self.battleFourSetup = True def hitBoss(self, bossDamage): avId = self.air.getAvatarIdFromSender() if not self.validate(avId, avId in self.involvedToons, 'hitBoss from unknown avatar'): return self.validate(avId, bossDamage <= 3, 'invalid bossDamage %s' % bossDamage) if bossDamage < 1: return currState = self.getCurrentOrNextState() if currState != 'BattleFour': return bossDamage *= 2 bossDamage = min(self.getBossDamage() + bossDamage, self.bossMaxDamage) self.b_setBossDamage(bossDamage, 0, 0) if self.bossDamage >= self.bossMaxDamage: self.b_setState('Victory') else: self.__recordHit(bossDamage) def __recordHit(self, bossDamage): now = globalClock.getFrameTime() self.hitCount += 1 avId = self.air.getAvatarIdFromSender() self.addThreat(avId, bossDamage) def getBossDamage(self): return self.bossDamage def b_setBossDamage(self, bossDamage, recoverRate, recoverStartTime): self.d_setBossDamage(bossDamage, recoverRate, recoverStartTime) self.setBossDamage(bossDamage, recoverRate, recoverStartTime) def setBossDamage(self, bossDamage, recoverRate, recoverStartTime): self.bossDamage = bossDamage self.recoverRate = recoverRate self.recoverStartTime = recoverStartTime def d_setBossDamage(self, bossDamage, recoverRate, recoverStartTime): timestamp = globalClockDelta.localToNetworkTime(recoverStartTime) self.sendUpdate('setBossDamage', [bossDamage, recoverRate, timestamp]) def getSpeedDamage(self): now = globalClock.getFrameTime() elapsed = now - self.speedRecoverStartTime self.notify.debug('elapsed=%s' % elapsed) floatSpeedDamage = max(self.speedDamage - self.speedRecoverRate * elapsed / 60.0, 0) self.notify.debug('floatSpeedDamage = %s' % floatSpeedDamage) return int(max(self.speedDamage - self.speedRecoverRate * elapsed / 60.0, 0)) def getFloatSpeedDamage(self): now = globalClock.getFrameTime() elapsed = now - self.speedRecoverStartTime floatSpeedDamage = max(self.speedDamage - self.speedRecoverRate * elapsed / 60.0, 0) self.notify.debug('floatSpeedDamage = %s' % floatSpeedDamage) return max(self.speedDamage - self.speedRecoverRate * elapsed / 60.0, 0) def b_setSpeedDamage(self, speedDamage, recoverRate, recoverStartTime): self.d_setSpeedDamage(speedDamage, recoverRate, recoverStartTime) self.setSpeedDamage(speedDamage, recoverRate, recoverStartTime) def setSpeedDamage(self, speedDamage, recoverRate, recoverStartTime): self.speedDamage = speedDamage self.speedRecoverRate = recoverRate self.speedRecoverStartTime = recoverStartTime def d_setSpeedDamage(self, speedDamage, recoverRate, recoverStartTime): timestamp = globalClockDelta.localToNetworkTime(recoverStartTime) self.sendUpdate('setSpeedDamage', [speedDamage, recoverRate, timestamp]) def createGolfSpots(self): if self.golfSpots: return for i in xrange(self.numGolfSpots): newGolfSpot = DistributedGolfSpotAI.DistributedGolfSpotAI(self.air, self, i) self.golfSpots.append(newGolfSpot) newGolfSpot.generateWithRequired(self.zoneId) newGolfSpot.forceFree() def deleteGolfSpots(self): for spot in self.golfSpots: spot.requestDelete() self.golfSpots = [] def ballHitBoss(self, speedDamage): avId = self.air.getAvatarIdFromSender() if not self.validate(avId, avId in self.involvedToons, 'hitBoss from unknown avatar'): return if speedDamage < 1: return currState = self.getCurrentOrNextState() if currState != 'BattleFour': return now = globalClock.getFrameTime() newDamage = self.getSpeedDamage() + speedDamage self.notify.debug('newDamage = %s' % newDamage) speedDamage = min(self.getFloatSpeedDamage() + speedDamage, self.maxSpeedDamage) self.b_setSpeedDamage(speedDamage, self.speedRecoverRate, now) self.addThreat(avId, 0.1) def enterVictory(self): self.resetBattles() for table in self.tables: table.turnOff() for golfSpot in self.golfSpots: golfSpot.turnOff() self.suitsKilled.append({'type': None, 'level': None, 'track': self.dna.dept, 'isSkelecog': 0, 'isForeman': 0, 'isBoss': 1, 'isSupervisor': 0, 'isVirtual': 0, 'activeToons': self.involvedToons[:]}) self.barrier = self.beginBarrier('Victory', self.involvedToons, 30, self.__doneVictory) return def __doneVictory(self, avIds): self.d_setBattleExperience() self.b_setState('Reward') BattleExperienceAI.assignRewards(self.involvedToons, self.toonSkillPtsGained, self.suitsKilled, ToontownGlobals.dept2cogHQ(self.dept), self.helpfulToons) for toonId in self.involvedToons: toon = self.air.doId2do.get(toonId) if toon: self.givePinkSlipReward(toon) toon.b_promote(self.deptIndex) def givePinkSlipReward(self, toon): toon.addPinkSlips(self.battleDifficulty + 1) def getThreat(self, toonId): if toonId in self.threatDict: return self.threatDict[toonId] else: return 0 def addThreat(self, toonId, threat): if toonId in self.threatDict: self.threatDict[toonId] += threat else: self.threatDict[toonId] = threat def subtractThreat(self, toonId, threat): if toonId in self.threatDict: self.threatDict[toonId] -= threat else: self.threatDict[toonId] = 0 if self.threatDict[toonId] < 0: self.threatDict[toonId] = 0 def waitForNextAttack(self, delayTime): currState = self.getCurrentOrNextState() if currState == 'BattleFour': taskName = self.uniqueName('NextAttack') taskMgr.remove(taskName) taskMgr.doMethodLater(delayTime, self.doNextAttack, taskName) def doNextAttack(self, task): attackCode = -1 optionalParam = None if self.movingToTable: self.waitForNextAttack(5) elif self.attackCode == ToontownGlobals.BossCogDizzyNow: attackCode = ToontownGlobals.BossCogRecoverDizzyAttack elif self.getBattleFourTime() > self.overtimeOneStart and not self.doneOvertimeOneAttack: attackCode = ToontownGlobals.BossCogOvertimeAttack self.doneOvertimeOneAttack = True optionalParam = 0 elif self.getBattleFourTime() > 1.0 and not self.doneOvertimeTwoAttack: attackCode = ToontownGlobals.BossCogOvertimeAttack self.doneOvertimeTwoAttack = True optionalParam = 1 else: attackCode = random.choice([ToontownGlobals.BossCogGolfAreaAttack, ToontownGlobals.BossCogDirectedAttack, ToontownGlobals.BossCogDirectedAttack, ToontownGlobals.BossCogDirectedAttack, ToontownGlobals.BossCogDirectedAttack]) if attackCode == ToontownGlobals.BossCogAreaAttack: self.__doAreaAttack() if attackCode == ToontownGlobals.BossCogGolfAreaAttack: self.__doGolfAreaAttack() elif attackCode == ToontownGlobals.BossCogDirectedAttack: self.__doDirectedAttack() elif attackCode >= 0: self.b_setAttackCode(attackCode, optionalParam) return def progressValue(self, fromValue, toValue): t0 = float(self.bossDamage) / float(self.bossMaxDamage) elapsed = globalClock.getFrameTime() - self.battleFourStart t1 = elapsed / float(self.battleThreeDuration) t = max(t0, t1) progVal = fromValue + (toValue - fromValue) * min(t, 1) self.notify.debug('progVal=%s' % progVal) return progVal def __doDirectedAttack(self): toonId = self.getMaxThreatToon() self.notify.debug('toonToAttack=%s' % toonId) unflattenedToons = self.getUnflattenedToons() attackTotallyRandomToon = random.random() < 0.1 if unflattenedToons and (attackTotallyRandomToon or toonId == 0): toonId = random.choice(unflattenedToons) if toonId: toonThreat = self.getThreat(toonId) toonThreat *= 0.25 threatToSubtract = max(toonThreat, 10) self.subtractThreat(toonId, threatToSubtract) if self.isToonRoaming(toonId): self.b_setAttackCode(ToontownGlobals.BossCogGolfAttack, toonId) self.numGolfAttacks += 1 elif self.isToonOnTable(toonId): doesMoveAttack = simbase.air.config.GetBool('ceo-does-move-attack', 1) if doesMoveAttack: chanceToShoot = 0.25 else: chanceToShoot = 1.0 if not self.moveAttackAllowed: self.notify.debug('moveAttack is not allowed, doing gearDirectedAttack') chanceToShoot = 1.0 if random.random() < chanceToShoot: self.b_setAttackCode(ToontownGlobals.BossCogGearDirectedAttack, toonId) self.numGearAttacks += 1 else: tableIndex = self.getToonTableIndex(toonId) self.doMoveAttack(tableIndex) else: self.b_setAttackCode(ToontownGlobals.BossCogGolfAttack, toonId) else: uprightTables = self.getUprightTables() if uprightTables: tableToMoveTo = random.choice(uprightTables) self.doMoveAttack(tableToMoveTo) else: self.waitForNextAttack(4) def doMoveAttack(self, tableIndex): self.numMoveAttacks += 1 self.movingToTable = True self.tableDest = tableIndex self.b_setAttackCode(ToontownGlobals.BossCogMoveAttack, tableIndex) def getUnflattenedToons(self): result = [] uprightTables = self.getUprightTables() for toonId in self.involvedToons: toonTable = self.getToonTableIndex(toonId) if toonTable >= 0 and toonTable not in uprightTables: pass else: result.append(toonId) return result def getMaxThreatToon(self): returnedToonId = 0 maxThreat = 0 maxToons = [] for toonId in self.threatDict: curThreat = self.threatDict[toonId] tableIndex = self.getToonTableIndex(toonId) if tableIndex > -1 and self.tables[tableIndex].state == 'Flat': pass elif curThreat > maxThreat: maxToons = [toonId] maxThreat = curThreat elif curThreat == maxThreat: maxToons.append(toonId) if maxToons: returnedToonId = random.choice(maxToons) return returnedToonId def getToonDifficulty(self): totalCogSuitTier = 0 totalToons = 0 for toonId in self.involvedToons: toon = simbase.air.doId2do.get(toonId) if toon: totalToons += 1 totalCogSuitTier += toon.cogTypes[1] averageTier = math.floor(totalCogSuitTier / totalToons) + 1 return int(averageTier) def calcAndSetBattleDifficulty(self): self.toonLevels = self.getToonDifficulty() battleDifficulty = int(math.floor(self.toonLevels / 2)) self.b_setBattleDifficulty(battleDifficulty) def b_setBattleDifficulty(self, batDiff): self.setBattleDifficulty(batDiff) self.d_setBattleDifficulty(batDiff) def setBattleDifficulty(self, batDiff): self.battleDifficulty = batDiff def d_setBattleDifficulty(self, batDiff): self.sendUpdate('setBattleDifficulty', [batDiff]) def getUprightTables(self): tableList = [] for table in self.tables: if table.state != 'Flat': tableList.append(table.index) return tableList def getToonTableIndex(self, toonId): tableIndex = -1 for table in self.tables: if table.avId == toonId: tableIndex = table.index break return tableIndex def getToonGolfSpotIndex(self, toonId): golfSpotIndex = -1 for golfSpot in self.golfSpots: if golfSpot.avId == toonId: golfSpotIndex = golfSpot.index break return golfSpotIndex def isToonOnTable(self, toonId): result = self.getToonTableIndex(toonId) != -1 return result def isToonOnGolfSpot(self, toonId): result = self.getToonGolfSpotIndex(toonId) != -1 return result def isToonRoaming(self, toonId): result = not self.isToonOnTable(toonId) and not self.isToonOnGolfSpot(toonId) return result def reachedTable(self, tableIndex): if self.movingToTable and self.tableDest == tableIndex: self.movingToTable = False self.curTable = self.tableDest self.tableDest = -1 def hitTable(self, tableIndex): self.notify.debug('hitTable tableIndex=%d' % tableIndex) if tableIndex < len(self.tables): table = self.tables[tableIndex] if table.state != 'Flat': table.goFlat() def awayFromTable(self, tableIndex): self.notify.debug('awayFromTable tableIndex=%d' % tableIndex) if tableIndex < len(self.tables): taskName = 'Unflatten-%d' % tableIndex unflattenTime = self.diffInfo[3] taskMgr.doMethodLater(unflattenTime, self.unflattenTable, taskName, extraArgs=[tableIndex]) def unflattenTable(self, tableIndex): if tableIndex < len(self.tables): table = self.tables[tableIndex] if table.state == 'Flat': if table.avId and table.avId in self.involvedToons: table.forceControl(table.avId) else: table.goFree() def incrementDinersExploded(self): self.numDinersExploded += 1 def magicWordHit(self, damage, avId): self.hitBoss(damage) def __doAreaAttack(self): self.b_setAttackCode(ToontownGlobals.BossCogAreaAttack) def __doGolfAreaAttack(self): self.numGolfAreaAttacks += 1 self.b_setAttackCode(ToontownGlobals.BossCogGolfAreaAttack) def hitToon(self, toonId): avId = self.air.getAvatarIdFromSender() if not self.validate(avId, avId != toonId, 'hitToon on self'): return if avId not in self.involvedToons or toonId not in self.involvedToons: return toon = self.air.doId2do.get(toonId) if toon: self.healToon(toon, 1) self.sendUpdate('toonGotHealed', [toonId]) def requestGetToonup(self, beltIndex, toonupIndex, toonupNum): grantRequest = False avId = self.air.getAvatarIdFromSender() if self.state != 'BattleFour': grantRequest = False elif (beltIndex, toonupNum) not in self.toonupsGranted: toon = simbase.air.doId2do.get(avId) if toon: grantRequest = True if grantRequest: self.toonupsGranted.insert(0, (beltIndex, toonupNum)) if len(self.toonupsGranted) > 8: self.toonupsGranted = self.toonupsGranted[0:8] self.sendUpdate('toonGotToonup', [avId, beltIndex, toonupIndex, toonupNum]) if toonupIndex < len(self.toonUpLevels): self.healToon(toon, self.toonUpLevels[toonupIndex]) self.numToonupGranted += 1 self.totalLaffHealed += self.toonUpLevels[toonupIndex] else: self.notify.warning('requestGetToonup this should not happen') self.healToon(toon, 1) def toonLeftTable(self, tableIndex): if self.movingToTable and self.tableDest == tableIndex: if random.random() < 0.5: self.movingToTable = False self.waitForNextAttack(0) def getBattleFourTime(self): if self.state != 'BattleFour': t1 = 0 else: elapsed = globalClock.getFrameTime() - self.battleFourStart t1 = elapsed / float(self.battleFourDuration) return t1 def getDamageMultiplier(self): mult = 1.0 if self.doneOvertimeOneAttack and not self.doneOvertimeTwoAttack: mult = 1.25 if self.getBattleFourTime() > 1.0: mult = self.getBattleFourTime() + 1 return mult def toggleMove(self): self.moveAttackAllowed = not self.moveAttackAllowed return self.moveAttackAllowed def getCEO(toon): for object in simbase.air.doId2do.values(): if isinstance(object, DistributedBossbotBossAI): if toon.doId in object.involvedToons: return object return None @magicWord(category=CATEGORY_ADMINISTRATOR) def skipCEOBanquet(): """ Skips to the banquet stage of the CEO. """ boss = getCEO(spellbook.getInvoker()) if not boss: return "You aren't in a CEO!" if boss.state in ('PrepareBattleTwo', 'BattleTwo'): return "You can't skip this round." boss.exitIntroduction() boss.b_setState('PrepareBattleTwo') @magicWord(category=CATEGORY_ADMINISTRATOR) def skipCEO(): """ Skips to the third round of the CEO. """ boss = getCEO(spellbook.getInvoker()) if not boss: return "You aren't in a CEO!" if boss.state in ('PrepareBattleThree', 'BattleThree'): return "You can't skip this round." boss.exitIntroduction() boss.b_setState('PrepareBattleThree') @magicWord(category=CATEGORY_ADMINISTRATOR) def skipCEOFinal(): """ Skips to the final round of the CEO. """ boss = getCEO(spellbook.getInvoker()) if not boss: return "You aren't in a CEO!" if boss.state in ('PrepareBattleFour', 'BattleFour'): return "You can't skip this round." boss.exitIntroduction() boss.b_setState('PrepareBattleFour') @magicWord(category=CATEGORY_ADMINISTRATOR) def killCEO(): """ Kills the CEO. """ boss = getCEO(spellbook.getInvoker()) if not boss: return "You aren't in a CEO!" boss.b_setState('Victory') return 'Killed CEO.'