class DistributedDisneyChar(DistributedAvatar, DistributedSmoothNode): notify = directNotify.newCategory('DistributedDisneyChar') def __init__(self, cr): DistributedAvatar.__init__(self, cr) DistributedSmoothNode.__init__(self, cr) self.fsm = ClassicFSM('DDisneyChar', [ State('off', self.enterOff, self.exitOff), State('walking', self.enterWalking, self.exitWalking), State('neutral', self.enterNeutral, self.exitNeutral) ], 'off', 'off') self.fsm.enterInitialState() self.neutralFSM = ClassicFSM('DDisneyChar-neutral', [ State('off', self.enterOff, self.exitOff), State('turn2target', self.enterTurn2Target, self.exitTurn2Target), State('talk2target', self.enterTalk2Target, self.exitTalk2Target) ], 'off', 'off') self.neutralFSM.enterInitialState() self.charId = 0 self.geoEyes = 0 self.avatarType = CIGlobals.CChar self.isInRange = False self.currentPointLetter = "a" self.walkIval = None self.currentChat = "" self.talkEnabled = True self.speechSound = None self.chatsSinceLastNoise = 0 self.chatsWithoutNoise = 5 self.eyes = None self.lpupil = None self.rpupil = None self.eyesOpen = None self.eyesClosed = None def setCharId(self, charId): self.charId = charId def enterOff(self): pass def exitOff(self): pass def doNeutral(self, pointLetter): self.fsm.request('neutral', [pointLetter]) def doWalking(self, pointLetter, startPointLetter, timestamp): ts = globalClockDelta.localElapsedTime(timestamp) self.fsm.request('walking', [pointLetter, startPointLetter, ts]) def enterWalking(self, pointLetter, startPointLetter, ts): if self.walkIval: self.walkIval.finish() self.walkIval = None self.nametag.clearChatText() self.loop('walk') point = WALK_POINTS[self.charId][pointLetter][0] lastPoint = WALK_POINTS[self.charId][startPointLetter][0] seq = Sequence(name=self.uniqueName('DCharWalkIval')) if self.charId == PLUTO: seq.append(ActorInterval(self, 'stand')) elif self.charId == SLEEP_DONALD: seq.append(ActorInterval(self, 'neutral2walk')) seq.append(Func(self.loop, 'walk')) ival = NPCWalkInterval(self, point, startPos=lastPoint, fluid=1) seq.append(ival) seq.append(Func(self.loop, 'neutral')) seq.start(ts) self.currentPointLetter = pointLetter self.walkIval = ival def exitWalking(self): if self.walkIval: self.walkIval.finish() self.walkIval = None def enterNeutral(self, pointLetter): point = WALK_POINTS[self.charId][pointLetter][0] self.setPos(point) if self.charId == PLUTO: seq = Sequence(ActorInterval(self, 'sit'), Func(self.loop, 'neutral')) seq.start() elif self.charId == SLEEP_DONALD: seq = Sequence(ActorInterval(self, 'walk2neutral'), Func(self.loop, 'neutral')) seq.start() else: self.loop('neutral') def talk2Toon(self, chatType, chatIndex, avId): toon = self.cr.doId2do.get(avId) if not toon: return if chatType in [SHARED_GREETINGS, SHARED_COMMENTS, SHARED_GOODBYES]: self.currentChat = CHATTER[chatType][chatIndex] elif chatType in [CHAR_GREETINGS, CHAR_COMMENTS, CHAR_GOODBYES]: self.currentChat = CHATTER[chatType][self.charId][chatIndex] if '%s' in self.currentChat: self.currentChat = self.currentChat % toon.getName() self.neutralFSM.request('turn2target', [toon]) def enterTurn2Target(self, toon): self.turnIval = NPCLookInterval(self, toon, fluid=1, name=self.uniqueName('turnIval')) if self.turnIval.distance > 30: self.loop('walk') elif self.turnIval.distance < 10.0: self.headsUp(toon) self.neutralFSM.request('talk2target') return self.turnIval.setDoneEvent(self.turnIval.getName()) self.acceptOnce(self.turnIval.getDoneEvent(), self.__handleTurningDone) self.turnIval.start() def __handleTurningDone(self): self.neutralFSM.request('talk2target') def exitTurn2Target(self): self.ignore(self.turnIval.getDoneEvent()) self.turnIval.finish() del self.turnIval def enterTalk2Target(self): self.setChat(self.currentChat) if self.getCurrentAnim() != 'neutral': if self.charId == SLEEP_DONALD: seq = Sequence(ActorInterval(self, 'walk2neutral'), Func(self.loop, 'neutral')) seq.start() else: self.loop('neutral') def exitTalk2Target(self): pass def exitNeutral(self): self.neutralFSM.request('off') self.stop() def setChat(self, chat): if self.charId == SLEEP_DONALD: chat = "." + chat DistributedAvatar.setChat(self, chat) if self.chatsSinceLastNoise >= self.chatsWithoutNoise or self.chatsSinceLastNoise == 0: base.playSfx(self.speechSound, node=self) self.chatsSinceLastNoise = 0 self.chatsWithoutNoise = random.randint(1, 5) self.chatsSinceLastNoise += 1 def loadChar(self): data = CHAR_DATA[self.charId] self.loadModel(data[0], 'modelRoot') self.loadAnims(data[1], 'modelRoot') if self.charId == SLEEP_DONALD: self.setPlayRate(0.5, 'neutral') self.setHeight(data[2]) self.setName(data[3]) self.talkEnabled = data[4] if self.talkEnabled: self.speechSound = data[5] if self.speechSound is not None: base.audio3d.attachSoundToObject(self.speechSound, self) self.setupNameTag() self.ears = [] if self.charId in [MINNIE, MICKEY]: for bundle in self.getPartBundleDict().values(): bundle = bundle['modelRoot'].getBundle() earNull = bundle.findChild('sphere3') if not earNull: earNull = bundle.findChild('*sphere3') earNull.clearNetTransforms() for bundle in self.getPartBundleDict().values(): charNodepath = bundle['modelRoot'].partBundleNP bundle = bundle['modelRoot'].getBundle() earNull = bundle.findChild('sphere3') if not earNull: earNull = bundle.findChild('*sphere3') ears = charNodepath.find('**/sphere3') if ears.isEmpty(): ears = charNodepath.find('**/*sphere3') ears.clearEffect(CharacterJointEffect.getClassType()) earRoot = charNodepath.attachNewNode('earRoot') earPitch = earRoot.attachNewNode('earPitch') earPitch.setP(40.0) ears.reparentTo(earPitch) earNull.addNetTransform(earRoot.node()) ears.clearMat() ears.node().setPreserveTransform(ModelNode.PTNone) ears.setP(-40.0) ears.flattenMedium() self.ears.append(ears) ears.setBillboardAxis() self.eyesOpen = loader.loadTexture('phase_3/maps/eyes1.jpg', 'phase_3/maps/eyes1_a.rgb') self.eyesClosed = loader.loadTexture( 'phase_3/maps/mickey_eyes_closed.jpg', 'phase_3/maps/mickey_eyes_closed_a.rgb') self.eyes = self.find('**/eyes') self.eyes.setBin('transparent', 0) self.lpupil = self.find('**/joint_pupilL') self.rpupil = self.find('**/joint_pupilR') self.drawInFront('joint_pupil?', 'eyes*', -3) elif self.charId == PLUTO: self.eyesOpen = loader.loadTexture( 'phase_6/maps/plutoEyesOpen.jpg', 'phase_6/maps/plutoEyesOpen_a.rgb') self.eyesClosed = loader.loadTexture( 'phase_6/maps/plutoEyesClosed.jpg', 'phase_6/maps/plutoEyesClosed_a.rgb') self.eyes = self.find('**/eyes') self.lpupil = self.find('**/joint_pupilL') self.rpupil = self.find('**/joint_pupilR') self.drawInFront('joint_pupil?', 'eyes*', -3) elif self.charId == DAISY: self.geoEyes = 1 self.eyeOpenList = [] self.eyeCloseList = [] self.eyeCloseList.append(self.find('**/eyesclose')) self.eyeOpenList.append(self.find('**/eyesclose')) self.eyeOpenList.append(self.find('**/eyespupil')) self.eyeOpenList.append(self.find('**/eyesopen')) for part in self.eyeOpenList: part.show() for part in self.eyeCloseList: part.hide() elif self.charId == SAILOR_DONALD: self.eyes = self.find('**/eyes') self.lpupil = self.find('**/joint_pupilL') self.rpupil = self.find('**/joint_pupilR') self.drawInFront('joint_pupil?', 'eyes*', -3) if self.lpupil is not None: self.lpupil.adjustAllPriorities(1) self.rpupil.adjustAllPriorities(1) if self.eyesOpen: self.eyesOpen.setMinfilter(Texture.FTLinear) self.eyesOpen.setMagfilter(Texture.FTLinear) if self.eyesClosed: self.eyesClosed.setMinfilter(Texture.FTLinear) self.eyesClosed.setMagfilter(Texture.FTLinear) if self.charId == MICKEY: pupilParent = self.rpupil.getParent() pupilOffsetNode = pupilParent.attachNewNode('pupilOffsetNode') pupilOffsetNode.setPos(0, 0.025, 0) self.rpupil.reparentTo(pupilOffsetNode) self.initShadow() self.shadow.setScale(0.6) self.initializeBodyCollisions(self.avatarType, self.getHeight(), 1.0) self.initializeRay(self.avatarType, 1) self.disableShadowRay() self.__blinkName = 'blink-' + data[3] def setupNameTag(self): DistributedAvatar.setupNameTag(self) self.nametag.setNametagColor( NametagGlobals.NametagColors[NametagGlobals.CCNPC]) self.nametag.setActive(0) self.nametag.updateAll() def __monitorRange(self, task): if base.localAvatar.getDistance(self) <= MAX_RANGE: if self.isInRange is False: self.sendUpdate('avatarEnter') self.isInRange = True else: if self.isInRange is True: self.sendUpdate('avatarExit') self.isInRange = False return task.cont def __blinkOpenEyes(self, task): self.openEyes() r = random.random() if r < 0.1: t = 0.2 else: t = r * 4.0 + 1.0 taskMgr.doMethodLater(t, self.__blinkCloseEyes, self.__blinkName) return task.done def __blinkCloseEyes(self, task): self.closeEyes() taskMgr.doMethodLater(0.125, self.__blinkOpenEyes, self.__blinkName) return task.done def openEyes(self): if self.geoEyes: for part in self.eyeOpenList: part.show() for part in self.eyeCloseList: part.hide() else: if self.eyes: self.eyes.setTexture(self.eyesOpen, 1) self.lpupil.show() self.rpupil.show() def closeEyes(self): if self.geoEyes: for part in self.eyeOpenList: part.hide() for part in self.eyeCloseList: part.show() else: if self.eyes: self.eyes.setTexture(self.eyesClosed, 1) self.lpupil.hide() self.rpupil.hide() def startBlink(self): if self.eyesOpen or self.geoEyes: taskMgr.remove(self.__blinkName) taskMgr.doMethodLater(random.random() * 4 + 1, self.__blinkCloseEyes, self.__blinkName) def stopBlink(self): if self.eyesOpen or self.geoEyes: taskMgr.remove(self.__blinkName) self.openEyes() def getNametagJoints(self): return [] def generate(self): DistributedAvatar.generate(self) DistributedSmoothNode.generate(self) def announceGenerate(self): DistributedAvatar.announceGenerate(self) DistributedSmoothNode.announceGenerate(self) self.loadChar() self.startBlink() base.taskMgr.add(self.__monitorRange, self.uniqueName('monitorRange')) self.sendUpdate('requestStateData') if self.charId == SAILOR_DONALD: self.disableRay() self.stashBodyCollisions() boat = self.cr.playGame.hood.loader.geom.find('**/*donalds_boat*') boat.find('**/wheel').hide() self.setPos(0, -1, 3.95) self.reparentTo(boat) self.loop('wheel') else: self.reparentTo(render) def disable(self): base.taskMgr.remove(self.uniqueName('monitorRange')) self.stopBlink() self.fsm.requestFinalState() self.fsm = None self.neutralFSM.requestFinalState() self.neutralFSM = None self.charId = None self.geoEyes = None self.avatarType = None self.isInRange = None self.currentPointLetter = None self.walkIval = None self.currentChat = None self.talkEnabled = None self.speechSound = None self.chatsSinceLastNoise = None self.eyes = None self.lpupil = None self.rpupil = None self.eyesOpen = None self.eyesClosed = None DistributedAvatar.disable(self) Avatar.disable(self) DistributedSmoothNode.disable(self)
class FactorySneakGuardSuit(Suit, FSM): notify = directNotify.newCategory('FactorySneakGuardSuit') SUIT = 'mrhollywood' VIEW_DISTANCE_TASK_NAME = 'ViewDistanceTask' MAX_VIEW_DISTANCE = 100.0 GUARD_DIED_DELAY = 6.0 MAX_HP = 200 IN_VIEW = 'somethingInSight' HEARD = 'heard' TRY_TO_CONFIRM_TIME = 5.0 def __init__(self, world, guardKey): Suit.__init__(self) FSM.__init__(self, 'FactorySneakGuardSuit') self.gameWorld = world self.guardKey = guardKey self.viewDistanceTaskName = self.VIEW_DISTANCE_TASK_NAME + '-' + str(id(self)) self.diedTaskName = 'GuardDied-' + str(id(self)) self.health = 0 self.maxHealth = self.MAX_HP self.eyeLight = None self.eyeLens = None self.eyeNode = None self.moveTrack = None return def enterGuard(self): self.loop('neutral') pos, hpr = CGG.FactoryGuardPoints[self.guardKey] self.setHpr(hpr - (180, 0, 0)) self.setPos(pos) base.taskMgr.add(self.__guard, self.taskName('guard')) def __guard(self, task): if self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode)): self.request('SeekTarget', self.IN_VIEW) return task.done return task.cont def exitGuard(self): base.taskMgr.remove(self.taskName('guard')) def enterTurnToGuardSpot(self): self.loop('walk') _, hpr = CGG.FactoryGuardPoints[self.guardKey] self.moveTrack = LerpHprInterval(self, duration=1.0, hpr=hpr, startHpr=self.getHpr()) self.moveTrack.setDoneEvent(self.uniqueName('TurnedToGuardSpot')) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['Guard']) self.moveTrack.start() def exitTurnToGuardSpot(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None return def enterSeekTarget(self, event): dialogue = random.choice(CGG.GuardDialog[event]) self.setChat(dialogue) self.loop('walk') self.moveTrack = NPCLookInterval(self, base.localAvatar) self.moveTrack.setDoneEvent(self.uniqueName('SeekLocalAvatar')) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['TryToConfirmTarget']) self.moveTrack.start() def exitSeekTarget(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None return def enterTryToConfirmTarget(self): self.loop('neutral') base.taskMgr.add(self.__tryToConfirmTarget, self.uniqueName('TryToConfirmTarget')) def __tryToConfirmTarget(self, task): if task.time >= self.TRY_TO_CONFIRM_TIME: chat = random.choice(CGG.GuardDialog['disregard']) self.setChat(chat) self.request('TurnToGuardSpot') return task.done if self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode)): chat = random.choice(CGG.GuardDialog['spot']) self.setChat(chat) return task.done return task.cont def exitTryToConfirmTarget(self): base.taskMgr.remove(self.uniqueName('TryToConfirmTarget')) def uniqueName(self, name): return self.taskName(name) def taskName(self, name): return name + '-' + str(id(self)) def setHealth(self, hp): self.health = hp def getHealth(self): return self.health def shot(self): dialogue = random.choice(CGG.GuardDialog['shot']) self.setChat(dialogue) def dead(self): self.animFSM.request('die') base.taskMgr.doMethodLater(self.GUARD_DIED_DELAY, self.__diedDone, self.diedTaskName) def __diedDone(self, task): self.gameWorld.deleteGuard(self) return task.done def generate(self): data = CIGlobals.SuitBodyData[self.SUIT] type = data[0] team = data[1] self.generateSuit(type, self.SUIT, team, self.MAX_HP, 0, False) base.taskMgr.add(self.__viewDistance, self.viewDistanceTaskName) self.setPythonTag('guard', self) self.eyeLight = Spotlight('eyes') self.eyeLens = PerspectiveLens() self.eyeLens.setMinFov(90.0 / (4.0 / 3.0)) self.eyeLight.setLens(self.eyeLens) self.eyeNode = self.headModel.attachNewNode(self.eyeLight) self.eyeNode.setZ(-5) self.eyeNode.setY(-4.5) self.request('Guard') def __viewDistance(self, task): if self.getDistance(base.localAvatar) > self.MAX_VIEW_DISTANCE: if not self.isHidden(): self.hide() elif self.isHidden(): self.show() task.delayTime = 1.0 return task.again def disable(self): base.taskMgr.remove(self.diedTaskName) base.taskMgr.remove(self.viewDistanceTaskName) if self.eyeNode: self.eyeNode.removeNode() self.eyeNode = None self.eyeLens = None self.eyeLight = None self.viewDistanceTaskName = None self.guardKey = None self.gameWorld = None Suit.disable(self) return
class FactorySneakGuardSuit(Suit, FSM): notify = directNotify.newCategory('FactorySneakGuardSuit') SUIT = 'mrhollywood' VIEW_DISTANCE_TASK_NAME = 'ViewDistanceTask' MAX_VIEW_DISTANCE = 100.0 GUARD_DIED_DELAY = 6.0 MAX_HP = 200 PROWLER_DISTANCE = 40.0 IN_VIEW = 'somethingInSight' HEARD = 'heard' TRY_TO_CONFIRM_TIME = 5.0 def __init__(self, world, guardKey): Suit.__init__(self) FSM.__init__(self, 'FactorySneakGuardSuit') self.gameWorld = world self.guardKey = guardKey self.viewDistanceTaskName = self.VIEW_DISTANCE_TASK_NAME + '-' + str( id(self)) self.diedTaskName = 'GuardDied-' + str(id(self)) self.health = 0 self.maxHealth = self.MAX_HP self.eyeLight = None self.eyeLens = None self.eyeNode = None self.moveTrack = None self.trav = None self.rayNP = None self.queue = None self.currentKey = self.guardKey self.firstPoint = CGG.GuardPointData[self.guardKey] self.walkTrack = None self.pathQueue = [] self.currentPathIndex = 0 return def enterGuard(self): self.loop('neutral') pos, hpr = CGG.FactoryGuardPoints[self.guardKey] self.setHpr(hpr - (180, 0, 0)) self.setPos(pos) base.taskMgr.add(self.__guard, self.taskName('guard')) def __checkToon(self): self.rayNP.lookAt(base.localAvatar) self.trav.traverse(render) if self.queue.getNumEntries() > 0: self.queue.sortEntries() hitObj = self.queue.getEntry(0).getIntoNodePath() print hitObj isLocalAvatar = hitObj.getParent().getPythonTag('localAvatar') if isLocalAvatar == 1: return 1 return 0 def __guard(self, task): if self.eyeNode.node().isInView(base.localAvatar.getPos( self.eyeNode)) and self.getDistance( base.localAvatar) <= self.PROWLER_DISTANCE: if self.__checkToon(): self.request('SeekTarget', self.IN_VIEW) return task.done return task.cont def exitGuard(self): base.taskMgr.remove(self.taskName('guard')) def enterTurnToGuardSpot(self): self.loop('walk') _, hpr = CGG.FactoryGuardPoints[self.guardKey] self.moveTrack = LerpHprInterval(self, duration=1.0, hpr=hpr, startHpr=self.getHpr()) self.moveTrack.setDoneEvent(self.uniqueName('TurnedToGuardSpot')) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['Guard']) self.moveTrack.start() def exitTurnToGuardSpot(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None return def enterSeekTarget(self, event): dialogue = random.choice(CGG.GuardDialog[event]) self.setChat(dialogue) self.loop('walk') self.moveTrack = NPCLookInterval(self, base.localAvatar) self.moveTrack.setDoneEvent(self.uniqueName('SeekLocalAvatar')) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['TryToConfirmTarget']) self.moveTrack.start() def exitSeekTarget(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None return def enterTryToConfirmTarget(self): self.loop('neutral') base.taskMgr.add(self.__tryToConfirmTarget, self.uniqueName('TryToConfirmTarget')) def __tryToConfirmTarget(self, task): if task.time >= self.TRY_TO_CONFIRM_TIME: chat = random.choice(CGG.GuardDialog['disregard']) self.setChat(chat) self.request('TurnToGuardSpot') return task.done if self.eyeNode.node().isInView(base.localAvatar.getPos( self.eyeNode)) and self.getDistance( base.localAvatar) <= self.PROWLER_DISTANCE: if self.__checkToon(): chat = random.choice(CGG.GuardDialog['spot']) self.setChat(chat) self.request('Pursue') return task.done return task.cont def exitTryToConfirmTarget(self): base.taskMgr.remove(self.uniqueName('TryToConfirmTarget')) def enterGoBackToGuardSpot(self): self.walkBackToGuardSpot() def walkBackToGuardSpot(self): self.currentPathIndex = 0 self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints, CGG.FactoryWayPointData, self.currentKey, self.guardKey) self.currentKey = self.guardKey self.walk(0.2) self.loop('walk') def exitGoBackToGuardSpot(self): pass def enterPursue(self): self.numTries = 0 self.maxTries = 3 self.runToClosestPoint() self.setPlayRate(1.5, 'walk') self.loop('walk') messenger.send('guardPursue') def getClosestPoint(self): closestPoint = None pointKey2range = {} for key, point in CGG.FactoryWalkPoints.items(): dummyNode = render.attachNewNode('dummyNode') dummyNode.setPos(point) pointKey2range[key] = base.localAvatar.getDistance(dummyNode) dummyNode.removeNode() ranges = [] for distance in pointKey2range.values(): ranges.append(distance) ranges.sort() for key in pointKey2range.keys(): distance = pointKey2range[key] if distance == ranges[0]: closestPoint = key break return closestPoint def runToClosestPoint(self): self.numTries += 1 closestPoint = self.getClosestPoint() self.currentPathIndex = 0 startKey = None if self.currentKey == self.guardKey and self.firstPoint in CGG.GuardPointData: startKey = CGG.GuardPointData[self.firstPoint] else: startKey = self.currentKey self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints, CGG.FactoryWayPointData, startKey, closestPoint) if self.currentKey == self.guardKey: self.pathQueue.insert(0, 1) else: self.pathQueue.insert(0, 0) self.currentKey = closestPoint self.walk(0.1) return def walk(self, speed=0.2): self.currentPathIndex += 1 if len(self.pathQueue) <= self.currentPathIndex: if self.getCurrentOrNextState() == 'Pursue': if self.getClosestPoint() != self.currentKey: if self.numTries >= self.maxTries: self.request('GoBackToGuardSpot') else: self.runToClosestPoint() else: if self.getCurrentOrNextState() == 'GoBackToGuardSpot': self.request('Guard') return print self.pathQueue[self.currentPathIndex] if self.currentPathIndex == 1 and self.pathQueue[0] == 1: startPoint = self.getPos(render) endPoint = CGG.FactoryWalkPoints[self.firstPoint] else: if self.pathQueue[0] == 0: self.pathQueue.remove(self.pathQueue[0]) key = self.pathQueue[self.currentPathIndex] endPoint = CGG.FactoryWalkPoints[key] oldKey = self.pathQueue[self.currentPathIndex - 1] startPoint = CGG.FactoryWalkPoints[oldKey] self.walkTrack = NPCWalkInterval(self, endPoint, speed, startPoint) self.walkTrack.setDoneEvent(self.uniqueName('guardWalkDone')) self.acceptOnce(self.uniqueName('guardWalkDone'), self.walk) self.walkTrack.start() def exitPursue(self): self.setPlayRate(1.0, 'walk') del self.numTries if self.walkTrack: self.ignore(self.walkTrack.getDoneEvent()) self.walkTrack.pause() self.walkTrack = None messenger.send('guardStopPursue') return def uniqueName(self, name): return self.taskName(name) def taskName(self, name): return name + '-' + str(id(self)) def setHealth(self, hp): self.health = hp def getHealth(self): return self.health def shot(self): dialogue = random.choice(CGG.GuardDialog['shot']) self.setChat(dialogue) def dead(self): self.request('Off') self.animFSM.request('die') base.taskMgr.doMethodLater(self.GUARD_DIED_DELAY, self.__diedDone, self.diedTaskName) def __diedDone(self, task): self.gameWorld.deleteGuard(self) return task.done def generate(self): data = CIGlobals.SuitBodyData[self.SUIT] type = data[0] team = data[1] self.team = team self.level = 12 self.suit = type Suit.generate(self, SuitBank.MrHollywood, 0, hideFirst=False) self.suit = type base.taskMgr.add(self.__viewDistance, self.viewDistanceTaskName) self.setPythonTag('guard', self) self.eyeLight = Spotlight('eyes') self.eyeLens = PerspectiveLens() self.eyeLens.setMinFov(90.0 / (4.0 / 3.0)) self.eyeLight.setLens(self.eyeLens) self.eyeNode = self.headModel.attachNewNode(self.eyeLight) self.eyeNode.setZ(-5) self.eyeNode.setY(-4.5) self.trav = CollisionTraverser(self.uniqueName('eyeTrav')) ray = CollisionRay(0, 0, 0, 0, 1, 0) rayNode = CollisionNode('ToonFPS.rayNode') rayNode.addSolid(ray) rayNode.setFromCollideMask(CGG.GuardBitmask | CIGlobals.WallBitmask) rayNode.setIntoCollideMask(BitMask32.allOff()) self.rayNP = base.camera.attachNewNode(rayNode) self.rayNP.setZ(3) self.queue = CollisionHandlerQueue() self.trav.addCollider(self.rayNP, self.queue) self.trav.addCollider(self.gameWorld.mg.avatarBody, self.queue) self.request('Guard') def __viewDistance(self, task): if self.getDistance(base.localAvatar) > self.MAX_VIEW_DISTANCE: if not self.isHidden(): self.hide() else: if self.isHidden(): self.show() task.delayTime = 1.0 return task.again def disable(self): self.request('Off') base.taskMgr.remove(self.taskName('guard')) base.taskMgr.remove(self.diedTaskName) base.taskMgr.remove(self.viewDistanceTaskName) self.trav = None if self.rayNP: self.rayNP.removeNode() self.rayNP = None self.queue = None self.currentPathIndex = None if self.eyeNode: self.eyeNode.removeNode() self.eyeNode = None self.eyeLens = None self.eyeLight = None self.viewDistanceTaskName = None self.guardKey = None self.gameWorld = None self.pathQueue = None if self.walkTrack: self.ignore(self.walkTrack.getDoneEvent()) self.walkTrack.finish() self.walkTrack = None Suit.disable(self) return
class FactorySneakGuardSuit(Suit, FSM): notify = directNotify.newCategory("FactorySneakGuardSuit") SUIT = "mrhollywood" VIEW_DISTANCE_TASK_NAME = "ViewDistanceTask" MAX_VIEW_DISTANCE = 100.0 GUARD_DIED_DELAY = 6.0 MAX_HP = 200 PROWLER_DISTANCE = 40.0 IN_VIEW = "somethingInSight" HEARD = "heard" TRY_TO_CONFIRM_TIME = 5.0 def __init__(self, world, guardKey): Suit.__init__(self) FSM.__init__(self, 'FactorySneakGuardSuit') self.gameWorld = world self.guardKey = guardKey self.viewDistanceTaskName = self.VIEW_DISTANCE_TASK_NAME + "-" + str( id(self)) self.diedTaskName = "GuardDied-" + str(id(self)) self.health = 0 self.maxHealth = self.MAX_HP self.eyeLight = None self.eyeLens = None self.eyeNode = None self.moveTrack = None self.trav = None self.rayNP = None self.queue = None self.currentKey = self.guardKey self.firstPoint = CGG.GuardPointData[self.guardKey] self.walkTrack = None self.pathQueue = [] self.currentPathIndex = 0 def enterGuard(self): self.loop('neutral') pos, hpr = CGG.FactoryGuardPoints[self.guardKey] self.setHpr(hpr - (180, 0, 0)) self.setPos(pos) base.taskMgr.add(self.__guard, self.taskName("guard")) def __checkToon(self): self.rayNP.lookAt(base.localAvatar) self.trav.traverse(render) if self.queue.getNumEntries() > 0: self.queue.sortEntries() hitObj = self.queue.getEntry(0).getIntoNodePath() print hitObj isLocalAvatar = hitObj.getParent().getPythonTag('localAvatar') if isLocalAvatar == 1: # Yes! We see the prowler! return 1 return 0 def __guard(self, task): # Let me check if the target is my frustrum, and if it's a close enough distance from me. if (self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode)) and self.getDistance(base.localAvatar) <= self.PROWLER_DISTANCE): # Now, let me check if the toon is standing right in front of me; not occluded. if self.__checkToon(): # Yes! We see some one! self.request('SeekTarget', self.IN_VIEW) return task.done return task.cont def exitGuard(self): base.taskMgr.remove(self.taskName("guard")) def enterTurnToGuardSpot(self): self.loop('walk') _, hpr = CGG.FactoryGuardPoints[self.guardKey] self.moveTrack = LerpHprInterval(self, duration=1.0, hpr=hpr, startHpr=self.getHpr()) self.moveTrack.setDoneEvent(self.uniqueName('TurnedToGuardSpot')) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['Guard']) self.moveTrack.start() def exitTurnToGuardSpot(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None def enterSeekTarget(self, event): dialogue = random.choice(CGG.GuardDialog[event]) self.setChat(dialogue) self.loop('walk') self.moveTrack = NPCLookInterval(self, base.localAvatar) self.moveTrack.setDoneEvent(self.uniqueName("SeekLocalAvatar")) self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['TryToConfirmTarget']) self.moveTrack.start() def exitSeekTarget(self): if self.moveTrack: self.ignore(self.moveTrack.getDoneEvent()) self.moveTrack.finish() self.moveTrack = None def enterTryToConfirmTarget(self): self.loop('neutral') base.taskMgr.add(self.__tryToConfirmTarget, self.uniqueName('TryToConfirmTarget')) def __tryToConfirmTarget(self, task): if task.time >= self.TRY_TO_CONFIRM_TIME: # Hmm, I guess it was nothing. chat = random.choice(CGG.GuardDialog['disregard']) self.setChat(chat) self.request('TurnToGuardSpot') return task.done # Let me see the target again, so I know it's actually something. if (self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode)) and self.getDistance(base.localAvatar) <= self.PROWLER_DISTANCE): # Now, let me check if the toon is standing right in front of me; not occluded. if self.__checkToon(): # There he is! chat = random.choice(CGG.GuardDialog['spot']) self.setChat(chat) self.request('Pursue') return task.done return task.cont def exitTryToConfirmTarget(self): base.taskMgr.remove(self.uniqueName('TryToConfirmTarget')) def enterGoBackToGuardSpot(self): self.walkBackToGuardSpot() def walkBackToGuardSpot(self): self.currentPathIndex = 0 self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints, CGG.FactoryWayPointData, self.currentKey, self.guardKey) self.currentKey = self.guardKey self.walk(0.2) self.loop('walk') def exitGoBackToGuardSpot(self): pass def enterPursue(self): self.numTries = 0 self.maxTries = 3 self.runToClosestPoint() self.setPlayRate(1.5, 'walk') self.loop('walk') messenger.send('guardPursue') def getClosestPoint(self): # Return the key of the closest point to the localAvatar. closestPoint = None pointKey2range = {} for key, point in CGG.FactoryWalkPoints.items(): dummyNode = render.attachNewNode('dummyNode') dummyNode.setPos(point) pointKey2range[key] = base.localAvatar.getDistance(dummyNode) dummyNode.removeNode() ranges = [] for distance in pointKey2range.values(): ranges.append(distance) ranges.sort() for key in pointKey2range.keys(): distance = pointKey2range[key] if distance == ranges[0]: closestPoint = key break return closestPoint def runToClosestPoint(self): self.numTries += 1 closestPoint = self.getClosestPoint() self.currentPathIndex = 0 startKey = None if self.currentKey == self.guardKey: startKey = CGG.GuardPointData[self.firstPoint] else: startKey = self.currentKey self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints, CGG.FactoryWayPointData, startKey, closestPoint) if self.currentKey == self.guardKey: self.pathQueue.insert(0, 1) else: self.pathQueue.insert(0, 0) self.currentKey = closestPoint self.walk(0.1) def walk(self, speed=0.2): self.currentPathIndex += 1 if len(self.pathQueue) <= self.currentPathIndex: if self.getCurrentOrNextState() == 'Pursue': if self.getClosestPoint() != self.currentKey: # Wow, the player ran off somewhere else! Go there! if self.numTries >= self.maxTries: # Dang it, give up, we can't get to them! self.request('GoBackToGuardSpot') else: self.runToClosestPoint() elif self.getCurrentOrNextState() == 'GoBackToGuardSpot': self.request('Guard') return print self.pathQueue[self.currentPathIndex] if self.currentPathIndex == 1 and self.pathQueue[0] == 1: # We need to walk from our guard point to the first waypoint in our path startPoint = self.getPos(render) endPoint = CGG.FactoryWalkPoints[self.firstPoint] else: if self.pathQueue[0] == 0: self.pathQueue.remove(self.pathQueue[0]) key = self.pathQueue[self.currentPathIndex] endPoint = CGG.FactoryWalkPoints[key] oldKey = self.pathQueue[self.currentPathIndex - 1] startPoint = CGG.FactoryWalkPoints[oldKey] self.walkTrack = NPCWalkInterval(self, endPoint, speed, startPoint) self.walkTrack.setDoneEvent(self.uniqueName('guardWalkDone')) self.acceptOnce(self.uniqueName('guardWalkDone'), self.walk) self.walkTrack.start() def exitPursue(self): self.setPlayRate(1.0, 'walk') del self.numTries if self.walkTrack: self.ignore(self.walkTrack.getDoneEvent()) self.walkTrack.pause() self.walkTrack = None messenger.send('guardStopPursue') def uniqueName(self, name): return self.taskName(name) def taskName(self, name): return name + "-" + str(id(self)) def setHealth(self, hp): self.health = hp def getHealth(self): return self.health def shot(self): dialogue = random.choice(CGG.GuardDialog['shot']) self.setChat(dialogue) def dead(self): self.request('Off') self.animFSM.request('die') base.taskMgr.doMethodLater(self.GUARD_DIED_DELAY, self.__diedDone, self.diedTaskName) def __diedDone(self, task): self.gameWorld.deleteGuard(self) return task.done def generate(self): data = CIGlobals.SuitBodyData[self.SUIT] type = data[0] team = data[1] self.generateSuit(type, self.SUIT, team, self.MAX_HP, 0, False) base.taskMgr.add(self.__viewDistance, self.viewDistanceTaskName) self.setPythonTag('guard', self) self.eyeLight = Spotlight('eyes') self.eyeLens = PerspectiveLens() self.eyeLens.setMinFov(90.0 / (4. / 3.)) self.eyeLight.setLens(self.eyeLens) self.eyeNode = self.headModel.attachNewNode(self.eyeLight) self.eyeNode.setZ(-5) self.eyeNode.setY(-4.5) self.trav = CollisionTraverser(self.uniqueName('eyeTrav')) ray = CollisionRay(0, 0, 0, 0, 1, 0) rayNode = CollisionNode('ToonFPS.rayNode') rayNode.addSolid(ray) rayNode.setFromCollideMask(CGG.GuardBitmask | CIGlobals.WallBitmask) rayNode.setIntoCollideMask(BitMask32.allOff()) self.rayNP = base.camera.attachNewNode(rayNode) self.rayNP.setZ(3) self.queue = CollisionHandlerQueue() self.trav.addCollider(self.rayNP, self.queue) self.trav.addCollider(self.gameWorld.mg.avatarBody, self.queue) self.request('Guard') def __viewDistance(self, task): # All the guards in the warehouse eat up a lot of frames. This task will # hide the guard geometry if it's too far away. if self.getDistance(base.localAvatar) > self.MAX_VIEW_DISTANCE: if not self.isHidden(): self.hide() else: if self.isHidden(): self.show() task.delayTime = 1.0 return task.again def disable(self): self.request('Off') base.taskMgr.remove(self.taskName("guard")) base.taskMgr.remove(self.diedTaskName) base.taskMgr.remove(self.viewDistanceTaskName) self.trav = None if self.rayNP: self.rayNP.removeNode() self.rayNP = None self.queue = None self.currentPathIndex = None if self.eyeNode: self.eyeNode.removeNode() self.eyeNode = None self.eyeLens = None self.eyeLight = None self.viewDistanceTaskName = None self.guardKey = None self.gameWorld = None self.pathQueue = None if self.walkTrack: self.ignore(self.walkTrack.getDoneEvent()) self.walkTrack.finish() self.walkTrack = None Suit.disable(self)