mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-06 16:51:37 +00:00
Add support for player / npc following
Implements a new MobExtension plugin which adds 'follow', and 'chase' mixins that allow the mob to follow behind another mob, and chase them while keeping at a safe distance to fire projectiles. Also adds a new public method 'raycast' to CollisionManager, for drawing a line through the world using bresenham's line algorithm whille checking for any impenetrable objects.
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
|||||||
|
on :message, :walk do |player, msg|
|
||||||
|
player.reset_interacting_mob
|
||||||
|
end
|
||||||
|
|
||||||
|
on :message, :player_action do |player, msg|
|
||||||
|
## todo: need a better way of mapping option numbers to their purpose
|
||||||
|
player.follow($world.player_repository.get(msg.index)) if msg.option == 3
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# A <code>MobExtension</code> for making a <code>Mob</code> trail behind, or chase a given mob.
|
||||||
|
module FollowingMobExtension
|
||||||
|
##
|
||||||
|
# Follow a mob and trail behind them.
|
||||||
|
def follow(mob)
|
||||||
|
do_follow(self, mob, behind: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Chase a mob (with the intention of getting in front of them), also optionally
|
||||||
|
# stopping within a projectile distance when at a position where a projectile can
|
||||||
|
# reach the target.
|
||||||
|
def chase(mob, projectile_distance: nil)
|
||||||
|
do_follow(self, mob, front: true, projectile_distance: projectile_distance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MobExtension::register(FollowingMobExtension)
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def do_follow(source, mob, behind: false, front: false, projectile_distance: nil)
|
||||||
|
source.interacting_mob = mob
|
||||||
|
|
||||||
|
schedule 0, true do |task|
|
||||||
|
# stop the task unless we're still interacting with the other mob.
|
||||||
|
unless self.interacting_mob.eql? mob
|
||||||
|
task.stop
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
next unless source.walking_queue.size <= 1
|
||||||
|
|
||||||
|
distance = mob.position.get_distance(source.position)
|
||||||
|
|
||||||
|
unless projectile_distance.nil?
|
||||||
|
next if distance <= projectile_distance &&
|
||||||
|
$world.collision_manager.raycast(source.position, mob.position)
|
||||||
|
end
|
||||||
|
|
||||||
|
if distance > 15
|
||||||
|
reset_interacting_mob
|
||||||
|
end
|
||||||
|
|
||||||
|
walk_to(mob, behind: behind, front: front)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<plugin>
|
||||||
|
<id>mob-following</id>
|
||||||
|
<version>1</version>
|
||||||
|
<name>Following</name>
|
||||||
|
<description>Adds following for mobs.</description>
|
||||||
|
<authors>
|
||||||
|
<author>Steve Soltys</author>
|
||||||
|
</authors>
|
||||||
|
<scripts>
|
||||||
|
<script>following.rb</script>
|
||||||
|
</scripts>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>mob-walk-to</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.apollo.game.model.area.collision;
|
package org.apollo.game.model.area.collision;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import org.apollo.game.model.Direction;
|
import org.apollo.game.model.Direction;
|
||||||
import org.apollo.game.model.Position;
|
import org.apollo.game.model.Position;
|
||||||
import org.apollo.game.model.area.Region;
|
import org.apollo.game.model.area.Region;
|
||||||
@@ -140,6 +141,91 @@ public final class CollisionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Casts a ray into the world to check for impenetrable objects from the given {@code start} position to the
|
||||||
|
* {@code end} position using Bresenham's line algorithm.
|
||||||
|
*
|
||||||
|
* @param start The start position of the ray.
|
||||||
|
* @param end The end position of the ray.
|
||||||
|
* @return {@code true} if an impenetrable object was hit, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public boolean raycast(Position start, Position end) {
|
||||||
|
Preconditions.checkArgument(start.getHeight() == end.getHeight(), "Positions must be on the same height");
|
||||||
|
|
||||||
|
if (start.equals(end)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x0 = start.getX();
|
||||||
|
int x1 = end.getX();
|
||||||
|
int y0 = start.getY();
|
||||||
|
int y1 = start.getY();
|
||||||
|
|
||||||
|
boolean steep = false;
|
||||||
|
if (Math.abs(x0 - x1) < Math.abs(y0 - y1)) {
|
||||||
|
int tmp = y0;
|
||||||
|
x0 = y0;
|
||||||
|
y0 = tmp;
|
||||||
|
|
||||||
|
tmp = x1;
|
||||||
|
x1 = y1;
|
||||||
|
y1 = tmp;
|
||||||
|
steep = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x0 > x1) {
|
||||||
|
int tmp = x0;
|
||||||
|
x0 = y1;
|
||||||
|
y1 = tmp;
|
||||||
|
|
||||||
|
tmp = y0;
|
||||||
|
y0 = y1;
|
||||||
|
y1 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dx = x1 - x0;
|
||||||
|
int dy = y1 - y0;
|
||||||
|
|
||||||
|
float derror = Math.abs(dy / (float) dx);
|
||||||
|
float error = 0;
|
||||||
|
|
||||||
|
int y = y0, currX, currY, lastX = 0, lastY = 0;
|
||||||
|
boolean first = true;
|
||||||
|
|
||||||
|
for (int x = x0; x <= x1; x++) {
|
||||||
|
if (steep) {
|
||||||
|
currX = y;
|
||||||
|
currY = x;
|
||||||
|
} else {
|
||||||
|
currX = x;
|
||||||
|
currY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
error += derror;
|
||||||
|
if (error > 0.5) {
|
||||||
|
y += (y1 > y0 ? 1 : -1);
|
||||||
|
error -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction direction = Direction.fromDeltas(currX - lastX, currY - lastY);
|
||||||
|
Position lastPosition = new Position(lastX, lastY, start.getHeight());
|
||||||
|
|
||||||
|
if (!traversable(lastPosition, EntityType.PROJECTILE, direction)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastX = currX;
|
||||||
|
lastY = currY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a {@link CollisionUpdate} flag to a {@link CollisionMatrix}.
|
* Apply a {@link CollisionUpdate} flag to a {@link CollisionMatrix}.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user