def createImpulses(self): from toontown.pets import PetWander self.createSphereImpulse() self.chaseImpulse = PetChase.PetChase() self.fleeImpulse = PetFlee.PetFlee() self.wanderImpulse = PetWander.PetWander() self.lockChaseImpulse = PetChase.PetChase()
def __init__(self, minDist=5.0, moveAngle=20.0): self.movingTarget = hidden.attachNewNode('petWanderTarget') PetChase.__init__(self, self.movingTarget, minDist, moveAngle) self.targetMoveCountdown = 0 self.collEvent = None self.gotCollision = False return
def createImpulses(self): from toontown.pets import PetWander self.createSphereImpulse() if self.public == False: self.chaseImpulse = PetChase.PetChase() self.fleeImpulse = PetFlee.PetFlee() self.wanderImpulse = PetWander.PetWander() else: self.chaseImpulse = None self.fleeImpulse = None self.wanderImpulse = None self.lockChaseImpulse = PetChase.PetChase()
def _process(self, dt): self.targetMoveCountdown -= dt if self.targetMoveCountdown <= 0.0: distance = normalDistrib(3.0, 30.0) heading = normalDistrib(-(90 + 45), 90 + 45) if self.gotCollision: self.gotCollision = False heading += 180 target = self.getTarget() target.setPos(self.getNodePath().getPos()) target.setH(target, heading) target.setY(target, distance) duration = distance / self.mover.getFwdSpeed() self.targetMoveCountdown = duration * randFloat(1.2, 3.0) PetChase.process(self, dt)
def createImpulses(self): self.createSphereImpulse() self.chaseImpulse = PetChase() self.fleeImpulse = PetFlee() self.wanderImpulse = PetWander.PetWander() self.lockChaseImpulse = PetChase()
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) self.destroySphereImpulse() self.createSphereImpulse() def announceZoneChange(self, newZoneId, oldZoneId): DistributedPetAI.notify.debug('%s.announceZoneChange: %s->%s' % (self.doId, oldZoneId, newZoneId)) broadcastZones = list2dict([newZoneId, oldZoneId]) self.estateOwnerId = simbase.air.estateMgr.getOwnerFromZone(newZoneId) if self.estateOwnerId: if __dev__: pass self.inEstate = 1 self.estateZones = simbase.air.estateMgr.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 = bound(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 generate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.generate(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 = Mover.Mover(self) self.lockMover = Mover.Mover(self) self.createImpulses() 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.destroyImpulses() self.mover.destroy() del self.mover self.lockMover.destroy() del self.lockMover 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 createImpulses(self): self.createSphereImpulse() self.chaseImpulse = PetChase() self.fleeImpulse = PetFlee() self.wanderImpulse = PetWander.PetWander() self.lockChaseImpulse = PetChase() def destroyImpulses(self): self.wanderImpulse.destroy() del self.chaseImpulse del self.fleeImpulse del self.wanderImpulse self.destroySphereImpulse() del self.lockChaseImpulse def createSphereImpulse(self): petRadius = 1.0 collTrav = self.getCollTrav() if collTrav is None: DistributedPetAI.notify.warning('no collision traverser for zone %s' % self.zoneId) else: self.sphereImpulse = PetSphere.PetSphere(petRadius, collTrav) self.mover.addImpulse('sphere', self.sphereImpulse) return def destroySphereImpulse(self): self.mover.removeImpulse('sphere') if hasattr(self, 'sphereImpulse'): self.sphereImpulse.destroy() del self.sphereImpulse def getMoveTaskName(self): return 'petMove-%s' % self.doId def getLockMoveTaskName(self): return 'petLockMove-%s' % self.doId def move(self, task = None): if self.isEmpty(): try: self.air.writeServerEvent('Late Pet Move Call', self.doId, ' ') except: pass taskMgr.remove(task.name) return Task.done if not self.isLockMoverEnabled(): self.mover.move() 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, bound(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.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 = [] self.accept(self.mover.getCollisionEventName(), self._handleCollided) def _handleCollided(self, collEntry): now = globalClock.getFrameTime() self._collisionTimestamps.append(now) while now - self._collisionTimestamps[0] > PetConstants.UnstickSampleWindow: del self._collisionTimestamps[0:1] if len(self._collisionTimestamps) > PetConstants.UnstickCollisionThreshold: self._collisionTimestamps = [] DistributedPetAI.notify.debug('unsticking pet %s' % self.doId) self.brain._unstick() 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() self.lockChaseImpulse.setTarget(self.air.doId2do.get(avId)) self.lockMover.addImpulse('LockTarget', self.lockChaseImpulse) self.lockMover.setFwdSpeed(self.mover.getFwdSpeed()) self.lockMover.setRotSpeed(self.mover.getRotSpeed()) dist_Callable = self.movieDistSwitch.get(self.movieMode) dist = dist_Callable(self.air.doId2do.get(avId).getStyle().getLegSize()) self.lockChaseImpulse.setMinDist(dist) self.distList = [0, 0, 0] self.__lockPetMoveTask(avId) def getAverageDist(self): sum = 0 for i in self.distList: sum += i return sum / 3.0 def __lockPetMoveTask(self, avId): if not hasattr(self, 'air') or avId not in self.air.doId2do: self.notify.warning('avId: %s gone or self deleted!' % avId) return Task.done av = self.air.doId2do.get(avId) dist = av.getDistance(self) self.distList.append(dist) if len(self.distList) > 3: self.distList.pop(0) if self.movieMode in self.movieDistSwitch: dist_Callable = self.movieDistSwitch.get(self.movieMode) movieDist = dist_Callable(av.getStyle().getLegSize()) else: self.notify.warning('movieMode: %s not in movieSwitchDist map!' % self.movieMode) return Task.done avgDist = self.getAverageDist() if dist - movieDist > 0.25 and abs(avgDist - dist) > 0.1: self.lockMover.move() taskMgr.doMethodLater(simbase.petMovePeriod, self.__lockPetMoveTask, self.getLockMoveTaskName(), [avId]) else: self.endLockPetMove(avId) return Task.done def endLockPetMove(self, avId): del self.distList taskMgr.remove(self.getLockMoveTaskName()) self.lockPet() self.lockMover.removeImpulse('LockTarget') self.__petMovieStart(avId) def enableLockMover(self): if self.lockMoverEnabled == 0: self.brain._startMovie() self.lockMoverEnabled += 1 def isLockMoverEnabled(self): return self.lockMoverEnabled > 0 def disableLockMover(self): 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.debug('_willDoTrick: %s / %s' % (randVal, cutoff)) 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 self.brain.goalMgr.removeGoal(self.leashGoal) del self.leashGoal response = 'leash OFF' else: self.leashMode = 1 self.leashAvId = avId self.leashGoal = PetGoal.ChaseAvatarLeash(avId) self.brain.goalMgr.addGoal(self.leashGoal) 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) self.destroySphereImpulse() self.createSphereImpulse() def announceZoneChange(self, newZoneId, oldZoneId): DistributedPetAI.notify.debug('%s.announceZoneChange: %s->%s' % (self.doId, oldZoneId, newZoneId)) broadcastZones = list2dict([newZoneId, oldZoneId]) self.estateOwnerId = simbase.air.estateMgr.getOwnerFromZone(newZoneId) if self.estateOwnerId: if __dev__: pass self.inEstate = 1 self.estateZones = simbase.air.estateMgr.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 = min(max(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 generate(self): DistributedSmoothNodeAI.DistributedSmoothNodeAI.generate(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 = Mover.Mover(self) self.lockMover = Mover.Mover(self) self.createImpulses() 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.destroyImpulses() self.mover.destroy() del self.mover self.lockMover.destroy() del self.lockMover 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 createImpulses(self): self.createSphereImpulse() self.chaseImpulse = PetChase() self.fleeImpulse = PetFlee() self.wanderImpulse = PetWander.PetWander() self.lockChaseImpulse = PetChase() def destroyImpulses(self): self.wanderImpulse.destroy() del self.chaseImpulse del self.fleeImpulse del self.wanderImpulse self.destroySphereImpulse() del self.lockChaseImpulse def createSphereImpulse(self): petRadius = 1.0 collTrav = self.getCollTrav() if collTrav is None: DistributedPetAI.notify.warning('no collision traverser for zone %s' % self.zoneId) else: self.sphereImpulse = PetSphere.PetSphere(petRadius, collTrav) self.mover.addImpulse('sphere', self.sphereImpulse) return def destroySphereImpulse(self): self.mover.removeImpulse('sphere') if hasattr(self, 'sphereImpulse'): self.sphereImpulse.destroy() del self.sphereImpulse def getMoveTaskName(self): return 'petMove-%s' % self.doId def getLockMoveTaskName(self): return 'petLockMove-%s' % self.doId def move(self, task = None): if self.isEmpty(): try: self.air.writeServerEvent('Late Pet Move Call', self.doId, ' ') except: pass taskMgr.remove(task.name) return Task.done if not self.isLockMoverEnabled(): self.mover.move() 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, min(max(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.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 = [] self.accept(self.mover.getCollisionEventName(), self._handleCollided) def _handleCollided(self, collEntry): now = globalClock.getFrameTime() self._collisionTimestamps.append(now) while now - self._collisionTimestamps[0] > PetConstants.UnstickSampleWindow: del self._collisionTimestamps[0:1] if len(self._collisionTimestamps) > PetConstants.UnstickCollisionThreshold: self._collisionTimestamps = [] DistributedPetAI.notify.debug('unsticking pet %s' % self.doId) self.brain._unstick() 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() self.lockChaseImpulse.setTarget(self.air.doId2do.get(avId)) self.lockMover.addImpulse('LockTarget', self.lockChaseImpulse) self.lockMover.setFwdSpeed(self.mover.getFwdSpeed()) self.lockMover.setRotSpeed(self.mover.getRotSpeed()) dist_Callable = self.movieDistSwitch.get(self.movieMode) dist = dist_Callable(self.air.doId2do.get(avId).getStyle().getLegSize()) self.lockChaseImpulse.setMinDist(dist) self.distList = [0, 0, 0] self.__lockPetMoveTask(avId) def getAverageDist(self): sum = 0 for i in self.distList: sum += i return sum / 3.0 def __lockPetMoveTask(self, avId): if not hasattr(self, 'air') or avId not in self.air.doId2do: self.notify.warning('avId: %s gone or self deleted!' % avId) return Task.done av = self.air.doId2do.get(avId) dist = av.getDistance(self) self.distList.append(dist) if len(self.distList) > 3: self.distList.pop(0) if self.movieMode in self.movieDistSwitch: dist_Callable = self.movieDistSwitch.get(self.movieMode) movieDist = dist_Callable(av.getStyle().getLegSize()) else: self.notify.warning('movieMode: %s not in movieSwitchDist map!' % self.movieMode) return Task.done avgDist = self.getAverageDist() if dist - movieDist > 0.25 and abs(avgDist - dist) > 0.1: self.lockMover.move() taskMgr.doMethodLater(simbase.petMovePeriod, self.__lockPetMoveTask, self.getLockMoveTaskName(), [avId]) else: self.endLockPetMove(avId) return Task.done def endLockPetMove(self, avId): del self.distList taskMgr.remove(self.getLockMoveTaskName()) self.lockPet() self.lockMover.removeImpulse('LockTarget') self.__petMovieStart(avId) def enableLockMover(self): if self.lockMoverEnabled == 0: self.brain._startMovie() self.lockMoverEnabled += 1 def isLockMoverEnabled(self): return self.lockMoverEnabled > 0 def disableLockMover(self): 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.debug('_willDoTrick: %s / %s' % (randVal, cutoff)) 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 self.brain.goalMgr.removeGoal(self.leashGoal) del self.leashGoal response = 'leash OFF' else: self.leashMode = 1 self.leashAvId = avId self.leashGoal = PetGoal.ChaseAvatarLeash(avId) self.brain.goalMgr.addGoal(self.leashGoal) response = 'leash ON' return response
def createImpulses(self): self.createSphereImpulse() self.chaseImpulse = PetChase.PetChase() self.fleeImpulse = PetFlee.PetFlee() self.lockChaseImpulse = PetChase.PetChase()
def _clearMover(self, mover): PetChase.clearMover(self, mover) self.__ignoreCollisions()
def _setMover(self, mover): PetChase.setMover(self, mover) self.mover = mover self.__ignoreCollisions() self.collEvent = mover.getCollisionEventName() self.accept(self.collEvent, self._handleCollision)