def announceGenerate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.announceGenerate(self) self._hasCleanedUp = False self.setHasRequestedDelete(False) self.b_setParent(ToontownGlobals.SPHidden) self.lockedDown = 0 self.leashMode = 0 self.leashAvId = None self.leashGoal = None self.trickLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksPerformed', self.doId) self.trickFailLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksFailed', self.doId) self.feedLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petFeedings', self.doId) self.scratchLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petScratchings', self.doId) self.traits = PetTraits.PetTraits(self.traitSeed, self.safeZone) if not hasattr(self, '_beingCreatedInDB'): for i in xrange(len(self.traitList)): value = self.traitList[i] if value == 0.0: traitName = PetTraits.getTraitNames()[i] traitValue = self.traits.getTraitValue(traitName) DistributedPetAI.notify.info( "%s: initializing new trait '%s' to %s, seed=%s" % (self.doId, traitName, traitValue, self.traitSeed)) setterName = self.getSetterName(traitName, 'b_set') self.__dict__[setterName](traitValue) self.mood = PetMood.PetMood(self) if not self.active: return self.activated = 1 self.announceZoneChange(self.zoneId, ToontownGlobals.QuietZone) self.b_setParent(ToontownGlobals.SPRender) self.setPos(randFloat(-20, 20), randFloat(-20, 20), 0) self.setH(randFloat(360)) if self.initialDNA: self.setDNA(self.initialDNA) for mood, value in self.requiredMoodComponents.items(): self.mood.setComponent(mood, value, announce=0) self.requiredMoodComponents = {} self.brain = PetBrain.PetBrain(self) self.mover = PetMoverAI(self) self.enterPetLook() self.actionFSM = PetActionFSM.PetActionFSM(self) self.teleportIn() self.handleMoodChange(distribute=0) taskMgr.doMethodLater(simbase.petMovePeriod * random.random(), self.move, self.getMoveTaskName()) self.startPosHprBroadcast() self.accept(PetObserve.getEventName(self.zoneId), self.brain.observe) self.accept(self.mood.getMoodChangeEvent(), self.handleMoodChange) self.mood.start() self.brain.start() return
def announceGenerate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.announceGenerate(self) self._hasCleanedUp = False self.setHasRequestedDelete(False) self.b_setParent(ToontownGlobals.SPHidden) self.lockedDown = 0 self.leashMode = 0 self.leashAvId = None self.leashGoal = None self.trickLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksPerformed', self.doId) self.trickFailLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksFailed', self.doId) self.feedLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petFeedings', self.doId) self.scratchLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petScratchings', self.doId) self.traits = PetTraits.PetTraits(self.traitSeed, self.safeZone) if not hasattr(self, '_beingCreatedInDB'): for i in xrange(len(self.traitList)): value = self.traitList[i] if value == 0.0: traitName = PetTraits.getTraitNames()[i] traitValue = self.traits.getTraitValue(traitName) DistributedPetAI.notify.info( "%s: initializing new trait '%s' to %s, seed=%s" % (self.doId, traitName, traitValue, self.traitSeed)) setterName = self.getSetterName(traitName, 'b_set') self.__dict__[setterName](traitValue) self.mood = PetMood.PetMood(self) if not self.active: return self.activated = 1 self.announceZoneChange(self.zoneId, ToontownGlobals.QuietZone) self.b_setParent(ToontownGlobals.SPRender) self.setPos(randFloat(-20, 20), randFloat(-20, 20), 0) self.setH(randFloat(360)) if self.initialDNA: self.setDNA(self.initialDNA) for mood, value in self.requiredMoodComponents.items(): self.mood.setComponent(mood, value, announce=0) self.requiredMoodComponents = {} self.brain = PetBrain.PetBrain(self) self.mover = PetMoverAI(self) self.enterPetLook() self.actionFSM = PetActionFSM.PetActionFSM(self) self.teleportIn() self.handleMoodChange(distribute=0) taskMgr.doMethodLater( simbase.petMovePeriod * random.random(), self.move, self.getMoveTaskName()) self.startPosHprBroadcast() self.accept(PetObserve.getEventName(self.zoneId), self.brain.observe) self.accept(self.mood.getMoodChangeEvent(), self.handleMoodChange) self.mood.start() self.brain.start()
class DistributedPetAI(DistributedSmoothNodeAI.DistributedSmoothNodeAI, PetLookerAI.PetLookerAI, PetBase.PetBase): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPetAI") movieTimeSwitch = { PetConstants.PET_MOVIE_FEED: PetConstants.FEED_TIME, PetConstants.PET_MOVIE_SCRATCH: PetConstants.SCRATCH_TIME, PetConstants.PET_MOVIE_CALL: PetConstants.CALL_TIME, } movieDistSwitch = { PetConstants.PET_MOVIE_FEED: PetConstants.FEED_DIST.get, PetConstants.PET_MOVIE_SCRATCH: PetConstants.SCRATCH_DIST.get, } def __init__(self, air, dna=None): DistributedSmoothNodeAI.DistributedSmoothNodeAI.__init__(self, air) PetLookerAI.PetLookerAI.__init__(self) self.ownerId = 0 self.petName = "unnamed" self.traitSeed = 0 self.safeZone = ToontownGlobals.ToontownCentral self.initialDNA = dna self.active = 1 self.activated = 0 self._outOfBounds = False self.traitList = [0] * PetTraits.PetTraits.NumTraits self.head = -1 self.ears = -1 self.nose = -1 self.tail = -1 self.bodyTexture = 0 self.color = 0 self.colorScale = 0 self.eyeColor = 0 self.gender = 0 self.movieMode = None self.lockMoverEnabled = 0 self.trickAptitudes = [] self.inEstate = 0 self.estateOwnerId = None self.estateZones = [] self.lastSeenTimestamp = self.getCurEpochTimestamp() self.requiredMoodComponents = {} self.__funcsToDelete = [] self.__generateDistTraitFuncs() self.__generateDistMoodFuncs() self.busy = 0 self.gaitFSM = ClassicFSM.ClassicFSM( "petGaitFSM", [ State.State("off", self.gaitEnterOff, self.gaitExitOff), State.State("neutral", self.gaitEnterNeutral, self.gaitExitNeutral), State.State("happy", self.gaitEnterHappy, self.gaitExitHappy), State.State("sad", self.gaitEnterSad, self.gaitExitSad), ], "off", "off", ) self.gaitFSM.enterInitialState() self.unstickFSM = ClassicFSM.ClassicFSM( "unstickFSM", [ State.State("off", self.unstickEnterOff, self.unstickExitOff), State.State("on", self.unstickEnterOn, self.unstickExitOn), ], "off", "off", ) self.unstickFSM.enterInitialState() return def setInactive(self): self.active = 0 def _initDBVals(self, ownerId, name=None, traitSeed=0, dna=None, safeZone=ToontownGlobals.ToontownCentral): self.b_setOwnerId(ownerId) if name is None: name = "pet%s" % self.doId self.b_setPetName(name) self.b_setTraitSeed(traitSeed) self.b_setSafeZone(safeZone) traits = PetTraits.PetTraits(traitSeed, safeZone) for traitName in PetTraits.getTraitNames(): setter = self.getSetterName(traitName, "b_set") self.__dict__[setter](traits.getTraitValue(traitName)) self.traits = traits for component in PetMood.PetMood.Components: setterName = self.getSetterName(component, "b_set") self.__dict__[setterName](0.0) if not dna: dna = PetDNA.getRandomPetDNA() self.setDNA(dna) self.b_setLastSeenTimestamp(self.getCurEpochTimestamp()) for component in PetMood.PetMood.Components: self.setMoodComponent(component, 0.0) self.b_setTrickAptitudes([]) return def setDNA(self, dna): head, ears, nose, tail, body, color, colorScale, eyes, gender = dna self.b_setHead(head) self.b_setEars(ears) self.b_setNose(nose) self.b_setTail(tail) self.b_setBodyTexture(body) self.b_setColor(color) self.b_setColorScale(colorScale) self.b_setEyeColor(eyes) self.b_setGender(gender) def handleZoneChange(self, newZoneId, oldZoneId): DistributedSmoothNodeAI.DistributedSmoothNodeAI.handleZoneChange(self, newZoneId, oldZoneId) self.ignore(PetObserve.getEventName(oldZoneId)) self.accept(PetObserve.getEventName(newZoneId), self.brain.observe) def handleLogicalZoneChange(self, newZoneId, oldZoneId): DistributedSmoothNodeAI.DistributedSmoothNodeAI.handleLogicalZoneChange(self, newZoneId, oldZoneId) self.announceZoneChange(newZoneId, oldZoneId) def announceZoneChange(self, newZoneId, oldZoneId): DistributedPetAI.notify.debug("%s.announceZoneChange: %s->%s" % (self.doId, oldZoneId, newZoneId)) broadcastZones = list2dict([newZoneId, oldZoneId]) self.estateOwnerId = simbase.air.estateManager.getOwnerFromZone(newZoneId) if self.estateOwnerId: self.inEstate = 1 self.estateZones = simbase.air.estateManager.getEstateZones(self.estateOwnerId) else: self.inEstate = 0 self.estateZones = [] PetObserve.send( broadcastZones.keys(), PetObserve.PetActionObserve(PetObserve.Actions.CHANGE_ZONE, self.doId, (oldZoneId, newZoneId)), ) def getOwnerId(self): return self.ownerId def b_setOwnerId(self, ownerId): self.d_setOwnerId(ownerId) self.setOwnerId(ownerId) def d_setOwnerId(self, ownerId): self.sendUpdate("setOwnerId", [ownerId]) def setOwnerId(self, ownerId): self.ownerId = ownerId def getPetName(self): return self.petName def b_setPetName(self, petName): self.d_setPetName(petName) self.setPetName(petName) def d_setPetName(self, petName): self.sendUpdate("setPetName", [petName]) def setPetName(self, petName): self.petName = petName DistributedSmoothNodeAI.DistributedSmoothNodeAI.setName(self, self.petName) def getTraitSeed(self): return self.traitSeed def b_setTraitSeed(self, traitSeed): self.d_setTraitSeed(traitSeed) self.setTraitSeed(traitSeed) def d_setTraitSeed(self, traitSeed): self.sendUpdate("setTraitSeed", [traitSeed]) def setTraitSeed(self, traitSeed): self.traitSeed = traitSeed def getSafeZone(self): return self.safeZone def b_setSafeZone(self, safeZone): self.d_setSafeZone(safeZone) self.setSafeZone(safeZone) def d_setSafeZone(self, safeZone): self.sendUpdate("setSafeZone", [safeZone]) def setSafeZone(self, safeZone): self.safeZone = safeZone def getPetName(self): return self.petName def b_setPetName(self, petName): self.d_setPetName(petName) self.setPetName(petName) def d_setPetName(self, petName): self.sendUpdate("setPetName", [petName]) def setPetName(self, petName): self.petName = petName DistributedSmoothNodeAI.DistributedSmoothNodeAI.setName(self, self.petName) def setTraits(self, traitList): self.traitList = traitList def __generateDistTraitFuncs(self): for i in xrange(PetTraits.PetTraits.NumTraits): traitName = PetTraits.getTraitNames()[i] getterName = self.getSetterName(traitName, "get") b_setterName = self.getSetterName(traitName, "b_set") d_setterName = self.getSetterName(traitName, "d_set") setterName = self.getSetterName(traitName) def traitGetter(i=i): return self.traitList[i] def b_traitSetter(value, setterName=setterName, d_setterName=d_setterName): self.__dict__[d_setterName](value) self.__dict__[setterName](value) def d_traitSetter(value, setterName=setterName): self.sendUpdate(setterName, [value]) def traitSetter(value, i=i): self.traitList[i] = value self.__dict__[getterName] = traitGetter self.__dict__[b_setterName] = b_traitSetter self.__dict__[d_setterName] = d_traitSetter self.__dict__[setterName] = traitSetter self.__funcsToDelete.append(getterName) self.__funcsToDelete.append(b_setterName) self.__funcsToDelete.append(d_setterName) self.__funcsToDelete.append(setterName) def getHead(self): return self.head def b_setHead(self, head): self.d_setHead(head) self.setHead(head) def d_setHead(self, head): self.sendUpdate("setHead", [head]) def setHead(self, head): self.head = head def getEars(self): return self.ears def b_setEars(self, ears): self.d_setEars(ears) self.setEars(ears) def d_setEars(self, ears): self.sendUpdate("setEars", [ears]) def setEars(self, ears): self.ears = ears def getNose(self): return self.nose def b_setNose(self, nose): self.d_setNose(nose) self.setNose(nose) def d_setNose(self, nose): self.sendUpdate("setNose", [nose]) def setNose(self, nose): self.nose = nose def getTail(self): return self.tail def b_setTail(self, tail): self.d_setTail(tail) self.setTail(tail) def d_setTail(self, tail): self.sendUpdate("setTail", [tail]) def setTail(self, tail): self.tail = tail def getBodyTexture(self): return self.bodyTexture def b_setBodyTexture(self, bodyTexture): self.d_setBodyTexture(bodyTexture) self.setBodyTexture(bodyTexture) def d_setBodyTexture(self, bodyTexture): self.sendUpdate("setBodyTexture", [bodyTexture]) def setBodyTexture(self, bodyTexture): self.bodyTexture = bodyTexture def getColor(self): return self.color def b_setColor(self, color): self.d_setColor(color) self.setColor(color) def d_setColor(self, color): self.sendUpdate("setColor", [color]) def setColor(self, color): self.color = color def getColorScale(self): return self.colorScale def b_setColorScale(self, colorScale): self.d_setColorScale(colorScale) self.setColorScale(colorScale) def d_setColorScale(self, colorScale): self.sendUpdate("setColorScale", [colorScale]) def setColorScale(self, colorScale): self.colorScale = colorScale def getEyeColor(self): return self.eyeColor def b_setEyeColor(self, eyeColor): self.d_setEyeColor(eyeColor) self.setEyeColor(eyeColor) def d_setEyeColor(self, eyeColor): self.sendUpdate("setEyeColor", [eyeColor]) def setEyeColor(self, eyeColor): self.eyeColor = eyeColor def getGender(self): return self.gender def b_setGender(self, gender): self.d_setGender(gender) self.setGender(gender) def d_setGender(self, gender): self.sendUpdate("setGender", [gender]) def setGender(self, gender): self.gender = gender def teleportIn(self, timestamp=None): self.notify.debug("DPAI: teleportIn") timestamp = ClockDelta.globalClockDelta.getRealNetworkTime() self.notify.debug("DPAI: sending update @ ts = %s" % timestamp) self.sendUpdate("teleportIn", [timestamp]) return None def teleportOut(self, timestamp=None): self.notify.debug("DPAI: teleportOut") timestamp = ClockDelta.globalClockDelta.getRealNetworkTime() self.notify.debug("DPAI: sending update @ ts = %s" % timestamp) self.sendUpdate("teleportOut", [timestamp]) return None def getLastSeenTimestamp(self): return self.lastSeenTimestamp def b_setLastSeenTimestamp(self, timestamp): self.d_setLastSeenTimestamp(timestamp) self.setLastSeenTimestamp(timestamp) def d_setLastSeenTimestamp(self, timestamp): self.sendUpdate("setLastSeenTimestamp", [timestamp]) def setLastSeenTimestamp(self, timestamp): self.lastSeenTimestamp = timestamp def getCurEpochTimestamp(self): return int(time.time()) def getTimeSinceLastSeen(self): t = time.time() - self.lastSeenTimestamp return max(0.0, t) def __handleMoodSet(self, component, value): if self.isGenerated(): self.mood.setComponent(component, value) else: self.requiredMoodComponents[component] = value def __handleMoodGet(self, component): if self.isGenerated(): return self.mood.getComponent(component) else: return 0.0 def __generateDistMoodFuncs(self): for compName in PetMood.PetMood.Components: getterName = self.getSetterName(compName, "get") setterName = self.getSetterName(compName) def moodGetter(compName=compName): return self.__handleMoodGet(compName) def b_moodSetter(value, setterName=setterName): self.__dict__[setterName](value) def d_moodSetter(value, setterName=setterName): self.sendUpdate(setterName, [value]) def moodSetter(value, compName=compName): self.__handleMoodSet(compName, value) self.__dict__[getterName] = moodGetter self.__dict__["b_%s" % setterName] = b_moodSetter self.__dict__["d_%s" % setterName] = d_moodSetter self.__dict__[setterName] = moodSetter self.__funcsToDelete.append(getterName) self.__funcsToDelete.append("b_%s" % setterName) self.__funcsToDelete.append("d_%s" % setterName) self.__funcsToDelete.append(setterName) def getTrickAptitudes(self): return self.trickAptitudes def b_setTrickAptitudes(self, aptitudes): self.setTrickAptitudes(aptitudes, local=1) self.d_setTrickAptitudes(aptitudes) def d_setTrickAptitudes(self, aptitudes): while len(aptitudes) < len(PetTricks.Tricks) - 1: aptitudes.append(0.0) self.sendUpdate("setTrickAptitudes", [aptitudes]) def setTrickAptitudes(self, aptitudes, local=0): if not local: DistributedPetAI.notify.debug("setTrickAptitudes: %s" % aptitudes) while len(self.trickAptitudes) < len(PetTricks.Tricks) - 1: self.trickAptitudes.append(0.0) self.trickAptitudes = aptitudes def getTrickAptitude(self, trickId): if trickId > len(self.trickAptitudes) - 1: return 0.0 return self.trickAptitudes[trickId] def setTrickAptitude(self, trickId, aptitude, send=1): aptitude = clampScalar(aptitude, 0.0, 1.0) aptitudes = self.trickAptitudes while len(aptitudes) - 1 < trickId: aptitudes.append(0.0) if aptitudes[trickId] != aptitude: aptitudes[trickId] = aptitude if send: self.b_setTrickAptitudes(aptitudes) else: self.setTrickAptitudes(aptitudes, local=1) def announceGenerate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.announceGenerate(self) self._hasCleanedUp = False self.setHasRequestedDelete(False) self.b_setParent(ToontownGlobals.SPHidden) self.lockedDown = 0 self.leashMode = 0 self.leashAvId = None self.leashGoal = None self.trickLogger = ServerEventBuffer.ServerEventMultiAccumulator(self.air, "petTricksPerformed", self.doId) self.trickFailLogger = ServerEventBuffer.ServerEventMultiAccumulator(self.air, "petTricksFailed", self.doId) self.feedLogger = ServerEventBuffer.ServerEventAccumulator(self.air, "petFeedings", self.doId) self.scratchLogger = ServerEventBuffer.ServerEventAccumulator(self.air, "petScratchings", self.doId) self.traits = PetTraits.PetTraits(self.traitSeed, self.safeZone) if not hasattr(self, "_beingCreatedInDB"): for i in xrange(len(self.traitList)): value = self.traitList[i] if value == 0.0: traitName = PetTraits.getTraitNames()[i] traitValue = self.traits.getTraitValue(traitName) DistributedPetAI.notify.info( "%s: initializing new trait '%s' to %s, seed=%s" % (self.doId, traitName, traitValue, self.traitSeed) ) setterName = self.getSetterName(traitName, "b_set") self.__dict__[setterName](traitValue) self.mood = PetMood.PetMood(self) if not self.active: return self.activated = 1 self.announceZoneChange(self.zoneId, ToontownGlobals.QuietZone) self.b_setParent(ToontownGlobals.SPRender) self.setPos(randFloat(-20, 20), randFloat(-20, 20), 0) self.setH(randFloat(360)) if self.initialDNA: self.setDNA(self.initialDNA) for mood, value in self.requiredMoodComponents.items(): self.mood.setComponent(mood, value, announce=0) self.requiredMoodComponents = {} self.brain = PetBrain.PetBrain(self) self.mover = PetMoverAI(self) self.enterPetLook() self.actionFSM = PetActionFSM.PetActionFSM(self) self.teleportIn() self.handleMoodChange(distribute=0) taskMgr.doMethodLater(simbase.petMovePeriod * random.random(), self.move, self.getMoveTaskName()) self.startPosHprBroadcast() self.accept(PetObserve.getEventName(self.zoneId), self.brain.observe) self.accept(self.mood.getMoodChangeEvent(), self.handleMoodChange) self.mood.start() self.brain.start() return def _isPet(self): return 1 def setHasRequestedDelete(self, flag): self._requestedDeleteFlag = flag def hasRequestedDelete(self): return self._requestedDeleteFlag def requestDelete(self, task=None): DistributedPetAI.notify.info("PetAI.requestDelete: %s, owner=%s" % (self.doId, self.ownerId)) if self.hasRequestedDelete(): DistributedPetAI.notify.info( "PetAI.requestDelete: %s, owner=%s returning immediately" % (self.doId, self.ownerId) ) return self.setHasRequestedDelete(True) self.b_setLastSeenTimestamp(self.getCurEpochTimestamp()) DistributedSmoothNodeAI.DistributedSmoothNodeAI.requestDelete(self) def _doDeleteCleanup(self): self.trickLogger.destroy() self.trickFailLogger.destroy() self.feedLogger.destroy() self.scratchLogger.destroy() del self.trickLogger del self.trickFailLogger del self.feedLogger del self.scratchLogger taskMgr.remove(self.uniqueName("clearMovie")) taskMgr.remove(self.uniqueName("PetMovieWait")) taskMgr.remove(self.uniqueName("PetMovieClear")) taskMgr.remove(self.uniqueName("PetMovieComplete")) taskMgr.remove(self.getLockMoveTaskName()) taskMgr.remove(self.getMoveTaskName()) if hasattr(self, "zoneId"): self.announceZoneChange(ToontownGlobals.QuietZone, self.zoneId) else: myDoId = "No doId" myTaskName = "No task name" myStackTrace = StackTrace().trace myOldStackTrace = "No Trace" if hasattr(self, "doId"): myDoId = self.doId if task: myTaskName = task.name if hasattr(self, "destroyDoStackTrace"): myOldStackTrace = self.destroyDoStackTrace.trace simbase.air.writeServerEvent("Pet RequestDelete duplicate", myDoId, "from task %s" % myTaskName) simbase.air.writeServerEvent("Pet RequestDelete duplicate StackTrace", myDoId, "%s" % myStackTrace) simbase.air.writeServerEvent("Pet RequestDelete duplicate OldStackTrace", myDoId, "%s" % myOldStackTrace) DistributedPetAI.notify.warning("double requestDelete from task %s" % myTaskName) self.setParent(ToontownGlobals.SPHidden) if hasattr(self, "activated"): if self.activated: self.activated = 0 self.brain.destroy() del self.brain self.actionFSM.destroy() del self.actionFSM self.exitPetLook() self.mover.destroy() del self.mover self.stopPosHprBroadcast() if hasattr(self, "mood"): self.mood.destroy() del self.mood if hasattr(self, "traits"): del self.traits try: for funcName in self.__funcsToDelete: del self.__dict__[funcName] except: pass if hasattr(self, "gaitFSM"): if self.gaitFSM: self.gaitFSM.requestFinalState() del self.gaitFSM if hasattr(self, "unstickFSM"): if self.unstickFSM: self.unstickFSM.requestFinalState() del self.unstickFSM PetLookerAI.PetLookerAI.destroy(self) self.ignoreAll() self._hasCleanedUp = True def delete(self): DistributedPetAI.notify.info("PetAI.delete: %s, owner=%s" % (self.doId, self.ownerId)) if not self._hasCleanedUp: self._doDeleteCleanup() self.setHasRequestedDelete(False) DistributedSmoothNodeAI.DistributedSmoothNodeAI.delete(self) def patchDelete(self): for funcName in self.__funcsToDelete: del self.__dict__[funcName] del self.gaitFSM del self.unstickFSM PetLookerAI.PetLookerAI.destroy(self) self.doNotDeallocateChannel = True self.zoneId = None DistributedSmoothNodeAI.DistributedSmoothNodeAI.delete(self) self.ignoreAll() return def getMoveTaskName(self): return "petMove-%s" % self.doId def getLockMoveTaskName(self): return "petLockMove-%s" % self.doId def move(self, task=None): if self.isEmpty(): self.air.writeServerEvent("Late Pet Move Call", self.doId, " ") taskMgr.remove(task.name) return Task.done numNearby = len(self.brain.nearbyAvs) - 1 minNearby = 5 if numNearby > minNearby: delay = 0.08 * (numNearby - minNearby) self.setPosHprBroadcastPeriod(PetConstants.PosBroadcastPeriod + lerp(delay * 0.75, delay, random.random())) maxDist = 1000 if abs(self.getX()) > maxDist or abs(self.getY()) > maxDist: DistributedPetAI.notify.warning("deleting pet %s before he wanders off too far" % self.doId) self._outOfBounds = True self.stopPosHprBroadcast() self.requestDelete() return Task.done taskMgr.doMethodLater(simbase.petMovePeriod, self.move, self.getMoveTaskName()) return Task.done def startPosHprBroadcast(self): if self._outOfBounds: return DistributedSmoothNodeAI.DistributedSmoothNodeAI.startPosHprBroadcast( self, period=simbase.petPosBroadcastPeriod, type=DistributedSmoothNodeBase.DistributedSmoothNodeBase.BroadcastTypes.XYH, ) def setMoodComponent(self, component, value): setter = self.getSetterName(component, "b_set") self.__dict__[setter](value) def addToMood(self, component, delta): value = self.mood.getComponent(component) value += delta self.setMoodComponent(component, clampScalar(value, 0.0, 1.0)) def lerpMood(self, component, factor): curVal = self.mood.getComponent(component) if factor < 0: self.setMoodComponent(component, lerp(curVal, 0.0, -factor)) else: self.setMoodComponent(component, lerp(curVal, 1.0, factor)) def addToMoods(self, mood2delta): for mood, delta in mood2delta.items(): self.addToMood(mood, delta) def lerpMoods(self, mood2factor): for mood, factor in mood2factor.items(): self.lerpMood(mood, factor) def handleMoodChange(self, components=[], distribute=1): if len(components) == 0: components = PetMood.PetMood.Components if distribute: if len(components) == len(PetMood.PetMood.Components): values = [] for comp in PetMood.PetMood.Components: values.append(self.mood.getComponent(comp)) self.sendUpdate("setMood", values) else: for comp in components: setter = self.getSetterName(comp, "d_set") self.__dict__[setter](self.mood.getComponent(comp)) if self.isExcited(): self.gaitFSM.request("happy") elif self.isSad(): self.gaitFSM.request("sad") else: self.gaitFSM.request("neutral") def isContented(self): return self.mood.getDominantMood() in PetMood.PetMood.ContentedMoods def call(self, avatar): self.brain.observe(PetObserve.PetPhraseObserve(PetObserve.Phrases.COME, avatar.doId)) self.__petMovieStart(avatar.doId) def feed(self, avatar): if avatar.takeMoney(PetConstants.FEED_AMOUNT): self.startLockPetMove(avatar.doId) self.brain.observe(PetObserve.PetActionObserve(PetObserve.Actions.FEED, avatar.doId)) self.feedLogger.addEvent() def scratch(self, avatar): self.startLockPetMove(avatar.doId) self.brain.observe(PetObserve.PetActionObserve(PetObserve.Actions.SCRATCH, avatar.doId)) self.scratchLogger.addEvent() def lockPet(self): DistributedPetAI.notify.debug("%s: lockPet" % self.doId) if not self.lockedDown: self.mover.lock() self.stopPosHprBroadcast() self.lockedDown += 1 def isLockedDown(self): return self.lockedDown != 0 def unlockPet(self): DistributedPetAI.notify.debug("%s: unlockPet" % self.doId) if self.lockedDown <= 0: DistributedPetAI.notify.warning("%s: unlockPet called on unlocked pet" % self.doId) else: self.lockedDown -= 1 if not self.lockedDown and not self.isDeleted(): self.startPosHprBroadcast() def handleStay(self, avatar): self.brain.observe(PetObserve.PetPhraseObserve(PetObserve.Phrases.STAY, avatar.doId)) def handleShoo(self, avatar): self.brain.observe(PetObserve.PetPhraseObserve(PetObserve.Phrases.GO_AWAY, avatar.doId)) def gaitEnterOff(self): pass def gaitExitOff(self): pass def gaitEnterNeutral(self): self.mover.setFwdSpeed(PetConstants.FwdSpeed) self.mover.setRotSpeed(PetConstants.RotSpeed) def gaitExitNeutral(self): pass def gaitEnterHappy(self): self.mover.setFwdSpeed(PetConstants.HappyFwdSpeed) self.mover.setRotSpeed(PetConstants.HappyRotSpeed) def gaitExitHappy(self): pass def gaitEnterSad(self): self.mover.setFwdSpeed(PetConstants.SadFwdSpeed) self.mover.setRotSpeed(PetConstants.SadRotSpeed) def gaitExitSad(self): pass def unstickEnterOff(self): pass def unstickExitOff(self): pass def unstickEnterOn(self): self._collisionTimestamps = [] def unstickExitOn(self): pass def ownerIsOnline(self): return self.ownerId in simbase.air.doId2do def ownerIsInSameZone(self): if not self.ownerIsOnline(): return 0 return self.zoneId == simbase.air.doId2do[self.ownerId].zoneId def _getOwnerDict(self): if self.owner is not None: if self.ownerIsInSameZone(): return {self.ownerId: self.owner} return {} def _getFullNearbyToonDict(self): toons = self.air.getObjectsOfClassInZone(self.air.districtId, self.zoneId, DistributedToonAI.DistributedToonAI) return toons def _getNearbyToonDict(self): toons = self._getFullNearbyToonDict() if self.ownerId in toons: del toons[self.ownerId] return toons def _getNearbyPetDict(self): pets = self.air.getObjectsOfClassInZone(self.air.districtId, self.zoneId, DistributedPetAI) if self.doId in pets: del pets[self.doId] return pets def _getNearbyAvatarDict(self): avs = self._getFullNearbyToonDict() avs.update(self._getNearbyPetDict()) return avs def _getOwner(self): return self.air.doId2do.get(self.ownerId) def _getNearbyToon(self): nearbyToonDict = self._getFullNearbyToonDict() if not len(nearbyToonDict): return None return nearbyToonDict[random.choice(nearbyToonDict.keys())] def _getNearbyToonNonOwner(self): nearbyToonDict = self._getNearbyToonDict() if not len(nearbyToonDict): return None return nearbyToonDict[random.choice(nearbyToonDict.keys())] def _getNearbyPet(self): nearbyPetDict = self._getNearbyPetDict() if not len(nearbyPetDict): return None return nearbyPetDict[random.choice(nearbyPetDict.keys())] def _getNearbyAvatar(self): nearbyAvDict = self._getNearbyAvatarDict() if not len(nearbyAvDict): return None return nearbyAvDict[random.choice(nearbyAvDict.keys())] def isBusy(self): return self.busy > 0 def freeAvatar(self, avId): self.sendUpdateToAvatarId(avId, "freeAvatar", []) def avatarInteract(self, avId): av = self.air.doId2do.get(avId) if av is None: self.notify.warning("Avatar: %s not found" % avId) return 0 if self.isBusy(): self.notify.debug("freeing avatar!") self.freeAvatar(avId) return 0 self.busy = avId self.notify.debug("sending update") self.sendUpdateToAvatarId(avId, "avatarInteract", [avId]) self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId]) return 1 def rejectAvatar(self, avId): self.notify.error("rejectAvatar: should not be called by a pet!") def d_setMovie(self, avId, flag): self.sendUpdate("setMovie", [flag, avId, ClockDelta.globalClockDelta.getRealNetworkTime()]) def sendClearMovie(self, task=None): if self.air != None: self.ignore(self.air.getAvatarExitEvent(self.busy)) taskMgr.remove(self.uniqueName("clearMovie")) self.busy = 0 self.d_setMovie(0, PetConstants.PET_MOVIE_CLEAR) return Task.done def __handleUnexpectedExit(self, avId): self.notify.warning("avatar:" + str(avId) + " has exited unexpectedly") self.notify.warning("not busy with avId: %s, busy: %s " % (avId, self.busy)) taskMgr.remove(self.uniqueName("clearMovie")) self.sendClearMovie() def handleAvPetInteraction(self, mode, avId): if mode not in (PetConstants.PET_MOVIE_SCRATCH, PetConstants.PET_MOVIE_FEED, PetConstants.PET_MOVIE_CALL): self.air.writeServerEvent("suspicious", avId, "DistributedPetAI: unknown mode: %s" % mode) return if self.avatarInteract(avId): self.notify.debug("handleAvPetInteraction() avatarInteract calling callback") self.movieMode = mode callback = { PetConstants.PET_MOVIE_SCRATCH: self.scratch, PetConstants.PET_MOVIE_FEED: self.feed, PetConstants.PET_MOVIE_CALL: self.call, }.get(mode) callback(self.air.doId2do.get(avId)) else: self.notify.debug("handleAvPetInteraction() avatarInteract was busy or unhappy") def __petMovieStart(self, avId): self.d_setMovie(avId, self.movieMode) time = self.movieTimeSwitch.get(self.movieMode) taskMgr.doMethodLater(time, self.__petMovieComplete, self.uniqueName("PetMovieComplete")) def __petMovieComplete(self, task=None): self.disableLockMover() self.unlockPet() self.sendClearMovie() self.movieMode = None return Task.done def startLockPetMove(self, avId): self.enableLockMover() dist_Callable = self.movieDistSwitch.get(self.movieMode) dist = dist_Callable(self.air.doId2do.get(avId).getStyle().getLegSize()) self.distList = [0, 0, 0] self.mover.walkToAvatar(self.air.doId2do[avId], callback=lambda: self.endLockPetMove(avId)) self.__lockPetMoveTask(avId) def getAverageDist(self): sum = 0 for i in self.distList: sum += i return sum / 3.0 def __lockPetMoveTask(self, avId): return Task.done def endLockPetMove(self, avId): del self.distList taskMgr.remove(self.getLockMoveTaskName()) self.lockPet() self.__petMovieStart(avId) def enableLockMover(self): if not hasattr(self, "brain"): return if self.lockMoverEnabled == 0: self.brain._startMovie() self.lockMoverEnabled += 1 def isLockMoverEnabled(self): return self.lockMoverEnabled > 0 def disableLockMover(self): if not hasattr(self, "brain"): return if self.lockMoverEnabled > 0: self.lockMoverEnabled -= 1 if self.lockMoverEnabled == 0: self.brain._endMovie() def _willDoTrick(self, trickId): if self.isContented(): minApt = PetTricks.MinActualTrickAptitude maxApt = PetTricks.MaxActualTrickAptitude else: minApt = PetTricks.NonHappyMinActualTrickAptitude maxApt = PetTricks.NonHappyMaxActualTrickAptitude randVal = random.random() cutoff = lerp(minApt, maxApt, self.getTrickAptitude(trickId)) if self.mood.isComponentActive("fatigue"): cutoff *= 0.5 cutoff *= PetTricks.TrickAccuracies[trickId] DistributedPetAI.notify.info("_willDoTrick: %s / %s" % (randVal, cutoff)) # .debug return randVal < cutoff def _handleDidTrick(self, trickId): DistributedPetAI.notify.debug("_handleDidTrick: %s" % trickId) if trickId == PetTricks.Tricks.BALK: return aptitude = self.getTrickAptitude(trickId) self.setTrickAptitude(trickId, aptitude + PetTricks.AptitudeIncrementDidTrick) self.addToMood("fatigue", lerp(PetTricks.MaxTrickFatigue, PetTricks.MinTrickFatigue, aptitude)) self.trickLogger.addEvent(trickId) def _handleGotPositiveTrickFeedback(self, trickId, magnitude): if trickId == PetTricks.Tricks.BALK: return self.setTrickAptitude( trickId, self.getTrickAptitude(trickId) + PetTricks.MaxAptitudeIncrementGotPraise * magnitude ) def toggleLeash(self, avId): if self.leashMode: self.leashMode = 0 self.leashAvId = None response = "leash OFF" else: self.leashMode = 1 self.leashAvId = avId response = "leash ON" return response
class DistributedPetAI(DistributedSmoothNodeAI.DistributedSmoothNodeAI, PetLookerAI.PetLookerAI, PetBase.PetBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPetAI') movieTimeSwitch = { PetConstants.PET_MOVIE_FEED: PetConstants.FEED_TIME, PetConstants.PET_MOVIE_SCRATCH: PetConstants.SCRATCH_TIME, PetConstants.PET_MOVIE_CALL: PetConstants.CALL_TIME } movieDistSwitch = { PetConstants.PET_MOVIE_FEED: PetConstants.FEED_DIST.get, PetConstants.PET_MOVIE_SCRATCH: PetConstants.SCRATCH_DIST.get } def __init__(self, air, dna=None): DistributedSmoothNodeAI.DistributedSmoothNodeAI.__init__(self, air) PetLookerAI.PetLookerAI.__init__(self) self.ownerId = 0 self.petName = 'unnamed' self.traitSeed = 0 self.safeZone = ToontownGlobals.ToontownCentral self.initialDNA = dna self.active = 1 self.activated = 0 self._outOfBounds = False self.traitList = [0] * PetTraits.PetTraits.NumTraits self.head = -1 self.ears = -1 self.nose = -1 self.tail = -1 self.bodyTexture = 0 self.color = 0 self.colorScale = 0 self.eyeColor = 0 self.gender = 0 self.movieMode = None self.lockMoverEnabled = 0 self.trickAptitudes = [] self.inEstate = 0 self.estateOwnerId = None self.estateZones = [] self.lastSeenTimestamp = self.getCurEpochTimestamp() self.requiredMoodComponents = {} self.__funcsToDelete = [] self.__generateDistTraitFuncs() self.__generateDistMoodFuncs() self.busy = 0 self.gaitFSM = ClassicFSM.ClassicFSM('petGaitFSM', [ State.State('off', self.gaitEnterOff, self.gaitExitOff), State.State('neutral', self.gaitEnterNeutral, self.gaitExitNeutral), State.State('happy', self.gaitEnterHappy, self.gaitExitHappy), State.State('sad', self.gaitEnterSad, self.gaitExitSad) ], 'off', 'off') self.gaitFSM.enterInitialState() self.unstickFSM = ClassicFSM.ClassicFSM('unstickFSM', [ State.State('off', self.unstickEnterOff, self.unstickExitOff), State.State('on', self.unstickEnterOn, self.unstickExitOn) ], 'off', 'off') self.unstickFSM.enterInitialState() if __dev__: self.pscMoveResc = PStatCollector( 'App:Show code:petMove:Reschedule') return def setInactive(self): self.active = 0 def _initDBVals(self, ownerId, name=None, traitSeed=0, dna=None, safeZone=ToontownGlobals.ToontownCentral): self.b_setOwnerId(ownerId) if name is None: name = 'pet%s' % self.doId self.b_setPetName(name) self.b_setTraitSeed(traitSeed) self.b_setSafeZone(safeZone) traits = PetTraits.PetTraits(traitSeed, safeZone) for traitName in PetTraits.getTraitNames(): setter = self.getSetterName(traitName, 'b_set') self.__dict__[setter](traits.getTraitValue(traitName)) self.traits = traits for component in PetMood.PetMood.Components: setterName = self.getSetterName(component, 'b_set') self.__dict__[setterName](0.0) if not dna: dna = PetDNA.getRandomPetDNA() self.setDNA(dna) self.b_setLastSeenTimestamp(self.getCurEpochTimestamp()) for component in PetMood.PetMood.Components: self.setMoodComponent(component, 0.0) self.b_setTrickAptitudes([]) return def setDNA(self, dna): head, ears, nose, tail, body, color, colorScale, eyes, gender = dna self.b_setHead(head) self.b_setEars(ears) self.b_setNose(nose) self.b_setTail(tail) self.b_setBodyTexture(body) self.b_setColor(color) self.b_setColorScale(colorScale) self.b_setEyeColor(eyes) self.b_setGender(gender) def handleZoneChange(self, newZoneId, oldZoneId): DistributedSmoothNodeAI.DistributedSmoothNodeAI.handleZoneChange( self, newZoneId, oldZoneId) self.ignore(PetObserve.getEventName(oldZoneId)) self.accept(PetObserve.getEventName(newZoneId), self.brain.observe) def handleLogicalZoneChange(self, newZoneId, oldZoneId): DistributedSmoothNodeAI.DistributedSmoothNodeAI.handleLogicalZoneChange( self, newZoneId, oldZoneId) self.announceZoneChange(newZoneId, oldZoneId) def announceZoneChange(self, newZoneId, oldZoneId): DistributedPetAI.notify.debug('%s.announceZoneChange: %s->%s' % (self.doId, oldZoneId, newZoneId)) broadcastZones = list2dict([newZoneId, oldZoneId]) self.estateOwnerId = simbase.air.estateManager.getOwnerFromZone( newZoneId) if self.estateOwnerId: if __dev__: pass self.inEstate = 1 self.estateZones = simbase.air.estateManager.getEstateZones( self.estateOwnerId) else: self.inEstate = 0 self.estateZones = [] PetObserve.send( broadcastZones.keys(), PetObserve.PetActionObserve(PetObserve.Actions.CHANGE_ZONE, self.doId, (oldZoneId, newZoneId))) def getOwnerId(self): return self.ownerId def b_setOwnerId(self, ownerId): self.d_setOwnerId(ownerId) self.setOwnerId(ownerId) def d_setOwnerId(self, ownerId): self.sendUpdate('setOwnerId', [ownerId]) def setOwnerId(self, ownerId): self.ownerId = ownerId def getPetName(self): return self.petName def b_setPetName(self, petName): self.d_setPetName(petName) self.setPetName(petName) def d_setPetName(self, petName): self.sendUpdate('setPetName', [petName]) def setPetName(self, petName): self.petName = petName DistributedSmoothNodeAI.DistributedSmoothNodeAI.setName( self, self.petName) def getTraitSeed(self): return self.traitSeed def b_setTraitSeed(self, traitSeed): self.d_setTraitSeed(traitSeed) self.setTraitSeed(traitSeed) def d_setTraitSeed(self, traitSeed): self.sendUpdate('setTraitSeed', [traitSeed]) def setTraitSeed(self, traitSeed): self.traitSeed = traitSeed def getSafeZone(self): return self.safeZone def b_setSafeZone(self, safeZone): self.d_setSafeZone(safeZone) self.setSafeZone(safeZone) def d_setSafeZone(self, safeZone): self.sendUpdate('setSafeZone', [safeZone]) def setSafeZone(self, safeZone): self.safeZone = safeZone def getPetName(self): return self.petName def b_setPetName(self, petName): self.d_setPetName(petName) self.setPetName(petName) def d_setPetName(self, petName): self.sendUpdate('setPetName', [petName]) def setPetName(self, petName): self.petName = petName DistributedSmoothNodeAI.DistributedSmoothNodeAI.setName( self, self.petName) def setTraits(self, traitList): self.traitList = traitList def __generateDistTraitFuncs(self): for i in xrange(PetTraits.PetTraits.NumTraits): traitName = PetTraits.getTraitNames()[i] getterName = self.getSetterName(traitName, 'get') b_setterName = self.getSetterName(traitName, 'b_set') d_setterName = self.getSetterName(traitName, 'd_set') setterName = self.getSetterName(traitName) def traitGetter(i=i): return self.traitList[i] def b_traitSetter(value, setterName=setterName, d_setterName=d_setterName): self.__dict__[d_setterName](value) self.__dict__[setterName](value) def d_traitSetter(value, setterName=setterName): self.sendUpdate(setterName, [value]) def traitSetter(value, i=i): self.traitList[i] = value self.__dict__[getterName] = traitGetter self.__dict__[b_setterName] = b_traitSetter self.__dict__[d_setterName] = d_traitSetter self.__dict__[setterName] = traitSetter self.__funcsToDelete.append(getterName) self.__funcsToDelete.append(b_setterName) self.__funcsToDelete.append(d_setterName) self.__funcsToDelete.append(setterName) def getHead(self): return self.head def b_setHead(self, head): self.d_setHead(head) self.setHead(head) def d_setHead(self, head): self.sendUpdate('setHead', [head]) def setHead(self, head): self.head = head def getEars(self): return self.ears def b_setEars(self, ears): self.d_setEars(ears) self.setEars(ears) def d_setEars(self, ears): self.sendUpdate('setEars', [ears]) def setEars(self, ears): self.ears = ears def getNose(self): return self.nose def b_setNose(self, nose): self.d_setNose(nose) self.setNose(nose) def d_setNose(self, nose): self.sendUpdate('setNose', [nose]) def setNose(self, nose): self.nose = nose def getTail(self): return self.tail def b_setTail(self, tail): self.d_setTail(tail) self.setTail(tail) def d_setTail(self, tail): self.sendUpdate('setTail', [tail]) def setTail(self, tail): self.tail = tail def getBodyTexture(self): return self.bodyTexture def b_setBodyTexture(self, bodyTexture): self.d_setBodyTexture(bodyTexture) self.setBodyTexture(bodyTexture) def d_setBodyTexture(self, bodyTexture): self.sendUpdate('setBodyTexture', [bodyTexture]) def setBodyTexture(self, bodyTexture): self.bodyTexture = bodyTexture def getColor(self): return self.color def b_setColor(self, color): self.d_setColor(color) self.setColor(color) def d_setColor(self, color): self.sendUpdate('setColor', [color]) def setColor(self, color): self.color = color def getColorScale(self): return self.colorScale def b_setColorScale(self, colorScale): self.d_setColorScale(colorScale) self.setColorScale(colorScale) def d_setColorScale(self, colorScale): self.sendUpdate('setColorScale', [colorScale]) def setColorScale(self, colorScale): self.colorScale = colorScale def getEyeColor(self): return self.eyeColor def b_setEyeColor(self, eyeColor): self.d_setEyeColor(eyeColor) self.setEyeColor(eyeColor) def d_setEyeColor(self, eyeColor): self.sendUpdate('setEyeColor', [eyeColor]) def setEyeColor(self, eyeColor): self.eyeColor = eyeColor def getGender(self): return self.gender def b_setGender(self, gender): self.d_setGender(gender) self.setGender(gender) def d_setGender(self, gender): self.sendUpdate('setGender', [gender]) def setGender(self, gender): self.gender = gender def teleportIn(self, timestamp=None): self.notify.debug('DPAI: teleportIn') timestamp = ClockDelta.globalClockDelta.getRealNetworkTime() self.notify.debug('DPAI: sending update @ ts = %s' % timestamp) self.sendUpdate('teleportIn', [timestamp]) return None def teleportOut(self, timestamp=None): self.notify.debug('DPAI: teleportOut') timestamp = ClockDelta.globalClockDelta.getRealNetworkTime() self.notify.debug('DPAI: sending update @ ts = %s' % timestamp) self.sendUpdate('teleportOut', [timestamp]) return None def getLastSeenTimestamp(self): return self.lastSeenTimestamp def b_setLastSeenTimestamp(self, timestamp): self.d_setLastSeenTimestamp(timestamp) self.setLastSeenTimestamp(timestamp) def d_setLastSeenTimestamp(self, timestamp): self.sendUpdate('setLastSeenTimestamp', [timestamp]) def setLastSeenTimestamp(self, timestamp): self.lastSeenTimestamp = timestamp def getCurEpochTimestamp(self): return int(time.time()) def getTimeSinceLastSeen(self): t = time.time() - self.lastSeenTimestamp return max(0.0, t) def __handleMoodSet(self, component, value): if self.isGenerated(): self.mood.setComponent(component, value) else: self.requiredMoodComponents[component] = value def __handleMoodGet(self, component): if self.isGenerated(): return self.mood.getComponent(component) else: return 0.0 def __generateDistMoodFuncs(self): for compName in PetMood.PetMood.Components: getterName = self.getSetterName(compName, 'get') setterName = self.getSetterName(compName) def moodGetter(compName=compName): return self.__handleMoodGet(compName) def b_moodSetter(value, setterName=setterName): self.__dict__[setterName](value) def d_moodSetter(value, setterName=setterName): self.sendUpdate(setterName, [value]) def moodSetter(value, compName=compName): self.__handleMoodSet(compName, value) self.__dict__[getterName] = moodGetter self.__dict__['b_%s' % setterName] = b_moodSetter self.__dict__['d_%s' % setterName] = d_moodSetter self.__dict__[setterName] = moodSetter self.__funcsToDelete.append(getterName) self.__funcsToDelete.append('b_%s' % setterName) self.__funcsToDelete.append('d_%s' % setterName) self.__funcsToDelete.append(setterName) def getTrickAptitudes(self): return self.trickAptitudes def b_setTrickAptitudes(self, aptitudes): self.setTrickAptitudes(aptitudes, local=1) self.d_setTrickAptitudes(aptitudes) def d_setTrickAptitudes(self, aptitudes): if __dev__: for aptitude in aptitudes: pass while len(aptitudes) < len(PetTricks.Tricks) - 1: aptitudes.append(0.0) self.sendUpdate('setTrickAptitudes', [aptitudes]) def setTrickAptitudes(self, aptitudes, local=0): if not local: DistributedPetAI.notify.debug('setTrickAptitudes: %s' % aptitudes) while len(self.trickAptitudes) < len(PetTricks.Tricks) - 1: self.trickAptitudes.append(0.0) self.trickAptitudes = aptitudes def getTrickAptitude(self, trickId): if trickId > len(self.trickAptitudes) - 1: return 0.0 return self.trickAptitudes[trickId] def setTrickAptitude(self, trickId, aptitude, send=1): aptitude = clampScalar(aptitude, 0.0, 1.0) aptitudes = self.trickAptitudes while len(aptitudes) - 1 < trickId: aptitudes.append(0.0) if aptitudes[trickId] != aptitude: aptitudes[trickId] = aptitude if send: self.b_setTrickAptitudes(aptitudes) else: self.setTrickAptitudes(aptitudes, local=1) def announceGenerate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.announceGenerate(self) self._hasCleanedUp = False self.setHasRequestedDelete(False) self.b_setParent(ToontownGlobals.SPHidden) self.lockedDown = 0 self.leashMode = 0 self.leashAvId = None self.leashGoal = None self.trickLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksPerformed', self.doId) self.trickFailLogger = ServerEventBuffer.ServerEventMultiAccumulator( self.air, 'petTricksFailed', self.doId) self.feedLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petFeedings', self.doId) self.scratchLogger = ServerEventBuffer.ServerEventAccumulator( self.air, 'petScratchings', self.doId) self.traits = PetTraits.PetTraits(self.traitSeed, self.safeZone) if not hasattr(self, '_beingCreatedInDB'): for i in xrange(len(self.traitList)): value = self.traitList[i] if value == 0.0: traitName = PetTraits.getTraitNames()[i] traitValue = self.traits.getTraitValue(traitName) DistributedPetAI.notify.info( "%s: initializing new trait '%s' to %s, seed=%s" % (self.doId, traitName, traitValue, self.traitSeed)) setterName = self.getSetterName(traitName, 'b_set') self.__dict__[setterName](traitValue) self.mood = PetMood.PetMood(self) if not self.active: return self.activated = 1 self.announceZoneChange(self.zoneId, ToontownGlobals.QuietZone) self.b_setParent(ToontownGlobals.SPRender) self.setPos(randFloat(-20, 20), randFloat(-20, 20), 0) self.setH(randFloat(360)) if self.initialDNA: self.setDNA(self.initialDNA) for mood, value in self.requiredMoodComponents.items(): self.mood.setComponent(mood, value, announce=0) self.requiredMoodComponents = {} self.brain = PetBrain.PetBrain(self) self.mover = PetMoverAI(self) self.enterPetLook() self.actionFSM = PetActionFSM.PetActionFSM(self) self.teleportIn() self.handleMoodChange(distribute=0) taskMgr.doMethodLater(simbase.petMovePeriod * random.random(), self.move, self.getMoveTaskName()) self.startPosHprBroadcast() self.accept(PetObserve.getEventName(self.zoneId), self.brain.observe) self.accept(self.mood.getMoodChangeEvent(), self.handleMoodChange) self.mood.start() self.brain.start() return def _isPet(self): return 1 def setHasRequestedDelete(self, flag): self._requestedDeleteFlag = flag def hasRequestedDelete(self): return self._requestedDeleteFlag def requestDelete(self, task=None): DistributedPetAI.notify.info('PetAI.requestDelete: %s, owner=%s' % (self.doId, self.ownerId)) if self.hasRequestedDelete(): DistributedPetAI.notify.info( 'PetAI.requestDelete: %s, owner=%s returning immediately' % (self.doId, self.ownerId)) return self.setHasRequestedDelete(True) self.b_setLastSeenTimestamp(self.getCurEpochTimestamp()) DistributedSmoothNodeAI.DistributedSmoothNodeAI.requestDelete(self) def _doDeleteCleanup(self): self.trickLogger.destroy() self.trickFailLogger.destroy() self.feedLogger.destroy() self.scratchLogger.destroy() del self.trickLogger del self.trickFailLogger del self.feedLogger del self.scratchLogger taskMgr.remove(self.uniqueName('clearMovie')) taskMgr.remove(self.uniqueName('PetMovieWait')) taskMgr.remove(self.uniqueName('PetMovieClear')) taskMgr.remove(self.uniqueName('PetMovieComplete')) taskMgr.remove(self.getLockMoveTaskName()) taskMgr.remove(self.getMoveTaskName()) if hasattr(self, 'zoneId'): self.announceZoneChange(ToontownGlobals.QuietZone, self.zoneId) else: myDoId = 'No doId' myTaskName = 'No task name' myStackTrace = StackTrace().trace myOldStackTrace = 'No Trace' if hasattr(self, 'doId'): myDoId = self.doId if task: myTaskName = task.name if hasattr(self, 'destroyDoStackTrace'): myOldStackTrace = self.destroyDoStackTrace.trace simbase.air.writeServerEvent('Pet RequestDelete duplicate', myDoId, 'from task %s' % myTaskName) simbase.air.writeServerEvent( 'Pet RequestDelete duplicate StackTrace', myDoId, '%s' % myStackTrace) simbase.air.writeServerEvent( 'Pet RequestDelete duplicate OldStackTrace', myDoId, '%s' % myOldStackTrace) DistributedPetAI.notify.warning( 'double requestDelete from task %s' % myTaskName) self.setParent(ToontownGlobals.SPHidden) if hasattr(self, 'activated'): if self.activated: self.activated = 0 self.brain.destroy() del self.brain self.actionFSM.destroy() del self.actionFSM self.exitPetLook() self.mover.destroy() del self.mover self.stopPosHprBroadcast() if hasattr(self, 'mood'): self.mood.destroy() del self.mood if hasattr(self, 'traits'): del self.traits try: for funcName in self.__funcsToDelete: del self.__dict__[funcName] except: pass if hasattr(self, 'gaitFSM'): if self.gaitFSM: self.gaitFSM.requestFinalState() del self.gaitFSM if hasattr(self, 'unstickFSM'): if self.unstickFSM: self.unstickFSM.requestFinalState() del self.unstickFSM if __dev__: del self.pscMoveResc PetLookerAI.PetLookerAI.destroy(self) self.ignoreAll() self._hasCleanedUp = True def delete(self): DistributedPetAI.notify.info('PetAI.delete: %s, owner=%s' % (self.doId, self.ownerId)) if not self._hasCleanedUp: self._doDeleteCleanup() self.setHasRequestedDelete(False) DistributedSmoothNodeAI.DistributedSmoothNodeAI.delete(self) def patchDelete(self): for funcName in self.__funcsToDelete: del self.__dict__[funcName] del self.gaitFSM del self.unstickFSM if __dev__: del self.pscMoveResc PetLookerAI.PetLookerAI.destroy(self) self.doNotDeallocateChannel = True self.zoneId = None DistributedSmoothNodeAI.DistributedSmoothNodeAI.delete(self) self.ignoreAll() return def getMoveTaskName(self): return 'petMove-%s' % self.doId def getLockMoveTaskName(self): return 'petLockMove-%s' % self.doId def move(self, task=None): if self.isEmpty(): self.air.writeServerEvent('Late Pet Move Call', self.doId, ' ') taskMgr.remove(task.name) return Task.done numNearby = len(self.brain.nearbyAvs) - 1 minNearby = 5 if numNearby > minNearby: delay = 0.08 * (numNearby - minNearby) self.setPosHprBroadcastPeriod(PetConstants.PosBroadcastPeriod + lerp(delay * 0.75, delay, random.random())) maxDist = 1000 if abs(self.getX()) > maxDist or abs(self.getY()) > maxDist: DistributedPetAI.notify.warning( 'deleting pet %s before he wanders off too far' % self.doId) self._outOfBounds = True self.stopPosHprBroadcast() self.requestDelete() return Task.done if __dev__: self.pscMoveResc.start() taskMgr.doMethodLater(simbase.petMovePeriod, self.move, self.getMoveTaskName()) if __dev__: self.pscMoveResc.stop() return Task.done def startPosHprBroadcast(self): if self._outOfBounds: return DistributedSmoothNodeAI.DistributedSmoothNodeAI.startPosHprBroadcast( self, period=simbase.petPosBroadcastPeriod, type=DistributedSmoothNodeBase.DistributedSmoothNodeBase. BroadcastTypes.XYH) def setMoodComponent(self, component, value): setter = self.getSetterName(component, 'b_set') self.__dict__[setter](value) def addToMood(self, component, delta): value = self.mood.getComponent(component) value += delta self.setMoodComponent(component, clampScalar(value, 0.0, 1.0)) def lerpMood(self, component, factor): curVal = self.mood.getComponent(component) if factor < 0: self.setMoodComponent(component, lerp(curVal, 0.0, -factor)) else: self.setMoodComponent(component, lerp(curVal, 1.0, factor)) def addToMoods(self, mood2delta): for mood, delta in mood2delta.items(): self.addToMood(mood, delta) def lerpMoods(self, mood2factor): for mood, factor in mood2factor.items(): self.lerpMood(mood, factor) def handleMoodChange(self, components=[], distribute=1): if len(components) == 0: components = PetMood.PetMood.Components if distribute: if len(components) == len(PetMood.PetMood.Components): values = [] for comp in PetMood.PetMood.Components: values.append(self.mood.getComponent(comp)) self.sendUpdate('setMood', values) else: for comp in components: setter = self.getSetterName(comp, 'd_set') self.__dict__[setter](self.mood.getComponent(comp)) if self.isExcited(): self.gaitFSM.request('happy') elif self.isSad(): self.gaitFSM.request('sad') else: self.gaitFSM.request('neutral') def isContented(self): return self.mood.getDominantMood() in PetMood.PetMood.ContentedMoods def call(self, avatar): self.brain.observe( PetObserve.PetPhraseObserve(PetObserve.Phrases.COME, avatar.doId)) self.__petMovieStart(avatar.doId) def feed(self, avatar): if avatar.takeMoney(PetConstants.FEED_AMOUNT): self.startLockPetMove(avatar.doId) self.brain.observe( PetObserve.PetActionObserve(PetObserve.Actions.FEED, avatar.doId)) self.feedLogger.addEvent() def scratch(self, avatar): self.startLockPetMove(avatar.doId) self.brain.observe( PetObserve.PetActionObserve(PetObserve.Actions.SCRATCH, avatar.doId)) self.scratchLogger.addEvent() def lockPet(self): DistributedPetAI.notify.debug('%s: lockPet' % self.doId) if not self.lockedDown: self.mover.lock() self.stopPosHprBroadcast() self.lockedDown += 1 def isLockedDown(self): return self.lockedDown != 0 def unlockPet(self): DistributedPetAI.notify.debug('%s: unlockPet' % self.doId) if self.lockedDown <= 0: DistributedPetAI.notify.warning( '%s: unlockPet called on unlocked pet' % self.doId) else: self.lockedDown -= 1 if not self.lockedDown and not self.isDeleted(): self.startPosHprBroadcast() def handleStay(self, avatar): self.brain.observe( PetObserve.PetPhraseObserve(PetObserve.Phrases.STAY, avatar.doId)) def handleShoo(self, avatar): self.brain.observe( PetObserve.PetPhraseObserve(PetObserve.Phrases.GO_AWAY, avatar.doId)) def gaitEnterOff(self): pass def gaitExitOff(self): pass def gaitEnterNeutral(self): self.mover.setFwdSpeed(PetConstants.FwdSpeed) self.mover.setRotSpeed(PetConstants.RotSpeed) def gaitExitNeutral(self): pass def gaitEnterHappy(self): self.mover.setFwdSpeed(PetConstants.HappyFwdSpeed) self.mover.setRotSpeed(PetConstants.HappyRotSpeed) def gaitExitHappy(self): pass def gaitEnterSad(self): self.mover.setFwdSpeed(PetConstants.SadFwdSpeed) self.mover.setRotSpeed(PetConstants.SadRotSpeed) def gaitExitSad(self): pass def unstickEnterOff(self): pass def unstickExitOff(self): pass def unstickEnterOn(self): self._collisionTimestamps = [] def unstickExitOn(self): pass def ownerIsOnline(self): return self.ownerId in simbase.air.doId2do def ownerIsInSameZone(self): if not self.ownerIsOnline(): return 0 return self.zoneId == simbase.air.doId2do[self.ownerId].zoneId def _getOwnerDict(self): if self.owner is not None: if self.ownerIsInSameZone(): return {self.ownerId: self.owner} return {} def _getFullNearbyToonDict(self): toons = self.air.getObjectsOfClassInZone( self.air.districtId, self.zoneId, DistributedToonAI.DistributedToonAI) return toons def _getNearbyToonDict(self): toons = self._getFullNearbyToonDict() if self.ownerId in toons: del toons[self.ownerId] return toons def _getNearbyPetDict(self): pets = self.air.getObjectsOfClassInZone(self.air.districtId, self.zoneId, DistributedPetAI) if self.doId in pets: del pets[self.doId] return pets def _getNearbyAvatarDict(self): avs = self._getFullNearbyToonDict() avs.update(self._getNearbyPetDict()) return avs def _getOwner(self): return self.air.doId2do.get(self.ownerId) def _getNearbyToon(self): nearbyToonDict = self._getFullNearbyToonDict() if not len(nearbyToonDict): return None return nearbyToonDict[random.choice(nearbyToonDict.keys())] def _getNearbyToonNonOwner(self): nearbyToonDict = self._getNearbyToonDict() if not len(nearbyToonDict): return None return nearbyToonDict[random.choice(nearbyToonDict.keys())] def _getNearbyPet(self): nearbyPetDict = self._getNearbyPetDict() if not len(nearbyPetDict): return None return nearbyPetDict[random.choice(nearbyPetDict.keys())] def _getNearbyAvatar(self): nearbyAvDict = self._getNearbyAvatarDict() if not len(nearbyAvDict): return None return nearbyAvDict[random.choice(nearbyAvDict.keys())] def isBusy(self): return self.busy > 0 def freeAvatar(self, avId): self.sendUpdateToAvatarId(avId, 'freeAvatar', []) def avatarInteract(self, avId): av = self.air.doId2do.get(avId) if av is None: self.notify.warning('Avatar: %s not found' % avId) return 0 if self.isBusy(): self.notify.debug('freeing avatar!') self.freeAvatar(avId) return 0 self.busy = avId self.notify.debug('sending update') self.sendUpdateToAvatarId(avId, 'avatarInteract', [avId]) self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId]) return 1 def rejectAvatar(self, avId): self.notify.error('rejectAvatar: should not be called by a pet!') def d_setMovie(self, avId, flag): self.sendUpdate( 'setMovie', [flag, avId, ClockDelta.globalClockDelta.getRealNetworkTime()]) def sendClearMovie(self, task=None): if self.air != None: self.ignore(self.air.getAvatarExitEvent(self.busy)) taskMgr.remove(self.uniqueName('clearMovie')) self.busy = 0 self.d_setMovie(0, PetConstants.PET_MOVIE_CLEAR) return Task.done def __handleUnexpectedExit(self, avId): self.notify.warning('avatar:' + str(avId) + ' has exited unexpectedly') self.notify.warning('not busy with avId: %s, busy: %s ' % (avId, self.busy)) taskMgr.remove(self.uniqueName('clearMovie')) self.sendClearMovie() def handleAvPetInteraction(self, mode, avId): if mode not in (PetConstants.PET_MOVIE_SCRATCH, PetConstants.PET_MOVIE_FEED, PetConstants.PET_MOVIE_CALL): self.air.writeServerEvent( 'suspicious', avId, 'DistributedPetAI: unknown mode: %s' % mode) return if self.avatarInteract(avId): self.notify.debug( 'handleAvPetInteraction() avatarInteract calling callback') self.movieMode = mode callback = { PetConstants.PET_MOVIE_SCRATCH: self.scratch, PetConstants.PET_MOVIE_FEED: self.feed, PetConstants.PET_MOVIE_CALL: self.call }.get(mode) callback(self.air.doId2do.get(avId)) else: self.notify.debug( 'handleAvPetInteraction() avatarInteract was busy or unhappy') def __petMovieStart(self, avId): self.d_setMovie(avId, self.movieMode) time = self.movieTimeSwitch.get(self.movieMode) taskMgr.doMethodLater(time, self.__petMovieComplete, self.uniqueName('PetMovieComplete')) def __petMovieComplete(self, task=None): self.disableLockMover() self.unlockPet() self.sendClearMovie() self.movieMode = None return Task.done def startLockPetMove(self, avId): self.enableLockMover() dist_Callable = self.movieDistSwitch.get(self.movieMode) dist = dist_Callable( self.air.doId2do.get(avId).getStyle().getLegSize()) self.distList = [0, 0, 0] self.mover.walkToAvatar(self.air.doId2do[avId], callback=lambda: self.endLockPetMove(avId)) self.__lockPetMoveTask(avId) def getAverageDist(self): sum = 0 for i in self.distList: sum += i return sum / 3.0 def __lockPetMoveTask(self, avId): return Task.done def endLockPetMove(self, avId): del self.distList taskMgr.remove(self.getLockMoveTaskName()) self.lockPet() self.__petMovieStart(avId) def enableLockMover(self): if not hasattr(self, 'brain'): return if self.lockMoverEnabled == 0: self.brain._startMovie() self.lockMoverEnabled += 1 def isLockMoverEnabled(self): return self.lockMoverEnabled > 0 def disableLockMover(self): if not hasattr(self, 'brain'): return if self.lockMoverEnabled > 0: self.lockMoverEnabled -= 1 if self.lockMoverEnabled == 0: self.brain._endMovie() def _willDoTrick(self, trickId): if self.isContented(): minApt = PetTricks.MinActualTrickAptitude maxApt = PetTricks.MaxActualTrickAptitude else: minApt = PetTricks.NonHappyMinActualTrickAptitude maxApt = PetTricks.NonHappyMaxActualTrickAptitude randVal = random.random() cutoff = lerp(minApt, maxApt, self.getTrickAptitude(trickId)) if self.mood.isComponentActive('fatigue'): cutoff *= 0.5 cutoff *= PetTricks.TrickAccuracies[trickId] DistributedPetAI.notify.info('_willDoTrick: %s / %s' % (randVal, cutoff)) # .debug return randVal < cutoff def _handleDidTrick(self, trickId): DistributedPetAI.notify.debug('_handleDidTrick: %s' % trickId) if trickId == PetTricks.Tricks.BALK: return aptitude = self.getTrickAptitude(trickId) self.setTrickAptitude(trickId, aptitude + PetTricks.AptitudeIncrementDidTrick) self.addToMood( 'fatigue', lerp(PetTricks.MaxTrickFatigue, PetTricks.MinTrickFatigue, aptitude)) self.trickLogger.addEvent(trickId) def _handleGotPositiveTrickFeedback(self, trickId, magnitude): if trickId == PetTricks.Tricks.BALK: return self.setTrickAptitude( trickId, self.getTrickAptitude(trickId) + PetTricks.MaxAptitudeIncrementGotPraise * magnitude) def toggleLeash(self, avId): if self.leashMode: self.leashMode = 0 self.leashAvId = None response = 'leash OFF' else: self.leashMode = 1 self.leashAvId = avId response = 'leash ON' return response