Add a mob extension plugin for walking to entities

Adds a new mob extension plugin which creates a walk_to() method on
Mobs to allow walking to another entity (accounting for the size of the
entity) with an optional facing position.
This commit is contained in:
Gary Tierney
2017-01-01 08:17:21 +00:00
parent b047d0197a
commit baa12ca446
4 changed files with 128 additions and 3 deletions
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<plugin>
<id>mob-walk-to</id>
<version>0.1</version>
<name>Mob path generation</name>
<description>Adds a mixin for making mobs walk to another entity.</description>
<authors>
<author>Gary Tierney</author>
</authors>
<scripts>
<script>walk_to.rb</script>
</scripts>
<dependencies>
<dependency>mob-extension</dependency>
</dependencies>
</plugin>
@@ -0,0 +1,83 @@
java_import 'org.apollo.game.model.entity.path.AStarPathfindingAlgorithm'
java_import 'org.apollo.game.model.entity.path.EuclideanHeuristic'
java_import 'org.apollo.game.model.entity.path.SimplePathfindingAlgorithm'
java_import 'org.apollo.game.model.entity.obj.GameObject'
java_import 'org.apollo.game.model.entity.Mob'
java_import 'org.apollo.game.model.entity.Player'
java_import 'org.apollo.game.model.entity.EntityType'
java_import 'org.apollo.game.model.Direction'
##
# A pathfinder used for simple following (i.e.: An NPC attacking a player).
SIMPLE_PATH_FINDER = SimplePathfindingAlgorithm.new($world.collision_manager)
##
# A pathfinder used for precise following (i.e.: A player attacking another player).
FOLLOW_PATH_FINDER = AStarPathfindingAlgorithm.new($world.collision_manager, EuclideanHeuristic.new)
##
# The directions that we use as a random offset when not walking to the facing direction.
OFFSET_DIRECTIONS = Direction::NESW.to_a
module WalkToMobExtension
def walk_to(entity, front: false, behind: false)
if [front, behind].count { |option| option == true } > 1
fail 'Can only specify one of "front" or "behind"'
end
position = self.position
target_position = entity.position
target_distance = position.get_distance(target_position)
target_offset = walk_to_offset(entity)
target_offset_direction = OFFSET_DIRECTIONS.sample
target_facing_direction = walk_to_facing_direction(entity)
unless target_facing_direction.nil?
if front
target_offset_direction = target_facing_direction
elsif behind
target_offset_direction = target_facing_direction.opposite
end
end
target_offset_position = target_position.step(target_offset, target_offset_direction)
return if target_offset_position.eql?(position)
pathfinder = FOLLOW_PATH_FINDER
path = pathfinder.find(position, target_offset_position)
path.each { |tile| self.walking_queue.add_step(tile) }
end
end
MobExtension::register(WalkToMobExtension)
private
##
# Gets the number of tiles away from an entity's actual origin that we can
# walk to.
def walk_to_offset(entity)
case entity.entity_type
when EntityType::DYNAMIC_OBJECT, EntityType::STATIC_OBJECT
return max(entity.definition.width, entity.definition.length) + 1
when EntityType::NPC
return entity.definition.size + 1
when EntityType::PLAYER
return 1
else
fail "walk_to_offset called with invalid entity type: #{type.to_s}"
end
end
##
# Gets the direction that an entity is facing, so a mob can walk up infront of them.
def walk_to_facing_direction(entity)
case entity.entity_type
when EntityType::DYNAMIC_OBJECT, EntityType::STATIC_OBJECT
return Direction::WNES[entity.orientation]
when EntityType::NPC, EntityType::PLAYER
return entity.last_direction
else
fail "walk_to_offset called with invalid entity type: #{type.to_s}"
end
end
@@ -103,6 +103,11 @@ public abstract class Mob extends Entity {
*/
private Direction firstDirection = Direction.NONE;
/**
* The last facing direction of this mob.
*/
private Direction lastDirection = Direction.NORTH;
/**
* This mob's second movement direction.
*/
@@ -196,8 +201,8 @@ public abstract class Mob extends Entity {
*/
public final Direction[] getDirections() {
if (firstDirection != Direction.NONE) {
return secondDirection == Direction.NONE ? new Direction[]{ firstDirection }
: new Direction[]{ firstDirection, secondDirection };
return secondDirection == Direction.NONE ? new Direction[]{firstDirection}
: new Direction[]{firstDirection, secondDirection};
}
return Direction.EMPTY_DIRECTION_ARRAY;
@@ -268,6 +273,15 @@ public abstract class Mob extends Entity {
return inventory;
}
/**
* Gets the last facing direction of this mob.
*
* @return The last direction this mob was facing.
*/
public Direction getLastDirection() {
return lastDirection;
}
/**
* Gets this mob's local npc {@link List}.
*
@@ -425,6 +439,15 @@ public abstract class Mob extends Entity {
blockSet.add(SynchronizationBlock.createInteractingMobBlock(mob.getInteractionIndex()));
}
/**
* Set the last direction this mob was facing.
*
* @param lastDirection The direction to set.
*/
public void setLastDirection(Direction lastDirection) {
this.lastDirection = lastDirection;
}
/**
* Sets the {@link Position} of this mob.
* <p>
@@ -470,7 +493,7 @@ public abstract class Mob extends Entity {
* Gets the number of tiles this mob occupies.
*
* @return The number of tiles this mob occupies.
*/
*/
public int size() {
return definition.map(NpcDefinition::getSize).orElse(1);
}
@@ -548,4 +571,5 @@ public abstract class Mob extends Entity {
world.schedule(new SkillNormalizationTask(this));
}
}
@@ -146,6 +146,7 @@ public final class WalkingQueue {
} else {
previousPoints.add(next);
position = new Position(next.getX(), next.getY(), height);
mob.setLastDirection(firstDirection);
if (running) {
next = points.poll();
@@ -158,6 +159,7 @@ public final class WalkingQueue {
} else {
previousPoints.add(next);
position = new Position(next.getX(), next.getY(), height);
mob.setLastDirection(secondDirection);
}
}
}