toontown-just-works/toontown/suit/DistributedBossbotBossAI.py
2024-07-07 18:08:39 -05:00

971 lines
36 KiB
Python

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]
BossName = "CEO"
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.addStats()
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.'