toontown-just-works/toontown/suit/DistributedCashbotBossAI.py

552 lines
19 KiB
Python
Raw Permalink Normal View History

2024-07-07 18:08:39 -05:00
from panda3d.core import *
from direct.directnotify import DirectNotifyGlobal
from toontown.toonbase import ToontownGlobals
from toontown.coghq import DistributedCashbotBossCraneAI
from toontown.coghq import DistributedCashbotBossSafeAI
from toontown.suit import DistributedCashbotBossGoonAI
from toontown.coghq import DistributedCashbotBossTreasureAI
from toontown.battle import BattleExperienceAI
from toontown.chat import ResistanceChat
from direct.fsm import FSM
import DistributedBossCogAI
import SuitDNA
import random
from otp.ai.MagicWordGlobal import *
import math
class DistributedCashbotBossAI(DistributedBossCogAI.DistributedBossCogAI, FSM.FSM):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCashbotBossAI')
maxGoons = 8
BossName = "CFO"
def __init__(self, air):
DistributedBossCogAI.DistributedBossCogAI.__init__(self, air, 'm')
FSM.FSM.__init__(self, 'DistributedCashbotBossAI')
self.cranes = None
self.safes = None
self.goons = None
self.treasures = {}
self.grabbingTreasures = {}
self.recycledTreasures = []
self.healAmount = 0
self.rewardId = ResistanceChat.getRandomId()
self.rewardedToons = []
self.scene = NodePath('scene')
self.reparentTo(self.scene)
cn = CollisionNode('walls')
cs = CollisionSphere(0, 0, 0, 13)
cn.addSolid(cs)
cs = CollisionInvSphere(0, 0, 0, 42)
cn.addSolid(cs)
self.attachNewNode(cn)
self.heldObject = None
self.waitingForHelmet = 0
self.avatarHelmets = {}
self.bossMaxDamage = ToontownGlobals.CashbotBossMaxDamage
return
def generate(self):
DistributedBossCogAI.DistributedBossCogAI.generate(self)
def getHoodId(self):
return ToontownGlobals.CashbotHQ
def formatReward(self):
return str(self.rewardId)
def makeBattleOneBattles(self):
self.postBattleState = 'PrepareBattleThree'
self.initializeBattles(1, ToontownGlobals.CashbotBossBattleOnePosHpr)
def generateSuits(self, battleNumber):
cogs = self.invokeSuitPlanner(11, 0)
skelecogs = self.invokeSuitPlanner(12, 1)
activeSuits = cogs['activeSuits'] + skelecogs['activeSuits']
reserveSuits = cogs['reserveSuits'] + skelecogs['reserveSuits']
random.shuffle(activeSuits)
while len(activeSuits) > 4:
suit = activeSuits.pop()
reserveSuits.append((suit, 100))
def compareJoinChance(a, b):
return cmp(a[1], b[1])
reserveSuits.sort(compareJoinChance)
return {'activeSuits': activeSuits,
'reserveSuits': reserveSuits}
def removeToon(self, avId):
if self.cranes != None:
for crane in self.cranes:
crane.removeToon(avId)
if self.safes != None:
for safe in self.safes:
safe.removeToon(avId)
if self.goons != None:
for goon in self.goons:
goon.removeToon(avId)
DistributedBossCogAI.DistributedBossCogAI.removeToon(self, avId)
return
def __makeBattleThreeObjects(self):
if self.cranes == None:
self.cranes = []
for index in xrange(len(ToontownGlobals.CashbotBossCranePosHprs)):
crane = DistributedCashbotBossCraneAI.DistributedCashbotBossCraneAI(self.air, self, index)
crane.generateWithRequired(self.zoneId)
self.cranes.append(crane)
if self.safes == None:
self.safes = []
for index in xrange(len(ToontownGlobals.CashbotBossSafePosHprs)):
safe = DistributedCashbotBossSafeAI.DistributedCashbotBossSafeAI(self.air, self, index)
safe.generateWithRequired(self.zoneId)
self.safes.append(safe)
if self.goons == None:
self.goons = []
return
def __resetBattleThreeObjects(self):
if self.cranes != None:
for crane in self.cranes:
crane.request('Free')
if self.safes != None:
for safe in self.safes:
safe.request('Initial')
return
def __deleteBattleThreeObjects(self):
if self.cranes != None:
for crane in self.cranes:
crane.request('Off')
crane.requestDelete()
self.cranes = None
if self.safes != None:
for safe in self.safes:
safe.request('Off')
safe.requestDelete()
self.safes = None
if self.goons != None:
for goon in self.goons:
goon.request('Off')
goon.requestDelete()
self.goons = None
return
def doNextAttack(self, task):
if random.random() <= 0.2:
self.b_setAttackCode(ToontownGlobals.BossCogAreaAttack)
taskMgr.doMethodLater(7.36, self.__reviveGoons, self.uniqueName('reviveGoons'))
else:
self.__doDirectedAttack()
if self.heldObject == None and not self.waitingForHelmet:
self.waitForNextHelmet()
def __reviveGoons(self, task):
for goon in self.goons:
if goon.state == 'Stunned':
goon.request('Recovery')
def __doDirectedAttack(self):
if self.toonsToAttack:
toonId = self.toonsToAttack.pop(0)
while toonId not in self.involvedToons:
if not self.toonsToAttack:
self.b_setAttackCode(ToontownGlobals.BossCogNoAttack)
return
toonId = self.toonsToAttack.pop(0)
self.toonsToAttack.append(toonId)
self.b_setAttackCode(ToontownGlobals.BossCogSlowDirectedAttack, toonId)
def reprieveToon(self, avId):
if avId in self.toonsToAttack:
i = self.toonsToAttack.index(avId)
del self.toonsToAttack[i]
self.toonsToAttack.append(avId)
def makeTreasure(self, goon):
if self.state != 'BattleThree':
return
pos = goon.getPos(self)
v = Vec3(pos[0], pos[1], 0.0)
if not v.normalize():
v = Vec3(1, 0, 0)
v = v * 27
angle = random.uniform(0.0, 2.0 * math.pi)
radius = 10
dx = radius * math.cos(angle)
dy = radius * math.sin(angle)
fpos = self.scene.getRelativePoint(self, Point3(v[0] + dx, v[1] + dy, 0))
if goon.strength <= 10:
style = ToontownGlobals.ToontownCentral
healAmount = 3
elif goon.strength <= 15:
style = random.choice([ToontownGlobals.DonaldsDock, ToontownGlobals.DaisyGardens, ToontownGlobals.MinniesMelodyland])
healAmount = 10
else:
style = random.choice([ToontownGlobals.TheBrrrgh, ToontownGlobals.DonaldsDreamland])
healAmount = 12
if self.recycledTreasures:
treasure = self.recycledTreasures.pop(0)
treasure.d_setGrab(0)
treasure.b_setGoonId(goon.doId)
treasure.b_setStyle(style)
treasure.b_setPosition(pos[0], pos[1], 0)
treasure.b_setFinalPosition(fpos[0], fpos[1], 0)
else:
treasure = DistributedCashbotBossTreasureAI.DistributedCashbotBossTreasureAI(self.air, self, goon, style, fpos[0], fpos[1], 0)
treasure.generateWithRequired(self.zoneId)
treasure.healAmount = healAmount
self.treasures[treasure.doId] = treasure
def grabAttempt(self, avId, treasureId):
av = self.air.doId2do.get(avId)
if not av:
return
treasure = self.treasures.get(treasureId)
if treasure:
if treasure.validAvatar(av):
del self.treasures[treasureId]
treasure.d_setGrab(avId)
self.grabbingTreasures[treasureId] = treasure
taskMgr.doMethodLater(5, self.__recycleTreasure, treasure.uniqueName('recycleTreasure'), extraArgs=[treasure])
else:
treasure.d_setReject()
def __recycleTreasure(self, treasure):
if treasure.doId in self.grabbingTreasures:
del self.grabbingTreasures[treasure.doId]
self.recycledTreasures.append(treasure)
def deleteAllTreasures(self):
for treasure in self.treasures.values():
treasure.requestDelete()
self.treasures = {}
for treasure in self.grabbingTreasures.values():
taskMgr.remove(treasure.uniqueName('recycleTreasure'))
treasure.requestDelete()
self.grabbingTreasures = {}
for treasure in self.recycledTreasures:
treasure.requestDelete()
self.recycledTreasures = []
def getMaxGoons(self):
t = self.getBattleThreeTime()
if t <= 1.0:
return self.maxGoons
elif t <= 1.1:
return self.maxGoons + 1
elif t <= 1.2:
return self.maxGoons + 2
elif t <= 1.3:
return self.maxGoons + 3
elif t <= 1.4:
return self.maxGoons + 4
else:
return self.maxGoons + 8
def makeGoon(self, side = None):
if side == None:
side = random.choice(['EmergeA', 'EmergeB'])
goon = self.__chooseOldGoon()
if goon == None:
if len(self.goons) >= self.getMaxGoons():
return
goon = DistributedCashbotBossGoonAI.DistributedCashbotBossGoonAI(self.air, self)
goon.generateWithRequired(self.zoneId)
self.goons.append(goon)
if self.getBattleThreeTime() > 1.0:
goon.STUN_TIME = 4
goon.b_setupGoon(velocity=8, hFov=90, attackRadius=20, strength=30, scale=1.8)
else:
goon.STUN_TIME = self.progressValue(30, 8)
goon.b_setupGoon(velocity=self.progressRandomValue(3, 7), hFov=self.progressRandomValue(70, 80), attackRadius=self.progressRandomValue(6, 15), strength=int(self.progressRandomValue(5, 25)), scale=self.progressRandomValue(0.5, 1.5))
goon.request(side)
return
def __chooseOldGoon(self):
for goon in self.goons:
if goon.state == 'Off':
return goon
def waitForNextGoon(self, delayTime):
currState = self.getCurrentOrNextState()
if currState == 'BattleThree':
taskName = self.uniqueName('NextGoon')
taskMgr.remove(taskName)
taskMgr.doMethodLater(delayTime, self.doNextGoon, taskName)
def stopGoons(self):
taskName = self.uniqueName('NextGoon')
taskMgr.remove(taskName)
taskMgr.remove(self.uniqueName('reviveGoons'))
def doNextGoon(self, task):
if self.attackCode != ToontownGlobals.BossCogDizzy:
self.makeGoon()
delayTime = self.progressValue(10, 2)
self.waitForNextGoon(delayTime)
def waitForNextHelmet(self):
currState = self.getCurrentOrNextState()
if currState == 'BattleThree':
taskName = self.uniqueName('NextHelmet')
taskMgr.remove(taskName)
delayTime = self.progressValue(45, 15)
taskMgr.doMethodLater(delayTime, self.__donHelmet, taskName)
self.waitingForHelmet = 1
def __donHelmet(self, task):
self.waitingForHelmet = 0
if self.heldObject == None:
safe = self.safes[0]
safe.request('Grabbed', self.doId, self.doId)
self.heldObject = safe
return
def stopHelmets(self):
self.waitingForHelmet = 0
taskName = self.uniqueName('NextHelmet')
taskMgr.remove(taskName)
def acceptHelmetFrom(self, avId):
now = globalClock.getFrameTime()
then = self.avatarHelmets.get(avId, None)
if then == None or now - then > 300:
self.avatarHelmets[avId] = now
return 1
return 0
def magicWordHit(self, damage, avId):
if self.heldObject:
self.heldObject.demand('Dropped', avId, self.doId)
self.heldObject.avoidHelmet = 1
self.heldObject = None
self.waitForNextHelmet()
else:
self.recordHit(damage)
return
def magicWordReset(self):
if self.state == 'BattleThree':
self.__resetBattleThreeObjects()
def magicWordResetGoons(self):
if self.state == 'BattleThree':
if self.goons != None:
for goon in self.goons:
goon.request('Off')
goon.requestDelete()
self.goons = None
self.__makeBattleThreeObjects()
return
def recordHit(self, damage):
avId = self.air.getAvatarIdFromSender()
if not self.validate(avId, avId in self.involvedToons, 'recordHit from unknown avatar'):
return
if self.state != 'BattleThree':
return
self.b_setBossDamage(self.bossDamage + damage)
if self.bossDamage >= self.bossMaxDamage:
self.b_setState('Victory')
elif self.attackCode != ToontownGlobals.BossCogDizzy:
if damage >= ToontownGlobals.CashbotBossKnockoutDamage:
self.b_setAttackCode(ToontownGlobals.BossCogDizzy)
self.stopHelmets()
else:
self.b_setAttackCode(ToontownGlobals.BossCogNoAttack)
self.stopHelmets()
self.waitForNextHelmet()
def b_setBossDamage(self, bossDamage):
self.d_setBossDamage(bossDamage)
self.setBossDamage(bossDamage)
def setBossDamage(self, bossDamage):
self.reportToonHealth()
self.bossDamage = bossDamage
def d_setBossDamage(self, bossDamage):
self.sendUpdate('setBossDamage', [bossDamage])
def d_setRewardId(self, rewardId):
self.sendUpdate('setRewardId', [rewardId])
def applyReward(self):
avId = self.air.getAvatarIdFromSender()
if avId in self.involvedToons and avId not in self.rewardedToons:
self.rewardedToons.append(avId)
toon = self.air.doId2do.get(avId)
if toon:
toon.doResistanceEffect(self.rewardId)
def enterOff(self):
DistributedBossCogAI.DistributedBossCogAI.enterOff(self)
self.rewardedToons = []
def exitOff(self):
DistributedBossCogAI.DistributedBossCogAI.exitOff(self)
def enterIntroduction(self):
DistributedBossCogAI.DistributedBossCogAI.enterIntroduction(self)
self.__makeBattleThreeObjects()
self.__resetBattleThreeObjects()
def exitIntroduction(self):
DistributedBossCogAI.DistributedBossCogAI.exitIntroduction(self)
self.__deleteBattleThreeObjects()
def enterPrepareBattleThree(self):
self.resetBattles()
self.__makeBattleThreeObjects()
self.__resetBattleThreeObjects()
self.barrier = self.beginBarrier('PrepareBattleThree', self.involvedToons, 55, self.__donePrepareBattleThree)
def __donePrepareBattleThree(self, avIds):
self.b_setState('BattleThree')
def exitPrepareBattleThree(self):
if self.newState != 'BattleThree':
self.__deleteBattleThreeObjects()
self.ignoreBarrier(self.barrier)
def enterBattleThree(self):
self.setPosHpr(*ToontownGlobals.CashbotBossBattleThreePosHpr)
self.__makeBattleThreeObjects()
self.__resetBattleThreeObjects()
self.reportToonHealth()
self.toonsToAttack = self.involvedToons[:]
random.shuffle(self.toonsToAttack)
self.b_setBossDamage(0)
self.battleThreeStart = globalClock.getFrameTime()
self.resetBattles()
self.waitForNextAttack(15)
self.waitForNextHelmet()
self.makeGoon(side='EmergeA')
self.makeGoon(side='EmergeB')
taskName = self.uniqueName('NextGoon')
taskMgr.remove(taskName)
taskMgr.doMethodLater(2, self.__doInitialGoons, taskName)
def __doInitialGoons(self, task):
self.makeGoon(side='EmergeA')
self.makeGoon(side='EmergeB')
self.waitForNextGoon(10)
def exitBattleThree(self):
helmetName = self.uniqueName('helmet')
taskMgr.remove(helmetName)
if self.newState != 'Victory':
self.__deleteBattleThreeObjects()
self.deleteAllTreasures()
self.stopAttacks()
self.stopGoons()
self.stopHelmets()
self.heldObject = None
return
def enterVictory(self):
self.resetBattles()
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:
toon.addResistanceMessage(self.rewardId)
toon.b_promote(self.deptIndex)
def exitVictory(self):
self.__deleteBattleThreeObjects()
def enterEpilogue(self):
DistributedBossCogAI.DistributedBossCogAI.enterEpilogue(self)
self.d_setRewardId(self.rewardId)
@magicWord(category=CATEGORY_ADMINISTRATOR)
def restartCraneRound():
"""
Restarts the crane round in the CFO.
"""
invoker = spellbook.getInvoker()
boss = None
for do in simbase.air.doId2do.values():
if isinstance(do, DistributedCashbotBossAI):
if invoker.doId in do.involvedToons:
boss = do
break
if not boss:
return "You aren't in a CFO!"
boss.exitIntroduction()
boss.b_setState('PrepareBattleThree')
boss.b_setState('BattleThree')
return 'Restarting the crane round...'
@magicWord(category=CATEGORY_ADMINISTRATOR)
def skipCFO():
"""
Skips to the final round of the CFO.
"""
invoker = spellbook.getInvoker()
boss = None
for do in simbase.air.doId2do.values():
if isinstance(do, DistributedCashbotBossAI):
if invoker.doId in do.involvedToons:
boss = do
break
if not boss:
return "You aren't in a CFO!"
if boss.state in ('PrepareBattleThree', 'BattleThree'):
return "You can't skip this round."
boss.exitIntroduction()
boss.b_setState('PrepareBattleThree')
return 'Skipping the first round...'
@magicWord(category=CATEGORY_ADMINISTRATOR)
def killCFO():
"""
Kills the CFO.
"""
invoker = spellbook.getInvoker()
boss = None
for do in simbase.air.doId2do.values():
if isinstance(do, DistributedCashbotBossAI):
if invoker.doId in do.involvedToons:
boss = do
break
if not boss:
return "You aren't in a CFO"
boss.b_setState('Victory')
return 'Killed CFO.'