from pandac.PandaModules 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 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) if __dev__: self.scene.reparentTo(self.getRender()) 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): self.__doDirectedAttack() if self.heldObject == None and not self.waitingForHelmet: self.waitForNextHelmet() return 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): return 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) pass 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) 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) if simbase.config.GetBool('cfo-staff-event', False): withStaff = False for avId in self.involvedToons: av = self.air.doId2do.get(avId) if av: if av.adminAccess > 100: withStaff = True if withStaff: participants = simbase.backups.load('cfo-staff-event', ('participants',), default={'doIds': []}) if avId not in participants['doIds']: participants['doIds'].append(toon.doId) simbase.backups.save('cfo-staff-event', ('participants',), participants) 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, 'isVP': 0, 'isCFO': 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: 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...'