package net.aufdemrand.denizen.objects;
import net.aufdemrand.denizen.flags.FlagManager;
import net.aufdemrand.denizen.npc.dNPCRegistry;
import net.aufdemrand.denizen.npc.examiners.PathBlockExaminer;
import net.aufdemrand.denizen.npc.traits.*;
import net.aufdemrand.denizen.scripts.commands.npc.EngageCommand;
import net.aufdemrand.denizen.scripts.containers.core.InteractScriptContainer;
import net.aufdemrand.denizen.scripts.containers.core.InteractScriptHelper;
import net.aufdemrand.denizen.scripts.triggers.AbstractTrigger;
import net.aufdemrand.denizen.tags.core.NPCTags;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizencore.objects.*;
import net.aufdemrand.denizencore.objects.properties.Property;
import net.aufdemrand.denizencore.objects.properties.PropertyParser;
import net.aufdemrand.denizencore.tags.Attribute;
import net.aufdemrand.denizencore.tags.TagContext;
import net.aufdemrand.denizencore.utilities.CoreUtilities;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.ai.Navigator;
import net.citizensnpcs.api.ai.TeleportStuckAction;
import net.citizensnpcs.api.astar.pathfinder.FlyingBlockExaminer;
import net.citizensnpcs.api.astar.pathfinder.MinecraftBlockExaminer;
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.trait.Equipment;
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.trait.Anchors;
import net.citizensnpcs.trait.LookClose;
import net.citizensnpcs.trait.Poses;
import net.citizensnpcs.trait.waypoint.Waypoint;
import net.citizensnpcs.trait.waypoint.WaypointProvider;
import net.citizensnpcs.trait.waypoint.Waypoints;
import net.citizensnpcs.util.Anchor;
import net.citizensnpcs.util.Pose;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class dNPC implements dObject, Adjustable, InventoryHolder {
public static dNPC mirrorCitizensNPC(NPC npc) {
if (dNPCRegistry._isRegistered(npc)) {
return dNPCRegistry.getDenizen(npc);
}
else {
return new dNPC(npc);
}
}
public static dNPC fromEntity(Entity entity) {
return mirrorCitizensNPC(CitizensAPI.getNPCRegistry().getNPC(entity));
}
public static dNPC valueOf(String string) {
return valueOf(string, null);
}
@Fetchable("n")
public static dNPC valueOf(String string, TagContext context) {
if (string == null) {
return null;
}
////////
// Match NPC id
string = string.toUpperCase().replace("N@", "");
NPC npc;
if (aH.matchesInteger(string)) {
int id = aH.getIntegerFrom(string);
if (dNPCRegistry._isRegistered(id)) {
return dNPCRegistry.getDenizen(id);
}
npc = CitizensAPI.getNPCRegistry().getById(id);
if (npc != null) {
return new dNPC(npc);
}
}
////////
// Match NPC name
else {
for (NPC test : CitizensAPI.getNPCRegistry()) {
if (test.getName().equalsIgnoreCase(string)) {
return new dNPC(test);
}
}
}
return null;
}
public static boolean matches(String string) {
// If using object notation, assume it's valid
if (CoreUtilities.toLowerCase(string).startsWith("n@")) {
return true;
}
// Otherwise, let's do checks
string = string.toUpperCase().replace("N@", "");
NPC npc;
if (aH.matchesInteger(string)) {
npc = CitizensAPI.getNPCRegistry().getById(aH.getIntegerFrom(string));
if (npc != null) {
return true;
}
}
else {
for (NPC test : CitizensAPI.getNPCRegistry()) {
if (test.getName().equalsIgnoreCase(string)) {
return true;
}
}
}
return false;
}
public boolean isValid() {
return getCitizen() != null;
}
private int npcid = -1;
private final org.bukkit.Location locationCache = new org.bukkit.Location(null, 0, 0, 0);
public dNPC(NPC citizensNPC) {
if (citizensNPC != null) {
this.npcid = citizensNPC.getId();
}
if (npcid >= 0 && !dNPCRegistry._isRegistered(citizensNPC)) {
dNPCRegistry._registerNPC(this);
}
}
public NPC getCitizen() {
NPC npc = CitizensAPI.getNPCRegistry().getById(npcid);
if (npc == null) {
//dB.echoError(new RuntimeException("StackTraceOutput"));
//dB.log("Uh oh! Denizen has encountered a NPE while trying to fetch an NPC. " +
// "Has this NPC been removed?");
}
return npc;
}
public Entity getEntity() {
try {
return getCitizen().getEntity();
}
catch (NullPointerException e) {
dB.log("Uh oh! Denizen has encountered a NPE while trying to fetch an NPC entity. " +
"Has this NPC been removed?");
return null;
}
}
public LivingEntity getLivingEntity() {
try {
if (getCitizen().getEntity() instanceof LivingEntity) {
return (LivingEntity) getCitizen().getEntity();
}
else {
dB.log("Uh oh! Tried to get the living entity of a non-living NPC!");
return null;
}
}
catch (NullPointerException e) {
dB.log("Uh oh! Denizen has encountered a NPE while trying to fetch an NPC livingEntity. " +
"Has this NPC been removed?");
return null;
}
}
public dEntity getDenizenEntity() {
try {
return new dEntity(getCitizen().getEntity());
}
catch (NullPointerException e) {
dB.log("Uh oh! Denizen has encountered a NPE while trying to fetch an NPC dEntity. " +
"Has this NPC been removed?");
return null;
}
}
@Override
public Inventory getInventory() {
return dNPCRegistry.getInventory(getCitizen());
}
public dInventory getDenizenInventory() {
return new dInventory(this);
}
public EntityType getEntityType() {
return getCitizen().getEntity().getType();
}
public Navigator getNavigator() {
return getCitizen().getNavigator();
}
public int getId() {
return npcid;
}
public String getName() {
return getCitizen().getName();
}
public InteractScriptContainer getInteractScript(dPlayer player, Class<? extends AbstractTrigger> triggerType) {
return InteractScriptHelper.getInteractScript(this, player, triggerType);
}
public InteractScriptContainer getInteractScriptQuietly(dPlayer player, Class<? extends AbstractTrigger> triggerType) {
boolean db = dB.showDebug;
dB.showDebug = false;
InteractScriptContainer script = InteractScriptHelper.getInteractScript(this, player, triggerType);
dB.showDebug = db;
return script;
}
public void destroy() {
getCitizen().destroy();
}
public dLocation getLocation() {
if (isSpawned()) {
return new dLocation(getEntity().getLocation());
}
else {
return new dLocation(getCitizen().getStoredLocation());
}
}
public dLocation getEyeLocation() {
if (isSpawned() && getCitizen().getEntity() instanceof LivingEntity) {
return new dLocation(((LivingEntity) getCitizen().getEntity()).getEyeLocation());
}
else if (isSpawned()) {
return new dLocation(getEntity().getLocation());
}
else {
return new dLocation(getCitizen().getStoredLocation());
}
}
public World getWorld() {
if (isSpawned()) {
return getEntity().getWorld();
}
else {
return null;
}
}
@Override
public String toString() {
return getCitizen().getName() + '/' + getCitizen().getId();
}
public boolean isEngaged() {
return EngageCommand.getEngaged(getCitizen());
}
public boolean isSpawned() {
NPC npc = CitizensAPI.getNPCRegistry().getById(npcid);
return npc != null && npc.isSpawned();
}
public String getOwner() {
if (getCitizen().getTrait(Owner.class).getOwnerId() == null) {
return getCitizen().getTrait(Owner.class).getOwner();
}
return getCitizen().getTrait(Owner.class).getOwnerId().toString();
}
public AssignmentTrait getAssignmentTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(AssignmentTrait.class)) {
npc.addTrait(AssignmentTrait.class);
}
return npc.getTrait(AssignmentTrait.class);
}
public Equipment getEquipmentTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(Equipment.class)) {
npc.addTrait(Equipment.class);
}
return npc.getTrait(Equipment.class);
}
public NicknameTrait getNicknameTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(NicknameTrait.class)) {
npc.addTrait(NicknameTrait.class);
}
return npc.getTrait(NicknameTrait.class);
}
public FishingTrait getFishingTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(FishingTrait.class)) {
npc.addTrait(FishingTrait.class);
}
return npc.getTrait(FishingTrait.class);
}
public HealthTrait getHealthTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(HealthTrait.class)) {
npc.addTrait(HealthTrait.class);
}
return npc.getTrait(HealthTrait.class);
}
public net.citizensnpcs.api.trait.trait.Inventory getInventoryTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(net.citizensnpcs.api.trait.trait.Inventory.class)) {
npc.addTrait(net.citizensnpcs.api.trait.trait.Inventory.class);
}
return npc.getTrait(net.citizensnpcs.api.trait.trait.Inventory.class);
}
public PushableTrait getPushableTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(PushableTrait.class)) {
npc.addTrait(PushableTrait.class);
}
return npc.getTrait(PushableTrait.class);
}
public LookClose getLookCloseTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(LookClose.class)) {
npc.addTrait(LookClose.class);
}
return npc.getTrait(LookClose.class);
}
public TriggerTrait getTriggerTrait() {
NPC npc = getCitizen();
if (!npc.hasTrait(TriggerTrait.class)) {
npc.addTrait(TriggerTrait.class);
}
return npc.getTrait(TriggerTrait.class);
}
public String action(String actionName, dPlayer player, Map<String, dObject> context) {
if (getCitizen() != null) {
if (getCitizen().hasTrait(AssignmentTrait.class))
// Return the result from the ActionHandler
{
return DenizenAPI.getCurrentInstance().getNPCRegistry()
.getActionHandler().doAction(
actionName,
this,
player,
getAssignmentTrait().getAssignment(),
context);
}
}
return "none";
}
public String action(String actionName, dPlayer player) {
return action(actionName, player, null);
}
private String prefix = "npc";
@Override
public String getPrefix() {
return prefix;
}
@Override
public String debug() {
return (prefix + "='<A>" + identify() + "<G>' ");
}
@Override
public boolean isUnique() {
return true;
}
@Override
public String getObjectType() {
return "NPC";
}
@Override
public String identify() {
return "n@" + npcid;
}
@Override
public String identifySimple() {
return identify();
}
@Override
public dNPC setPrefix(String prefix) {
return this;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof dNPC)) {
return false;
}
return getId() == ((dNPC) o).getId();
}
@Override
public int hashCode() {
return getId();
}
@Override
public String getAttribute(Attribute attribute) {
if (attribute == null) {
return null;
}
// Defined in dEntity
if (attribute.startsWith("is_npc")) {
return Element.TRUE.getAttribute(attribute.fulfill(1));
}
// Defined in dEntity
if (attribute.startsWith("location") && !isSpawned()) {
return getLocation().getAttribute(attribute.fulfill(1));
}
// Defined in dEntity
if (attribute.startsWith("eye_location")) {
return getEyeLocation().getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.has_nickname>
// @returns Element(Boolean)
// @description
// Returns true if the NPC has a nickname.
// -->
if (attribute.startsWith("has_nickname")) {
NPC citizen = getCitizen();
return new Element(citizen.hasTrait(NicknameTrait.class) && citizen.getTrait(NicknameTrait.class).hasNickname())
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.name.nickname>
// @returns Element
// @description
// Returns the NPC's display name.
// -->
if (attribute.startsWith("name.nickname")) {
return new Element(getCitizen().hasTrait(NicknameTrait.class) ? getCitizen().getTrait(NicknameTrait.class)
.getNickname() : getName()).getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.name>
// @returns Element
// @description
// Returns the name of the NPC.
// -->
if (attribute.startsWith("name")) {
return new Element(getName())
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.list_traits>
// @returns dList
// @description
// Returns a list of all of the NPC's traits.
// -->
if (attribute.startsWith("list_traits")) {
List<String> list = new ArrayList<String>();
for (Trait trait : getCitizen().getTraits()) {
list.add(trait.getName());
}
return new dList(list).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.has_trait[<trait>]>
// @returns Element(Boolean)
// @description
// Returns whether the NPC has a specified trait.
// -->
if (attribute.startsWith("has_trait")) {
if (attribute.hasContext(1)) {
Class<? extends Trait> trait = CitizensAPI.getTraitFactory().getTraitClass(attribute.getContext(1));
if (trait != null) {
return new Element(getCitizen().hasTrait(trait))
.getAttribute(attribute.fulfill(1));
}
}
}
// <--[tag]
// @attribute <n@npc.pushable>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is pushable.
// -->
if (attribute.startsWith("pushable") || attribute.startsWith("is_pushable")) {
return new Element(getPushableTrait().isPushable()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.has_trigger[<trigger>]>
// @returns Element(Boolean)
// @description
// Returns whether the NPC has a specified trigger.
// -->
if (attribute.startsWith("has_trigger")
&& attribute.hasContext(1)) {
if (!getCitizen().hasTrait(TriggerTrait.class)) {
return Element.FALSE.getAttribute(attribute.fulfill(1));
}
TriggerTrait trait = getCitizen().getTrait(TriggerTrait.class);
return new Element(trait.hasTrigger(attribute.getContext(1)))
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.anchor.list>
// @returns dList
// @description
// Returns a list of anchor names currently assigned to the NPC.
// -->
if (attribute.startsWith("anchor.list")
|| attribute.startsWith("anchors.list")) {
List<String> list = new ArrayList<String>();
for (Anchor anchor : getCitizen().getTrait(Anchors.class).getAnchors()) {
list.add(anchor.getName());
}
return new dList(list).getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.has_anchors>
// @returns Element(Boolean)
// @description
// Returns whether the NPC has anchors assigned.
// -->
if (attribute.startsWith("has_anchors")) {
return (new Element(getCitizen().getTrait(Anchors.class).getAnchors().size() > 0))
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.anchor[<name>]>
// @returns dLocation
// @description
// Returns the location associated with the specified anchor, or null if it doesn't exist.
// -->
if (attribute.startsWith("anchor")) {
if (attribute.hasContext(1)
&& getCitizen().getTrait(Anchors.class).getAnchor(attribute.getContext(1)) != null) {
return new dLocation(getCitizen().getTrait(Anchors.class)
.getAnchor(attribute.getContext(1)).getLocation())
.getAttribute(attribute.fulfill(1));
}
}
// <--[tag]
// @attribute <n@npc.has_flag[<flag_name>]>
// @returns Element(Boolean)
// @description
// Returns true if the NPC has the specified flag, otherwise returns false.
// -->
if (attribute.startsWith("has_flag")) {
String flag_name;
if (attribute.hasContext(1)) {
flag_name = attribute.getContext(1);
}
else {
return null;
}
return new Element(FlagManager.npcHasFlag(this, flag_name)).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.flag[<flag_name>]>
// @returns Flag dList
// @description
// Returns the specified flag from the NPC.
// -->
if (attribute.startsWith("flag")) {
String flag_name;
if (attribute.hasContext(1)) {
flag_name = attribute.getContext(1);
}
else {
return null;
}
if (attribute.getAttribute(2).equalsIgnoreCase("is_expired")
|| attribute.startsWith("isexpired")) {
return new Element(!FlagManager.npcHasFlag(this, flag_name))
.getAttribute(attribute.fulfill(2));
}
if (attribute.getAttribute(2).equalsIgnoreCase("size") && !FlagManager.npcHasFlag(this, flag_name)) {
return new Element(0).getAttribute(attribute.fulfill(2));
}
if (FlagManager.npcHasFlag(this, flag_name)) {
FlagManager.Flag flag = DenizenAPI.getCurrentInstance().flagManager()
.getNPCFlag(getId(), flag_name);
return new dList(flag.toString(), true, flag.values())
.getAttribute(attribute.fulfill(1));
}
return new Element(identify()).getAttribute(attribute);
}
// <--[tag]
// @attribute <n@npc.list_flags[(regex:)<search>]>
// @returns dList
// @description
// Returns a list of an NPC's flag names, with an optional search for
// names containing a certain pattern.
// -->
if (attribute.startsWith("list_flags")) {
dList allFlags = new dList(DenizenAPI.getCurrentInstance().flagManager().listNPCFlags(getId()));
dList searchFlags = null;
if (!allFlags.isEmpty() && attribute.hasContext(1)) {
searchFlags = new dList();
String search = attribute.getContext(1);
if (search.startsWith("regex:")) {
try {
Pattern pattern = Pattern.compile(search.substring(6), Pattern.CASE_INSENSITIVE);
for (String flag : allFlags) {
if (pattern.matcher(flag).matches()) {
searchFlags.add(flag);
}
}
}
catch (Exception e) {
dB.echoError(e);
}
}
else {
search = CoreUtilities.toLowerCase(search);
for (String flag : allFlags) {
if (CoreUtilities.toLowerCase(flag).contains(search)) {
searchFlags.add(flag);
}
}
}
}
return searchFlags == null ? allFlags.getAttribute(attribute.fulfill(1))
: searchFlags.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.constant[<constant_name>]>
// @returns Element
// @description
// Returns the specified constant from the NPC.
// -->
if (attribute.startsWith("constant")) {
if (attribute.hasContext(1)) {
if (getCitizen().hasTrait(ConstantsTrait.class)
&& getCitizen().getTrait(ConstantsTrait.class).getConstant(attribute.getContext(1)) != null) {
return new Element(getCitizen().getTrait(ConstantsTrait.class)
.getConstant(attribute.getContext(1))).getAttribute(attribute.fulfill(1));
}
else {
return null;
}
}
}
// <--[tag]
// @attribute <n@npc.has_pose[<name>]>
// @returns Element(Boolean)
// @description
// Returns true if the NPC has the specified pose, otherwise returns false.
// -->
if (attribute.startsWith("has_pose")) {
if (attribute.hasContext(1)) {
return new Element(getCitizen().getTrait(Poses.class).hasPose(attribute.getContext(1)))
.getAttribute(attribute.fulfill(1));
}
else {
return null;
}
}
// <--[tag]
// @attribute <n@npc.pose[<name>]>
// @returns dLocation
// @description
// Returns the pose as a dLocation with x, y, and z set to 0, and the world set to the first
// possible available world Bukkit knows about.
// -->
if (attribute.startsWith("pose") || attribute.startsWith("get_pose")) {
if (attribute.hasContext(1)) {
Pose pose = getCitizen().getTrait(Poses.class).getPose(attribute.getContext(1));
return new dLocation(org.bukkit.Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch())
.getAttribute(attribute.fulfill(1));
}
else {
return null;
}
}
// <--[tag]
// @attribute <n@npc.is_engaged>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is currently engaged.
// See <@link command engage>
// -->
if (attribute.startsWith("engaged") || attribute.startsWith("is_engaged")) {
return new Element(isEngaged()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.invulnerable>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is currently invulnerable.
// See <@link command vulnerable>
// -->
if (attribute.startsWith("invulnerable") || attribute.startsWith("vulnerable")) {
return new Element(getCitizen().data().get(NPC.DEFAULT_PROTECTED_METADATA, true)).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.id>
// @returns Element(Number)
// @description
// Returns the NPC's ID number.
// -->
if (attribute.startsWith("id")) {
return new Element(getId()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.owner>
// @returns dPlayer/Element
// @description
// Returns the owner of the NPC as a dPlayer if it's a player, otherwise as just the name.
// -->
if (attribute.startsWith("owner")) {
String owner = getOwner();
dPlayer player = null;
if (!owner.equalsIgnoreCase("server")) {
player = dPlayer.valueOfInternal(owner, false);
}
if (player != null) {
return player.getAttribute(attribute.fulfill(1));
}
else {
return new Element(owner).getAttribute(attribute.fulfill(1));
}
}
// <--[tag]
// @attribute <n@npc.has_skin>
// @returns Element
// @description
// Returns whether the NPC has a custom skinskin.
// -->
if (attribute.startsWith("has_skin")) {
return new Element(getCitizen().data().has(NPC.PLAYER_SKIN_UUID_METADATA)).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.skin_blob>
// @returns Element
// @description
// Returns the NPC's custom skin blob, if any.
// -->
if (attribute.startsWith("skin_blob")) {
if (getCitizen().data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA)) {
String tex = getCitizen().data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA).toString();
String sign = "";
if (getCitizen().data().has(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA)) {
sign = ";" + getCitizen().data().get(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA).toString();
}
return new Element(tex + sign).getAttribute(attribute.fulfill(1));
}
}
// <--[tag]
// @attribute <n@npc.skin>
// @returns Element
// @description
// Returns the NPC's custom skin, if any.
// -->
if (attribute.startsWith("skin")) {
if (getCitizen().data().has(NPC.PLAYER_SKIN_UUID_METADATA)) {
return new Element(getCitizen().data().get(NPC.PLAYER_SKIN_UUID_METADATA).toString()).getAttribute(attribute.fulfill(1));
}
}
// <--[tag]
// @attribute <n@npc.inventory>
// @returns dInventory
// @description
// Returns the dInventory of the NPC.
// -->
if (attribute.startsWith("inventory")) {
return getDenizenInventory().getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.is_spawned>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is spawned.
// -->
if (attribute.startsWith("is_spawned")) {
return new Element(isSpawned()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.is_protected>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is protected.
// -->
if (attribute.startsWith("is_protected")) {
return new Element(getCitizen().isProtected()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.lookclose>
// @returns Element(Boolean)
// @description
// Returns the NPC's "lookclose" value.
// -->
if (attribute.startsWith("lookclose")) {
NPC citizen = getCitizen();
if (citizen.hasTrait(LookClose.class)) {
// There is no method to check if the NPC has LookClose enabled...
// LookClose.toString() returns "LookClose{" + enabled + "}"
String lookclose = citizen.getTrait(LookClose.class).toString();
lookclose = lookclose.substring(10, lookclose.length() - 1);
return new Element(Boolean.valueOf(lookclose)).getAttribute(attribute.fulfill(1));
}
return Element.FALSE.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.location.previous_location>
// @returns dLocation
// @description
// Returns the NPC's previous navigated location.
// -->
if (attribute.startsWith("location.previous_location")) {
return (NPCTags.previousLocations.containsKey(getId())
? NPCTags.previousLocations.get(getId()).getAttribute(attribute.fulfill(2))
: null);
}
// <--[tag]
// @attribute <n@npc.teleport_on_stuck>
// @returns dLocation
// @mechanism dNPC.teleport_on_stuck
// @description
// Returns whether the NPC teleports when it is stuck.
// -->
if (attribute.startsWith("teleport_on_stuck")) {
return new Element(getNavigator().getDefaultParameters().stuckAction() == TeleportStuckAction.INSTANCE)
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.has_script>
// @returns Element(Boolean)
// @description
// Returns true if the NPC has an assignment script.
// -->
if (attribute.startsWith("has_script")) {
NPC citizen = getCitizen();
return new Element(citizen.hasTrait(AssignmentTrait.class) && citizen.getTrait(AssignmentTrait.class).hasAssignment())
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <n@npc.script>
// @returns dScript
// @description
// Returns the NPC's assigned script.
// -->
if (attribute.startsWith("script")) {
NPC citizen = getCitizen();
if (!citizen.hasTrait(AssignmentTrait.class) || !citizen.getTrait(AssignmentTrait.class).hasAssignment()) {
return null;
}
else {
return new dScript(citizen.getTrait(AssignmentTrait.class).getAssignment().getName())
.getAttribute(attribute.fulfill(1));
}
}
// <--[tag]
// @attribute <n@npc.navigator.is_navigating>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is currently navigating.
// -->
if (attribute.startsWith("navigator.is_navigating")) {
return new Element(getNavigator().isNavigating()).getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.speed>
// @returns Element(Number)
// @description
// Returns the current speed of the NPC.
// -->
if (attribute.startsWith("navigator.speed")) {
return new Element(getNavigator().getLocalParameters().speed())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.range>
// @returns Element(Number)
// @description
// Returns the maximum pathfinding range.
// -->
if (attribute.startsWith("navigator.range")) {
return new Element(getNavigator().getLocalParameters().range())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.attack_range>
// @returns Element(Number)
// @description
// Returns the maximum attack range.
// -->
if (attribute.startsWith("navigator.attack_range")) {
return new Element(getNavigator().getLocalParameters().attackRange())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.attack_strategy>
// @returns Element
// @description
// Returns the NPC's attack strategy.
// -->
if (attribute.startsWith("navigator.attack_strategy")) {
return new Element(getNavigator().getLocalParameters().attackStrategy().toString())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.speed_modifier>
// @returns Element(Number)
// @description
// Returns the NPC movement speed modifier.
// -->
if (attribute.startsWith("navigator.speed_modifier")) {
return new Element(getNavigator().getLocalParameters().speedModifier())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.base_speed>
// @returns Element(Number)
// @description
// Returns the base navigation speed.
// -->
if (attribute.startsWith("navigator.base_speed")) {
return new Element(getNavigator().getLocalParameters().baseSpeed())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.avoid_water>
// @returns Element(Boolean)
// @description
// Returns whether the NPC will avoid water.
// -->
if (attribute.startsWith("navigator.avoid_water")) {
return new Element(getNavigator().getLocalParameters().avoidWater())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.target_location>
// @returns dLocation
// @description
// Returns the location the NPC is curently navigating towards.
// -->
if (attribute.startsWith("navigator.target_location")) {
return (getNavigator().getTargetAsLocation() != null
? new dLocation(getNavigator().getTargetAsLocation()).getAttribute(attribute.fulfill(2))
: null);
}
// <--[tag]
// @attribute <n@npc.navigator.is_fighting>
// @returns Element(Boolean)
// @description
// Returns whether the NPC is in combat.
// -->
if (attribute.startsWith("navigator.is_fighting")) {
return new Element(getNavigator().getEntityTarget() != null && getNavigator().getEntityTarget().isAggressive())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.target_type>
// @returns Element
// @description
// Returns the entity type of the target.
// -->
if (attribute.startsWith("navigator.target_type"))
// TODO: IMPROVE
{
return new Element(getNavigator().getTargetType() == null ? "null"
: getNavigator().getTargetType().toString())
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <n@npc.navigator.target_entity>
// @returns dEntity
// @description
// Returns the entity being targeted.
// -->
if (attribute.startsWith("navigator.target_entity")) {
return (getNavigator().getEntityTarget() != null && getNavigator().getEntityTarget().getTarget() != null
? new dEntity(getNavigator().getEntityTarget().getTarget()).getAttribute(attribute.fulfill(2))
: null);
}
// <--[tag]
// @attribute <n@npc.type>
// @returns Element
// @description
// Always returns 'NPC' for dNPC objects. All objects fetchable by the Object Fetcher will return the
// type of object that is fulfilling this attribute.
// -->
if (attribute.startsWith("type")) {
return new Element("NPC").getAttribute(attribute.fulfill(1));
}
// Iterate through this object's properties' attributes
for (Property property : PropertyParser.getProperties(this)) {
String returned = property.getAttribute(attribute);
if (returned != null) {
return returned;
}
}
return (getEntity() != null
? new dEntity(this).getAttribute(attribute)
: new Element(identify()).getAttribute(attribute));
}
public void applyProperty(Mechanism mechanism) {
dB.echoError("Cannot apply properties to an NPC!");
}
@Override
public void adjust(Mechanism mechanism) {
Element value = mechanism.getValue();
// TODO: For all the mechanism tags, add the @Mechanism link!
// <--[mechanism]
// @object dNPC
// @name set_assignment
// @input dScript
// @description
// Sets the NPC's assignment script.
// @tags
// <n@npc.script>
// -->
if (mechanism.matches("set_assignment") && mechanism.requireObject(dScript.class)) {
getAssignmentTrait().setAssignment(value.asType(dScript.class).getName(), null);
}
// <--[mechanism]
// @object dNPC
// @name remove_assignment
// @input none
// @description
// Removes the NPC's assigment script.
// @tags
// <n@npc.has_script>
// -->
if (mechanism.matches("remove_assignment")) {
getAssignmentTrait().removeAssignment(null);
}
// <--[mechanism]
// @object dNPC
// @name set_nickname
// @input Element
// @description
// Sets the NPC's nickname.
// @tags
// <n@npc.name.nickname>
// -->
if (mechanism.matches("set_nickname")) {
getNicknameTrait().setNickname(value.asString());
}
// <--[mechanism]
// @object dNPC
// @name remove_nickname
// @input none
// @description
// Removes the NPC's nickname.
// @tags
// <n@npc.has_nickname>
// -->
if (mechanism.matches("remove_nickname")) {
getNicknameTrait().removeNickname();
}
// <--[mechanism]
// @object dNPC
// @name set_entity_type
// @input dEntity
// @description
// Sets the NPC's entity type.
// @tags
// <n@npc.entity_type>
// -->
if (mechanism.matches("set_entity_type") && mechanism.requireObject(dEntity.class)) {
getCitizen().setBukkitEntityType(value.asType(dEntity.class).getBukkitEntityType());
}
// <--[mechanism]
// @object dNPC
// @name name
// @input Element
// @description
// Sets the name of the NPC.
// @tags
// <n@npc.name>
// -->
if (mechanism.matches("name") || mechanism.matches("set_name")) {
getCitizen().setName(value.asString().length() > 64 ? value.asString().substring(0, 64) : value.asString());
}
// <--[mechanism]
// @object dNPC
// @name owner
// @input Element
// @description
// Sets the owner of the NPC.
// @tags
// <n@npc.owner>
// -->
if (mechanism.matches("owner")) {
getCitizen().getTrait(Owner.class).setOwner(value.asString());
}
// <--[mechanism]
// @object dNPC
// @name skin_blob
// @input Element
// @description
// Sets the skin blob of an NPC.
// @tags
// <n@npc.skin>
// -->
if (mechanism.matches("skin_blob")) {
if (!mechanism.hasValue()) {
getCitizen().data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA);
getCitizen().data().remove(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA);
}
else {
String[] dat = mechanism.getValue().asString().split(";");
getCitizen().data().setPersistent(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA, dat[0]);
getCitizen().data().setPersistent(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA, dat.length > 0 ? dat[1] : null);
}
if (getCitizen().isSpawned()) {
getCitizen().despawn(DespawnReason.PENDING_RESPAWN);
getCitizen().spawn(getCitizen().getStoredLocation());
}
}
// <--[mechanism]
// @object dNPC
// @name skin
// @input Element
// @description
// Sets the skin of an NPC.
// @tags
// <n@npc.skin>
// -->
if (mechanism.matches("skin")) {
if (!mechanism.hasValue()) {
getCitizen().data().remove(NPC.PLAYER_SKIN_UUID_METADATA);
}
else {
getCitizen().data().setPersistent(NPC.PLAYER_SKIN_UUID_METADATA, mechanism.getValue().asString());
}
if (getCitizen().isSpawned()) {
getCitizen().despawn(DespawnReason.PENDING_RESPAWN);
getCitizen().spawn(getCitizen().getStoredLocation());
}
}
// <--[mechanism]
// @object dNPC
// @name item_type
// @input dItem
// @description
// Sets the item type of the item.
// @tags
// None
// -->
if (mechanism.matches("item_type") && mechanism.requireObject(dItem.class)) {
dItem item = mechanism.getValue().asType(dItem.class);
Material mat = item.getMaterial().getMaterial();
int data = item.getMaterial().getData((byte) 0);
switch (getEntity().getType()) {
case DROPPED_ITEM:
((org.bukkit.entity.Item) getEntity()).getItemStack().setType(mat);
//((ItemController.ItemNPC) getEntity()).setType(mat, data);
break;
case ITEM_FRAME:
((ItemFrame) getEntity()).getItem().setType(mat);
//((ItemFrameController.ItemFrameNPC) getEntity()).setType(mat, data);
break;
case FALLING_BLOCK:
//((FallingBlockController.FallingBlockNPC) getEntity()).setType(mat, data);
break;
default:
dB.echoError("NPC is the not an item type!");
break;
}
if (getCitizen().isSpawned()) {
getCitizen().despawn();
getCitizen().spawn(getCitizen().getStoredLocation());
}
}
// <--[mechanism]
// @object dNPC
// @name spawn
// @input dLocation
// @description
// Spawns the NPC at a location. If no location is specified, the NPC will spawn
// at its last known location.
// @tags
// <n@npc.is_spawned>
// -->
if (mechanism.matches("spawn")) {
if (mechanism.requireObject("Invalid dLocation specified. Assuming last known NPC location.", dLocation.class)) {
getCitizen().spawn(value.asType(dLocation.class));
}
else {
getCitizen().spawn(getCitizen().getStoredLocation());
}
}
// <--[mechanism]
// @object dNPC
// @name range
// @input Element(Decimal)
// @description
// Sets the maximum movement distance of the NPC.
// @tags
// <n@npc.navigator.range>
// -->
if (mechanism.matches("range") && mechanism.requireFloat()) {
getCitizen().getNavigator().getDefaultParameters().range(mechanism.getValue().asFloat());
}
// <--[mechanism]
// @object dNPC
// @name attack_range
// @input Element(Decimal)
// @description
// Sets the maximum attack distance of the NPC.
// @tags
// <n@npc.navigator.attack_range>
// -->
if (mechanism.matches("attack_range") && mechanism.requireFloat()) {
getCitizen().getNavigator().getDefaultParameters().attackRange(mechanism.getValue().asFloat());
}
// <--[mechanism]
// @object dNPC
// @name speed
// @input Element(Decimal)
// @description
// Sets the movement speed of the NPC.
// @tags
// <n@npc.navigator.speed>
// -->
if (mechanism.matches("speed") && mechanism.requireFloat()) {
getCitizen().getNavigator().getDefaultParameters().speedModifier(mechanism.getValue().asFloat());
}
// <--[mechanism]
// @object dNPC
// @name despawn
// @input none
// @description
// Despawns the NPC.
// @tags
// <n@npc.is_spawned>
// -->
if (mechanism.matches("despawn")) {
getCitizen().despawn(DespawnReason.PLUGIN);
}
// <--[mechanism]
// @object dNPC
// @name set_protected
// @input Element(Boolean)
// @description
// Sets whether or not the NPC is protected.
// @tags
// <n@npc.is_protected>
// -->
if (mechanism.matches("set_protected") && mechanism.requireBoolean()) {
getCitizen().setProtected(value.asBoolean());
}
// <--[mechanism]
// @object dNPC
// @name set_lookclose
// @input Element(Boolean)
// @description
// Sets the NPC's lookclose value.
// @tags
// <n@npc.lookclose>
// -->
if (mechanism.matches("lookclose") && mechanism.requireBoolean()) {
getLookCloseTrait().lookClose(value.asBoolean());
}
// <--[mechanism]
// @object dNPC
// @name set_examiner
// @input Element
// @description
// Sets the NPC's block examiner
// @tags
// TODO
// -->
if (mechanism.matches("set_examiner")) {
if (mechanism.getValue().toString().equalsIgnoreCase("default")) {
getNavigator().getLocalParameters().clearExaminers();
getNavigator().getLocalParameters().examiner(new MinecraftBlockExaminer());
}
else if (mechanism.getValue().toString().equalsIgnoreCase("fly")) {
getNavigator().getLocalParameters().clearExaminers();
getNavigator().getLocalParameters().examiner(new FlyingBlockExaminer());
}
else if (mechanism.getValue().toString().equalsIgnoreCase("path")) {
getNavigator().getLocalParameters().clearExaminers();
getNavigator().getLocalParameters().examiner(new PathBlockExaminer(this, null));
}
}
// <--[mechanism]
// @object dNPC
// @name teleport_on_stuck
// @input Element(Boolean)
// @description
// Sets whether the NPC teleports when it is stuck.
// @tags
// <n@npc.teleport_on_stuck>
// -->
if (mechanism.matches("teleport_on_stuck") && mechanism.requireBoolean()) {
if (value.asBoolean()) {
getNavigator().getDefaultParameters().stuckAction(TeleportStuckAction.INSTANCE);
}
else {
getNavigator().getDefaultParameters().stuckAction(null);
}
}
// <--[mechanism]
// @object dNPC
// @name set_distance
// @input Element
// @description
// Sets the NPC's distance margin.
// @tags
// TODO
// -->
if (mechanism.matches("set_distance") && mechanism.requireDouble()) {
getNavigator().getDefaultParameters().distanceMargin(mechanism.getValue().asDouble());
}
// <--[mechanism]
// @object dNPC
// @name add_waypoint
// @input dLocation
// @description
// Add a waypoint location to the NPC's path.
// @tags
// TODO
// -->
if (mechanism.matches("add_waypoint") && mechanism.requireObject(dLocation.class)) {
if (!getCitizen().hasTrait(Waypoints.class)) {
getCitizen().addTrait(Waypoints.class);
}
Waypoints wp = getCitizen().getTrait(Waypoints.class);
if ((wp.getCurrentProvider() instanceof WaypointProvider.EnumerableWaypointProvider)) {
((List<Waypoint>) ((WaypointProvider.EnumerableWaypointProvider) wp.getCurrentProvider()).waypoints())
.add(new Waypoint(value.asType(dLocation.class)));
}
}
// Iterate through this object's properties' mechanisms
for (Property property : PropertyParser.getProperties(this)) {
property.adjust(mechanism);
if (mechanism.fulfilled()) {
break;
}
}
// Pass along to dEntity mechanism handler if not already handled.
if (!mechanism.fulfilled()) {
if (isSpawned()) {
new dEntity(getEntity()).adjust(mechanism);
}
else {
mechanism.reportInvalid();
}
}
}
}