diff --git a/data/plugins/entity/mob/walk-to/plugin.xml b/data/plugins/entity/mob/walk-to/plugin.xml new file mode 100644 index 00000000..676560e8 --- /dev/null +++ b/data/plugins/entity/mob/walk-to/plugin.xml @@ -0,0 +1,16 @@ + + + mob-walk-to + 0.1 + Mob path generation + Adds a mixin for making mobs walk to another entity. + + Gary Tierney + + + + + + mob-extension + + \ No newline at end of file diff --git a/data/plugins/entity/mob/walk-to/walk_to.rb b/data/plugins/entity/mob/walk-to/walk_to.rb new file mode 100644 index 00000000..6381172f --- /dev/null +++ b/data/plugins/entity/mob/walk-to/walk_to.rb @@ -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 \ No newline at end of file diff --git a/game/src/main/org/apollo/game/model/entity/Mob.java b/game/src/main/org/apollo/game/model/entity/Mob.java index 0c06a050..82cdba96 100644 --- a/game/src/main/org/apollo/game/model/entity/Mob.java +++ b/game/src/main/org/apollo/game/model/entity/Mob.java @@ -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. *

@@ -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)); } + } \ No newline at end of file diff --git a/game/src/main/org/apollo/game/model/entity/WalkingQueue.java b/game/src/main/org/apollo/game/model/entity/WalkingQueue.java index f2feeac7..7db2579d 100644 --- a/game/src/main/org/apollo/game/model/entity/WalkingQueue.java +++ b/game/src/main/org/apollo/game/model/entity/WalkingQueue.java @@ -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); } } }