Skip to content

Commit

Permalink
Allow Walk and Follow commands to accept non-NPC entities
Browse files Browse the repository at this point in the history
TA-DA! It's MAGIC!
Wanna do something fun?
/ex follow followers:<pl.location.find.entities[zombie].within[1000]>
  • Loading branch information
Morphan1 committed Dec 30, 2014
1 parent 0aea3f0 commit 9f51fde
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 132 deletions.
Expand Up @@ -1147,22 +1147,21 @@ public void registerCoreMembers() {

// <--[command]
// @Name Follow
// @Syntax follow (stop) (lead:<#.#>) (target:<entity>)
// @Syntax follow (followers:<entity>|...) (stop) (lead:<#.#>) (target:<entity>)
// @Required 0
// @Stable unstable
// @Short Causes the NPC to follow a target (Currently experiencing bugs with lead: )
// @Author aufdemrand
// @Group npc
// @Stable stable
// @Short Causes a list of entities to follow a target.
// @Author aufdemrand, Morphan1
// @Group entity
// @Description
// TODO: Document Command Details
// @Tags
// TODO: Document Command Details
// @Usage
// TODO: Document Command Details
// -->
if (Depends.citizens != null)
registerCoreMember(FollowCommand.class,
"FOLLOW", "follow (stop) (lead:<#.#>) (target:<entity>)", 0);
registerCoreMember(FollowCommand.class,
"FOLLOW", "follow (followers:<entity>|...) (stop) (lead:<#.#>) (target:<entity>)", 0);


// <--[command]
Expand Down Expand Up @@ -2786,12 +2785,12 @@ public void registerCoreMembers() {

// <--[command]
// @Name Walk
// @Syntax walk (<npc>|...) [<location>] (speed:<#.#>) (auto_range) (radius:<#.#>)
// @Syntax walk (<entity>|...) [<location>] (speed:<#.#>) (auto_range) (radius:<#.#>)
// @Required 1
// @Stable stable
// @Short Causes an NPC or list of NPCs to walk to another location.
// @Author aufdemrand
// @Group npc
// @Short Causes an entity or list of entities to walk to another location.
// @Author aufdemrand, Morphan1
// @Group entity
// @Description
// TODO: Document Command Details
// @Tags
Expand All @@ -2802,9 +2801,8 @@ public void registerCoreMembers() {
// @Usage
// TODO: Document Command Details
// -->
if (Depends.citizens != null)
registerCoreMember(WalkCommand.class,
"WALK, WALKTO", "walk (<npc>|...) [<location>] (speed:<#>) (auto_range) (radius:<#.#>)", 1);
registerCoreMember(WalkCommand.class,
"WALK, WALKTO", "walk (<entity>|...) [<location>] (speed:<#>) (auto_range) (radius:<#.#>)", 1);

// <--[command]
// @Name Weather
Expand Down
@@ -0,0 +1,107 @@
package net.aufdemrand.denizen.scripts.commands.entity;

import net.aufdemrand.denizen.BukkitScriptEntryData;
import net.aufdemrand.denizen.objects.*;
import net.aufdemrand.denizen.utilities.entity.EntityMovement;
import net.aufdemrand.denizencore.exceptions.CommandExecutionException;
import net.aufdemrand.denizencore.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.commands.AbstractCommand;
import net.aufdemrand.denizen.utilities.debugging.dB;

/**
* Instructs the NPC to follow a player.
*
* @author aufdemrand
*
*/
public class FollowCommand extends AbstractCommand {

@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {

// Parse Arguments
for (aH.Argument arg : aH.interpret(scriptEntry.getArguments())) {
if (!scriptEntry.hasObject("stop") &&
arg.matches("STOP"))
scriptEntry.addObject("stop", new Element(true));

else if (!scriptEntry.hasObject("lead") &&
arg.matchesPrimitive(aH.PrimitiveType.Double))
scriptEntry.addObject("lead", arg.asElement());

else if (!scriptEntry.hasObject("speed") &&
arg.matchesPrimitive(aH.PrimitiveType.Percentage))
scriptEntry.addObject("speed", arg.asElement());

else if (!scriptEntry.hasObject("target") &&
arg.matchesArgumentType(dEntity.class))
scriptEntry.addObject("target", arg.asType(dEntity.class));

else if (!scriptEntry.hasObject("entities") &&
arg.matchesPrefix("followers", "follower") &&
arg.matchesArgumentList(dEntity.class))
scriptEntry.addObject("entities", arg.asType(dList.class));

else
arg.reportUnhandled();
}
if (!scriptEntry.hasObject("target")) {
if (((BukkitScriptEntryData)scriptEntry.entryData).hasPlayer())
scriptEntry.addObject("target", ((BukkitScriptEntryData)scriptEntry.entryData).getPlayer().getDenizenEntity());
else
throw new InvalidArgumentsException("This command requires a linked player!");
}
if (!scriptEntry.hasObject("entities")) {
if (!((BukkitScriptEntryData)scriptEntry.entryData).hasNPC())
throw new InvalidArgumentsException("This command requires a linked NPC!");
else
scriptEntry.addObject("entities",
new dList(((BukkitScriptEntryData) scriptEntry.entryData).getNPC().identify()));
}

scriptEntry.defaultObject("stop", new Element(false));
}

@Override
public void execute(ScriptEntry scriptEntry) throws CommandExecutionException {
// Get objects
Element stop = scriptEntry.getElement("stop");
Element lead = scriptEntry.getElement("lead");
Element speed = scriptEntry.getElement("speed");
dList entities = scriptEntry.getdObject("entities");
dEntity target = scriptEntry.getdObject("target");

// Report to dB
dB.report(scriptEntry, getName(),
(((BukkitScriptEntryData)scriptEntry.entryData).getPlayer() != null ? ((BukkitScriptEntryData)scriptEntry.entryData).getPlayer().debug() : "")
+ (!stop.asBoolean() ? aH.debugObj("Action", "FOLLOW") : aH.debugObj("Action", "STOP"))
+ (lead != null ? lead.debug() : "")
+ entities.debug()
+ target.debug());

for (dEntity entity : entities.filter(dEntity.class)) {
if (entity.isNPC()) {
dNPC npc = entity.getDenizenNPC();
if (lead != null)
npc.getNavigator().getLocalParameters().distanceMargin(lead.asDouble());

if (speed != null)
npc.getNavigator().getLocalParameters().speedModifier(speed.asFloat());

if (stop.asBoolean())
npc.getNavigator().cancelNavigation();
else
npc.getNavigator().setTarget(target.getBukkitEntity(), false);
}
else {
if (stop.asBoolean())
EntityMovement.stopFollowing(entity.getBukkitEntity());
else
EntityMovement.follow(target.getBukkitEntity(), entity.getBukkitEntity(),
speed != null ? speed.asDouble() : 0.3, lead != null ? lead.asDouble(): 3);
}
}

}
}
@@ -1,14 +1,16 @@
package net.aufdemrand.denizen.scripts.commands.npc;
package net.aufdemrand.denizen.scripts.commands.entity;

import net.aufdemrand.denizen.BukkitScriptEntryData;
import net.aufdemrand.denizencore.exceptions.CommandExecutionException;
import net.aufdemrand.denizencore.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizen.objects.*;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.commands.AbstractCommand;
import net.aufdemrand.denizencore.scripts.commands.Holdable;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.depends.Depends;
import net.aufdemrand.denizen.utilities.entity.EntityMovement;
import net.aufdemrand.denizencore.exceptions.CommandExecutionException;
import net.aufdemrand.denizencore.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizencore.scripts.commands.Holdable;
import net.citizensnpcs.api.ai.event.NavigationCancelEvent;
import net.citizensnpcs.api.ai.event.NavigationCompleteEvent;
import net.citizensnpcs.api.ai.event.NavigationEvent;
Expand Down Expand Up @@ -56,9 +58,9 @@ else if (!scriptEntry.hasObject("radius")
&& arg.matchesPrefix("radius"))
scriptEntry.addObject("radius", arg.asElement());

else if (!scriptEntry.hasObject("npcs")
&& arg.matchesArgumentList(dNPC.class))
scriptEntry.addObject("npcs", arg.asType(dList.class).filter(dNPC.class));
else if (!scriptEntry.hasObject("entities")
&& arg.matchesArgumentList(dEntity.class))
scriptEntry.addObject("entities", arg.asType(dList.class).filter(dEntity.class));

else
arg.reportUnhandled();
Expand All @@ -70,13 +72,13 @@ else if (!scriptEntry.hasObject("npcs")
if (!scriptEntry.hasObject("location"))
throw new InvalidArgumentsException("Must specify a location!");

if (!scriptEntry.hasObject("npcs")) {
if (!scriptEntry.hasObject("entities")) {
if (((BukkitScriptEntryData)scriptEntry.entryData).getNPC() == null
|| !((BukkitScriptEntryData)scriptEntry.entryData).getNPC().isValid()
|| !((BukkitScriptEntryData)scriptEntry.entryData).getNPC().isSpawned())
throw new InvalidArgumentsException("Must have a valid spawned NPC attached.");
else
scriptEntry.addObject("npcs", Arrays.asList(((BukkitScriptEntryData)scriptEntry.entryData).getNPC()));
scriptEntry.addObject("entities", Arrays.asList(((BukkitScriptEntryData)scriptEntry.entryData).getNPC()));
}


Expand All @@ -92,7 +94,7 @@ public void execute(ScriptEntry scriptEntry) throws CommandExecutionException {
Element speed = scriptEntry.getElement("speed");
Element auto_range = scriptEntry.getElement("auto_range");
Element radius = scriptEntry.getElement("radius");
List<dNPC> npcs = (List<dNPC>) scriptEntry.getObject("npcs");
List<dEntity> entities = (List<dEntity>) scriptEntry.getObject("entities");


// Debug the execution
Expand All @@ -101,39 +103,48 @@ public void execute(ScriptEntry scriptEntry) throws CommandExecutionException {
+ (speed != null ? speed.debug() : "")
+ (auto_range != null ? auto_range.debug() : "")
+ (radius != null ? radius.debug(): "")
+ (aH.debugObj("npcs", npcs)));
+ (aH.debugObj("entities", entities)));

// Do the execution

for (dNPC npc: npcs) {
if (!npc.isSpawned()) {
dB.echoError(scriptEntry.getResidingQueue(), "NPC " + npc.identify() + " is not spawned!");
continue;
List<dNPC> npcs = new ArrayList<dNPC>();
for (dEntity entity : entities) {
if (entity.isNPC()) {
dNPC npc = entity.getDenizenNPC();
npcs.add(npc);
if (!npc.isSpawned()) {
dB.echoError(scriptEntry.getResidingQueue(), "NPC " + npc.identify() + " is not spawned!");
continue;
}
if (auto_range != null
&& auto_range == Element.TRUE) {
double distance = npc.getLocation().distance(loc);
if (npc.getNavigator().getLocalParameters().range() < distance + 10)
npc.getNavigator().getDefaultParameters().range((float) distance + 10);
// TODO: Should be using local params rather than default?
}

npc.getNavigator().setTarget(loc);

if (speed != null)
npc.getNavigator().getLocalParameters().speedModifier(speed.asFloat());

if (radius != null) {
NPCFlock flock = new RadiusNPCFlock(radius.asDouble());
Flocker flocker = new Flocker(npc.getCitizen(), flock, new SeparationBehavior(Flocker.LOW_INFLUENCE),
new CohesionBehavior(Flocker.LOW_INFLUENCE), new AlignmentBehavior(Flocker.HIGH_INFLUENCE));
npc.getNavigator().getLocalParameters().addRunCallback(flocker);
}
}
if (auto_range != null
&& auto_range == Element.TRUE) {
double distance = npc.getLocation().distance(loc);
if (npc.getNavigator().getLocalParameters().range() < distance + 10)
npc.getNavigator().getDefaultParameters().range((float) distance + 10);
// TODO: Should be using local params rather than default?
}

npc.getNavigator().setTarget(loc);

if (speed != null)
npc.getNavigator().getLocalParameters().speedModifier(speed.asFloat());

if (radius != null) {
NPCFlock flock = new RadiusNPCFlock(radius.asDouble());
Flocker flocker = new Flocker(npc.getCitizen(), flock, new SeparationBehavior(Flocker.LOW_INFLUENCE),
new CohesionBehavior(Flocker.LOW_INFLUENCE), new AlignmentBehavior(Flocker.HIGH_INFLUENCE));
npc.getNavigator().getLocalParameters().addRunCallback(flocker);
else {
EntityMovement.walkTo(entity.getBukkitEntity(), loc, speed != null ? speed.asDouble() : 0.3);
}
}

if (scriptEntry.shouldWaitFor()) {
held.add(scriptEntry);
scriptEntry.addObject("tally", new ArrayList<dNPC>(npcs));
scriptEntry.addObject("tally", npcs);
// TODO: make non-NPC entities waitable
}

}
Expand Down Expand Up @@ -187,7 +198,9 @@ public void checkHeld(NavigationEvent e) {

@Override
public void onEnable() {
DenizenAPI.getCurrentInstance().getServer().getPluginManager()
.registerEvents(this, DenizenAPI.getCurrentInstance());
if (Depends.citizens != null) {
DenizenAPI.getCurrentInstance().getServer().getPluginManager()
.registerEvents(this, DenizenAPI.getCurrentInstance());
}
}
}

This file was deleted.

0 comments on commit 9f51fde

Please sign in to comment.