from panda3d.core import * from direct.task.TaskManagerGlobal import * from direct.distributed.ClockDelta import * from direct.interval.IntervalGlobal import * import GoonGlobals from direct.task.Task import Task from toontown.toonbase import ToontownGlobals from otp.otpbase import OTPGlobals from toontown.coghq import DistributedCashbotBossObjectAI from direct.showbase import PythonUtil import DistributedGoonAI import math import random class DistributedCashbotBossGoonAI(DistributedGoonAI.DistributedGoonAI, DistributedCashbotBossObjectAI.DistributedCashbotBossObjectAI): legLength = 10 directionTable = [(0, 15), (10, 10), (-10, 10), (20, 8), (-20, 8), (40, 5), (-40, 5), (60, 4), (-60, 4), (80, 3), (-80, 3), (120, 2), (-120, 2), (180, 1)] offMask = BitMask32(0) onMask = CollisionNode.getDefaultCollideMask() def __init__(self, air, boss): DistributedGoonAI.DistributedGoonAI.__init__(self, air, 0) DistributedCashbotBossObjectAI.DistributedCashbotBossObjectAI.__init__(self, air, boss) cn = CollisionNode('tubeNode') self.tube = CollisionTube(0, 0, 0, 0, 0, 0, 2) cn.addSolid(self.tube) self.tubeNode = cn self.tubeNodePath = self.attachNewNode(self.tubeNode) self.feelers = [] cn = CollisionNode('feelerNode') self.feelerLength = self.legLength * 1.5 feelerStart = 1 for heading, weight in self.directionTable: rad = deg2Rad(heading) x = -math.sin(rad) y = math.cos(rad) seg = CollisionSegment(x * feelerStart, y * feelerStart, 0, x * self.feelerLength, y * self.feelerLength, 0) cn.addSolid(seg) self.feelers.append(seg) cn.setIntoCollideMask(self.offMask) self.feelerNodePath = self.attachNewNode(cn) self.isWalking = 0 self.cTrav = CollisionTraverser('goon') self.cQueue = CollisionHandlerQueue() self.cTrav.addCollider(self.feelerNodePath, self.cQueue) def requestBattle(self, pauseTime): avId = self.air.getAvatarIdFromSender() avatar = self.air.doId2do.get(avId) if avatar: self.boss.damageToon(avatar, self.strength) DistributedGoonAI.DistributedGoonAI.requestBattle(self, pauseTime) def sendMovie(self, type, avId = 0, pauseTime = 0): if type == GoonGlobals.GOON_MOVIE_WALK: self.demand('Walk') elif type == GoonGlobals.GOON_MOVIE_BATTLE: self.demand('Battle') elif type == GoonGlobals.GOON_MOVIE_STUNNED: self.demand('Stunned') elif type == GoonGlobals.GOON_MOVIE_RECOVERY: self.demand('Recovery') else: self.notify.warning('Ignoring movie type %s' % type) def __chooseTarget(self, extraDelay = 0): direction = self.__chooseDirection() if direction == None: self.target = None self.arrivalTime = None self.b_destroyGoon() return heading, dist = direction dist = min(dist, self.legLength) targetH = PythonUtil.reduceAngle(self.getH() + heading) origH = self.getH() h = PythonUtil.fitDestAngle2Src(origH, targetH) delta = abs(h - origH) turnTime = delta / (self.velocity * 5) walkTime = dist / self.velocity self.setH(targetH) self.target = self.boss.scene.getRelativePoint(self, Point3(0, dist, 0)) self.departureTime = globalClock.getFrameTime() self.arrivalTime = self.departureTime + turnTime + walkTime + extraDelay self.d_setTarget(self.target[0], self.target[1], h, globalClockDelta.localToNetworkTime(self.arrivalTime)) return def __chooseDirection(self): self.tubeNode.setIntoCollideMask(self.offMask) self.cTrav.traverse(self.boss.scene) self.tubeNode.setIntoCollideMask(self.onMask) entries = {} self.cQueue.sortEntries() for i in xrange(self.cQueue.getNumEntries() - 1, -1, -1): entry = self.cQueue.getEntry(i) dist = Vec3(entry.getSurfacePoint(self)).length() if dist < 1.2: dist = 0 entries[entry.getFrom()] = dist netScore = 0 scoreTable = [] for i in xrange(len(self.directionTable)): heading, weight = self.directionTable[i] seg = self.feelers[i] dist = entries.get(seg, self.feelerLength) score = dist * weight netScore += score scoreTable.append(score) if netScore == 0: self.notify.info('Could not find a path for %s' % self.doId) return None s = random.uniform(0, netScore) for i in xrange(len(self.directionTable)): s -= scoreTable[i] if s <= 0: heading, weight = self.directionTable[i] seg = self.feelers[i] dist = entries.get(seg, self.feelerLength) return (heading, dist) self.notify.warning('Fell off end of weighted table.') return (0, self.legLength) def __startWalk(self): if self.arrivalTime == None: return now = globalClock.getFrameTime() availableTime = self.arrivalTime - now if availableTime > 0: point = self.getRelativePoint(self.boss.scene, self.target) self.tube.setPointB(point) self.node().resetPrevTransform() taskMgr.doMethodLater(availableTime, self.__reachedTarget, self.uniqueName('reachedTarget')) self.isWalking = 1 else: self.__reachedTarget(None) return def __stopWalk(self, pauseTime = None): if self.isWalking: taskMgr.remove(self.uniqueName('reachedTarget')) if pauseTime == None: now = globalClock.getFrameTime() t = (now - self.departureTime) / (self.arrivalTime - self.departureTime) else: t = pauseTime / (self.arrivalTime - self.departureTime) t = min(t, 1.0) pos = self.getPos() self.setPos(pos + (self.target - pos) * t) self.tube.setPointB(0, 0, 0) self.isWalking = 0 return def __reachedTarget(self, task): self.__stopWalk() self.__chooseTarget() self.__startWalk() def __recoverWalk(self, task): self.demand('Walk') return Task.done def doFree(self, task): DistributedCashbotBossObjectAI.DistributedCashbotBossObjectAI.doFree(self, task) self.demand('Walk') return Task.done def requestStunned(self, pauseTime): avId = self.air.getAvatarIdFromSender() if avId not in self.boss.involvedToons: return if self.state == 'Stunned' or self.state == 'Grabbed': return self.__stopWalk(pauseTime) self.boss.makeTreasure(self) DistributedGoonAI.DistributedGoonAI.requestStunned(self, pauseTime) def hitBoss(self, impact): avId = self.air.getAvatarIdFromSender() self.validate(avId, impact <= 1.0, 'invalid hitBoss impact %s' % impact) if avId not in self.boss.involvedToons: return if self.state == 'Dropped' or self.state == 'Grabbed': if not self.boss.heldObject: damage = int(impact * 25 * self.scale) self.boss.recordHit(max(damage, 2)) self.b_destroyGoon() def d_setTarget(self, x, y, h, arrivalTime): self.sendUpdate('setTarget', [x, y, h, arrivalTime]) def d_destroyGoon(self): self.sendUpdate('destroyGoon') def b_destroyGoon(self): self.d_destroyGoon() self.destroyGoon() def destroyGoon(self): self.demand('Off') def enterOff(self): self.tubeNodePath.stash() self.feelerNodePath.stash() def exitOff(self): self.tubeNodePath.unstash() self.feelerNodePath.unstash() def enterGrabbed(self, avId, craneId): DistributedCashbotBossObjectAI.DistributedCashbotBossObjectAI.enterGrabbed(self, avId, craneId) taskMgr.remove(self.taskName('recovery')) taskMgr.remove(self.taskName('resumeWalk')) def enterWalk(self): self.avId = 0 self.craneId = 0 self.__chooseTarget() self.__startWalk() self.d_setObjectState('W', 0, 0) def exitWalk(self): self.__stopWalk() def enterEmergeA(self): self.avId = 0 self.craneId = 0 h = 0 dist = 15 pos = self.boss.getPos() walkTime = dist / self.velocity self.setPosHpr(pos[0], pos[1], pos[2], h, 0, 0) self.d_setPosHpr(pos[0], pos[1], pos[2], h, 0, 0) self.target = self.boss.scene.getRelativePoint(self, Point3(0, dist, 0)) self.departureTime = globalClock.getFrameTime() self.arrivalTime = self.departureTime + walkTime self.d_setTarget(self.target[0], self.target[1], h, globalClockDelta.localToNetworkTime(self.arrivalTime)) self.__startWalk() self.d_setObjectState('a', 0, 0) taskMgr.doMethodLater(walkTime, self.__recoverWalk, self.uniqueName('recoverWalk')) def exitEmergeA(self): self.__stopWalk() taskMgr.remove(self.uniqueName('recoverWalk')) def enterEmergeB(self): self.avId = 0 self.craneId = 0 h = 180 dist = 15 pos = self.boss.getPos() walkTime = dist / self.velocity self.setPosHpr(pos[0], pos[1], pos[2], h, 0, 0) self.d_setPosHpr(pos[0], pos[1], pos[2], h, 0, 0) self.target = self.boss.scene.getRelativePoint(self, Point3(0, dist, 0)) self.departureTime = globalClock.getFrameTime() self.arrivalTime = self.departureTime + walkTime self.d_setTarget(self.target[0], self.target[1], h, globalClockDelta.localToNetworkTime(self.arrivalTime)) self.__startWalk() self.d_setObjectState('b', 0, 0) taskMgr.doMethodLater(walkTime, self.__recoverWalk, self.uniqueName('recoverWalk')) def exitEmergeB(self): self.__stopWalk() taskMgr.remove(self.uniqueName('recoverWalk')) def enterBattle(self): self.d_setObjectState('B', 0, 0) def exitBattle(self): taskMgr.remove(self.taskName('resumeWalk')) def enterStunned(self): self.d_setObjectState('S', 0, 0) def exitStunned(self): taskMgr.remove(self.taskName('recovery')) def enterRecovery(self): self.d_setObjectState('R', 0, 0) taskMgr.doMethodLater(2.0, self.__recoverWalk, self.uniqueName('recoverWalk')) def exitRecovery(self): self.__stopWalk() taskMgr.remove(self.uniqueName('recoverWalk'))