def equip(self, itemType): ''' Equip an item of the given enumerated type from this agent's inventory. Returns true if the agent successfully equips the item, false otherwise. Preconditions: - The agent has an item of the given type ''' # Check action override if self.__shouldPerformActionOverride(self.equip): return self.__actionOverride.function(*self.__actionOverride.args) # Preconditions if not self.__checkPreconditions( self.inventory.amountOfItem(itemType) >= 1): return False # Obtain a reference to the item we will equip inventoryItem = self.inventory.getItem(itemType) oldIndex = self.inventory.getItemIndex(itemType) if inventoryItem == None or oldIndex == None: return False # If item is already in the hotbar... if oldIndex < 9: self.__host.sendCommand("hotbar.{} 1".format(oldIndex + 1)) self.__host.sendCommand("hotbar.{} 0".format(oldIndex + 1)) self.__logReports.append(LogUtils.EquipReport(inventoryItem)) return True # If there is an available hotbar slot... newIndex = self.inventory.nextUnusedHotbarIndex() if newIndex != None: self.__host.sendCommand("swapInventoryItems {} {}".format(newIndex, oldIndex)) self.__host.sendCommand("hotbar.{} 1".format(newIndex + 1)) self.__host.sendCommand("hotbar.{} 0".format(newIndex + 1)) self.__logReports.append(LogUtils.EquipReport(inventoryItem)) return True # Swap item in overflow w/ item in hotbar newIndex = self.inventory.equippedIndex() if newIndex != -1: self.__host.sendCommand("swapInventoryItems {} {}".format(newIndex, oldIndex)) self.__host.sendCommand("hotbar.{} 1".format(newIndex + 1)) self.__host.sendCommand("hotbar.{} 0".format(newIndex + 1)) self.__logReports.append(LogUtils.EquipReport(inventoryItem)) return True return False
def __attackCleanup(self, mob): ''' Perform additional cleanup work and logging as a result of an agent having killed the given mob. ''' # Get any items that were immediately picked up itemsPickedUp, _ = self.inventory.sync() # Get any items that were dropped to the ground (register their IDs w/ Inventory class to preserve them) nearbyEntities = self.nearbyEntities() itemsDropped = [x for x in nearbyEntities if Items.All.isMember(x.type)] for item in itemsDropped: for i in range(0, item.quantity): Inventory.registerDropItem(item) # Create the log report for the attack self.__logReports.append(LogUtils.AttackReport(mob, True, itemsDropped, itemsPickedUp)) # Trigger a log report for new closest mobs of this mob's type for all agents allAgents = list(Agent.allAgents.values()) for agent in allAgents: if Mobs.All.isMember(mob.type): agent.closestMob() if Mobs.Peaceful.isMember(mob.type): agent.closestMob(Mobs.Peaceful) if Mobs.Hostile.isMember(mob.type): agent.closestMob(Mobs.Hostile) if Mobs.Food.isMember(mob.type): agent.closestMob(Mobs.Food)
def craft(self, itemType, recipe): ''' Craft an item of the given enumerated type using a list of RecipeItems. Returns true if successful, and false otherwise. Preconditions: - The agent has enough of each recipe item ''' # Check for override if self.__shouldPerformActionOverride(self.craft): return self.__actionOverride.function(*self.__actionOverride.args) # Preconditions hasAllItems = True for recipeItem in recipe: if self.inventory.amountOfItem(recipeItem) < recipeItem.quantity: hasAllItems = False break if not self.__checkPreconditions(hasAllItems): return False # Remove each recipe item from the inventory consumedItems = [] for recipeItem in recipe: for i in range(0, recipeItem.quantity): consumedItems.append(self.inventory.removeItem(recipeItem.type)) # Add the crafted item to the inventory craftedItem = self.inventory.addItem(itemType) # Action self.__host.sendCommand("craft {}".format(itemType.value)) time.sleep(0.5) self.__logReports.append(LogUtils.CraftReport(craftedItem, recipeItem)) return True
def attackMob(self, mob): ''' Direct this agent to attack a mob using the currently equipped item. Returns true if the agent successfully swung, false otherwise. Preconditions: - The given entity is a mob - The agent is looking at the mob - The agent is at the mob ''' # Check action override if self.__shouldPerformActionOverride(self.attackMob): return self.__actionOverride.function(*self.__actionOverride.args) # Preconditions if not self.__checkPreconditions( Mobs.All.isMember(mob.type), self.__isLookingAt(mob.position), self.__isAt(mob.position)): self.stopMoving() return False # Action oldMobsKilled = self.__mobsKilled() self.__startAttacking() self.stopMoving() time.sleep(0.7) newMobsKilled = self.__mobsKilled() if newMobsKilled > oldMobsKilled: self.__attackCleanup(mob) else: self.__logReports.append(LogUtils.AttackReport(mob, False, [], [])) return True
def __pickUpItem(self, item, previousInventoryAmt): ''' Internal lockdown action for continuously moving an agent towards an item until it has been picked up and shows up in the agent's inventory. Requires the previous amount of that item in the agent's inventory to be passed in as a parameter. ''' # Do not check for action override. Otherwise, we'd get stuck in an infinite loop! # Do not check any preconditions - we assume that if we locked down on this override that preconditions remain satisfied # Move to the position, slowing down as we approach self.__moveToPosition(item.position, 0, PICK_UP_ITEM_LOCKDOWN_DISTANCE, False) # Make sure we log that we picked up all kinds of items, regardless of what they are newInventoryItems, _ = self.inventory.sync() for item in newInventoryItems: self.__logReports.append(LogUtils.PickUpItemReport(item)) # Only report true when we picked up the target item newInventoryAmt = self.inventory.amountOfItem(item.type) if newInventoryAmt > previousInventoryAmt: # Avoid stopMoving() function since it checks for action override self.__stopTurning() self.__stopWalking() self.__stopAttacking() self.__actionOverride = None return True return False
def lookAt(self, entity): ''' Begin moving the agent's POV up/down and left/right to face the given entity. Returns true if the agent is facing the entity, false otherwise. Preconditions: None ''' # Check for override if self.__shouldPerformActionOverride(self.lookAt): return self.__actionOverride.function(*self.__actionOverride.args) # If entity is an agent, represent it as an entity if isinstance(entity, Agent): entity = Entity(entity.id, "agent", entity.__position(), 1) # Preconditions - None # Action pitchRate = self.__calculateTargetPitchRate(entity.position) yawRate = self.__calculateTargetYawRate(entity.position) if self.__isLookingAt(entity.position, pitchRate, yawRate): self.__stopTurning() if not Items.All.isMember(entity.type): # Items are a special case for which we do not log self.__logReports.append(LogUtils.LookAtReport(entity)) return True else: self.__startChangingPitch(pitchRate) self.__startChangingYaw(yawRate) return False
def closestItem(self, variant=Items.All): ''' Get the closest item on the ground to this agent. Optionally specify additional modifiers for filtering items by an enumerated type. Returns None if no item was found nearby to this agent. ''' # Check for override if self.__shouldPerformActionOverride(self.closestItem): self.__actionOverride.function(*self.__actionOverride.args) return None aPos = self.__position() nearbyEntities = self.nearbyEntities() if variant == Items.All: comparator = Items.All.isMember elif variant == Items.Food: comparator = Items.Food.isMember else: raise Exception("Closest item variant must be an enumerated type") closestDistance = 1000000.0 closestItem = None for entity in nearbyEntities: if comparator(entity.type): ePos = entity.position distance = MathUtils.distanceBetweenPoints(aPos, ePos) if distance < closestDistance: closestDistance = distance closestItem = entity self.__logReports.append(LogUtils.ClosestItemReport(variant, closestItem)) return closestItem
def moveTo(self, entity): ''' Begin moving the agent to the given entity. Returns true if the agent is at the entity, false otherwise. Preconditions: - The agent is looking at the entity ''' # Check for override if self.__shouldPerformActionOverride(self.moveTo): return self.__actionOverride.function(*self.__actionOverride.args) minTol = 0.0 maxTol = STRIKING_DISTANCE # If entity is an agent, represent it as an entity if isinstance(entity, Agent): entity = Entity(entity.id, "agent", entity.__position(), 1) minTol = 2.0 maxTol = GIVING_DISTANCE # Preconditions if not self.__checkPreconditions(self.__isLookingAt(entity.position)): self.stopMoving() return False # Items are a special case since they can be picked up. Once close, lock down on the pickUpItem action. if Items.All.isMember(entity.type): distanceToItem = MathUtils.distanceBetweenPointsXZ(self.__position(), entity.position) if distanceToItem <= PICK_UP_ITEM_LOCKDOWN_DISTANCE: currentInventoryAmt = self.inventory.amountOfItem(entity.type) self.__actionOverride = Agent.ActionOverride(self.__pickUpItem, [entity, currentInventoryAmt]) return self.__pickUpItem(entity, currentInventoryAmt) # Action if self.__moveToPosition(entity.position, minTol, maxTol): self.__stopWalking() self.__logReports.append(LogUtils.MoveToReport(entity)) return True else: return False
def giveItem(self, itemType, agent): ''' Give an item of the given enumerated type to another agent. Returns true if successful, false otherwise. Preconditions: - The agent has an item of the given type - The agent has that item currently equipped - The agent is looking at the agent to give the item to - The agent is at the agent to give the item to ''' # Check action override if self.__shouldPerformActionOverride(self.giveItem): return self.__actionOverride.function(*self.__actionOverride.args) # Stop moving before going any further... self.stopMoving() # Preconditions equippedItem = self.inventory.equippedItem() if not self.__checkPreconditions( equippedItem != None, equippedItem.type == itemType.value, self.__isLookingAt(agent.__position()), self.__isAt(agent.__position(), 2, GIVING_DISTANCE) ): return False # Record the exchange in each agent's inventory toGive = self.inventory.removeItem(itemType) agent.inventory.addItem(itemType, toGive.id) # Preserve the ID # Action self.__throwItem() time.sleep(2.8) self.__logReports.append(LogUtils.GiveItemReport(toGive, agent)) return True