Search in sources :

Example 1 with Anchor

use of net.citizensnpcs.util.Anchor in project Denizen-For-Bukkit by DenizenScript.

the class AnchorCommand method execute.

@Override
public void execute(ScriptEntry scriptEntry) throws CommandExecutionException {
    // Get objects
    Action action = (Action) scriptEntry.getObject("action");
    dLocation location = (dLocation) scriptEntry.getObject("location");
    Element range = (Element) scriptEntry.getObject("range");
    Element id = (Element) scriptEntry.getObject("id");
    dNPC npc = ((BukkitScriptEntryData) scriptEntry.entryData).getNPC();
    // Report to dB
    dB.report(scriptEntry, getName(), npc.debug() + action.name() + id.debug() + (location != null ? location.debug() : "") + (range != null ? range.debug() : ""));
    if (!npc.getCitizen().hasTrait(Anchors.class)) {
        npc.getCitizen().addTrait(Anchors.class);
    }
    switch(action) {
        case ADD:
            npc.getCitizen().getTrait(Anchors.class).addAnchor(id.asString(), location);
            return;
        case ASSUME:
            {
                Anchor n = npc.getCitizen().getTrait(Anchors.class).getAnchor(id.asString());
                if (n == null) {
                    dB.echoError(scriptEntry.getResidingQueue(), "Invalid anchor name '" + id.asString() + "'");
                } else {
                    npc.getEntity().teleport(n.getLocation());
                }
            }
            return;
        case WALKNEAR:
            {
                Anchor n = npc.getCitizen().getTrait(Anchors.class).getAnchor(id.asString());
                if (n == null) {
                    dB.echoError(scriptEntry.getResidingQueue(), "Invalid anchor name '" + id.asString() + "'");
                } else if (range == null) {
                    dB.echoError(scriptEntry.getResidingQueue(), "Must specify a range!");
                } else {
                    npc.getNavigator().setTarget(Utilities.getWalkableLocationNear(n.getLocation(), range.asInt()));
                }
            }
            return;
        case WALKTO:
            {
                Anchor n = npc.getCitizen().getTrait(Anchors.class).getAnchor(id.asString());
                if (n == null) {
                    dB.echoError(scriptEntry.getResidingQueue(), "Invalid anchor name '" + id.asString() + "'");
                } else {
                    npc.getNavigator().setTarget(n.getLocation());
                }
            }
            return;
        case REMOVE:
            {
                Anchor n = npc.getCitizen().getTrait(Anchors.class).getAnchor(id.asString());
                if (n == null) {
                    dB.echoError(scriptEntry.getResidingQueue(), "Invalid anchor name '" + id.asString() + "'");
                } else {
                    npc.getCitizen().getTrait(Anchors.class).removeAnchor(n);
                }
            }
    }
}
Also used : Anchors(net.citizensnpcs.trait.Anchors) Anchor(net.citizensnpcs.util.Anchor) net.aufdemrand.denizen.objects.dNPC(net.aufdemrand.denizen.objects.dNPC) BukkitScriptEntryData(net.aufdemrand.denizen.BukkitScriptEntryData) Element(net.aufdemrand.denizencore.objects.Element) net.aufdemrand.denizen.objects.dLocation(net.aufdemrand.denizen.objects.dLocation)

Example 2 with Anchor

use of net.citizensnpcs.util.Anchor in project Denizen-For-Bukkit by DenizenScript.

the class dNPC method getAttribute.

@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));
    }
    // -->
    if (attribute.startsWith("has_nickname")) {
        NPC citizen = getCitizen();
        return new Element(citizen.hasTrait(NicknameTrait.class) && citizen.getTrait(NicknameTrait.class).hasNickname()).getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("name.nickname")) {
        return new Element(getCitizen().hasTrait(NicknameTrait.class) ? getCitizen().getTrait(NicknameTrait.class).getNickname() : getName()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("name")) {
        return new Element(getName()).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
    }
    // -->
    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));
            }
        }
    }
    // -->
    if (attribute.startsWith("pushable") || attribute.startsWith("is_pushable")) {
        return new Element(getPushableTrait().isPushable()).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
    }
    // -->
    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));
    }
    // -->
    if (attribute.startsWith("has_anchors")) {
        return (new Element(getCitizen().getTrait(Anchors.class).getAnchors().size() > 0)).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
        }
    }
    // -->
    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));
    }
    // -->
    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);
    }
    // -->
    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));
    }
    // -->
    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;
            }
        }
    }
    // -->
    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;
        }
    }
    // -->
    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;
        }
    }
    // -->
    if (attribute.startsWith("engaged") || attribute.startsWith("is_engaged")) {
        return new Element(isEngaged()).getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("invulnerable") || attribute.startsWith("vulnerable")) {
        return new Element(getCitizen().data().get(NPC.DEFAULT_PROTECTED_METADATA, true)).getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("id")) {
        return new Element(getId()).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
        }
    }
    // -->
    if (attribute.startsWith("has_skin")) {
        return new Element(getCitizen().data().has(NPC.PLAYER_SKIN_UUID_METADATA)).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
        }
    }
    // -->
    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));
        }
    }
    // -->
    if (attribute.startsWith("inventory")) {
        return getDenizenInventory().getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("is_spawned")) {
        return new Element(isSpawned()).getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("is_protected")) {
        return new Element(getCitizen().isProtected()).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
    }
    // -->
    if (attribute.startsWith("location.previous_location")) {
        return (NPCTags.previousLocations.containsKey(getId()) ? NPCTags.previousLocations.get(getId()).getAttribute(attribute.fulfill(2)) : null);
    }
    // -->
    if (attribute.startsWith("teleport_on_stuck")) {
        return new Element(getNavigator().getDefaultParameters().stuckAction() == TeleportStuckAction.INSTANCE).getAttribute(attribute.fulfill(1));
    }
    // -->
    if (attribute.startsWith("has_script")) {
        NPC citizen = getCitizen();
        return new Element(citizen.hasTrait(AssignmentTrait.class) && citizen.getTrait(AssignmentTrait.class).hasAssignment()).getAttribute(attribute.fulfill(1));
    }
    // -->
    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));
        }
    }
    // -->
    if (attribute.startsWith("navigator.is_navigating")) {
        return new Element(getNavigator().isNavigating()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.speed")) {
        return new Element(getNavigator().getLocalParameters().speed()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.range")) {
        return new Element(getNavigator().getLocalParameters().range()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.attack_range")) {
        return new Element(getNavigator().getLocalParameters().attackRange()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.attack_strategy")) {
        return new Element(getNavigator().getLocalParameters().attackStrategy().toString()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.speed_modifier")) {
        return new Element(getNavigator().getLocalParameters().speedModifier()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.base_speed")) {
        return new Element(getNavigator().getLocalParameters().baseSpeed()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.avoid_water")) {
        return new Element(getNavigator().getLocalParameters().avoidWater()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.target_location")) {
        return (getNavigator().getTargetAsLocation() != null ? new dLocation(getNavigator().getTargetAsLocation()).getAttribute(attribute.fulfill(2)) : null);
    }
    // -->
    if (attribute.startsWith("navigator.is_fighting")) {
        return new Element(getNavigator().getEntityTarget() != null && getNavigator().getEntityTarget().isAggressive()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.target_type")) // TODO: IMPROVE
    {
        return new Element(getNavigator().getTargetType() == null ? "null" : getNavigator().getTargetType().toString()).getAttribute(attribute.fulfill(2));
    }
    // -->
    if (attribute.startsWith("navigator.target_entity")) {
        return (getNavigator().getEntityTarget() != null && getNavigator().getEntityTarget().getTarget() != null ? new dEntity(getNavigator().getEntityTarget().getTarget()).getAttribute(attribute.fulfill(2)) : null);
    }
    // -->
    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));
}
Also used : NPC(net.citizensnpcs.api.npc.NPC) ArrayList(java.util.ArrayList) FlagManager(net.aufdemrand.denizen.flags.FlagManager) Pose(net.citizensnpcs.util.Pose) Property(net.aufdemrand.denizencore.objects.properties.Property) Pattern(java.util.regex.Pattern) Anchors(net.citizensnpcs.trait.Anchors) Anchor(net.citizensnpcs.util.Anchor) Poses(net.citizensnpcs.trait.Poses) LookClose(net.citizensnpcs.trait.LookClose) Trait(net.citizensnpcs.api.trait.Trait)

Example 3 with Anchor

use of net.citizensnpcs.util.Anchor in project Citizens2 by CitizensDev.

the class Anchors method addAnchor.

public boolean addAnchor(String name, Location location) {
    Anchor newAnchor = new Anchor(name, location);
    if (anchors.contains(newAnchor))
        return false;
    anchors.add(newAnchor);
    return true;
}
Also used : Anchor(net.citizensnpcs.util.Anchor)

Example 4 with Anchor

use of net.citizensnpcs.util.Anchor in project Citizens2 by CitizensDev.

the class NPCCommands method anchor.

@Command(aliases = { "npc" }, usage = "anchor (--save [name]|--assume [name]|--remove [name]) (-a)(-c)", desc = "Changes/Saves/Lists NPC's location anchor(s)", flags = "ac", modifiers = { "anchor" }, min = 1, max = 3, permission = "citizens.npc.anchor")
public void anchor(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
    Anchors trait = npc.getTrait(Anchors.class);
    if (args.hasValueFlag("save")) {
        if (args.getFlag("save").isEmpty())
            throw new CommandException(Messages.INVALID_ANCHOR_NAME);
        if (args.getSenderLocation() == null)
            throw new ServerCommandException();
        if (args.hasFlag('c')) {
            if (trait.addAnchor(args.getFlag("save"), args.getSenderTargetBlockLocation())) {
                Messaging.sendTr(sender, Messages.ANCHOR_ADDED);
            } else
                throw new CommandException(Messages.ANCHOR_ALREADY_EXISTS, args.getFlag("save"));
        } else {
            if (trait.addAnchor(args.getFlag("save"), args.getSenderLocation())) {
                Messaging.sendTr(sender, Messages.ANCHOR_ADDED);
            } else
                throw new CommandException(Messages.ANCHOR_ALREADY_EXISTS, args.getFlag("save"));
        }
    } else if (args.hasValueFlag("assume")) {
        if (args.getFlag("assume").isEmpty())
            throw new CommandException(Messages.INVALID_ANCHOR_NAME);
        Anchor anchor = trait.getAnchor(args.getFlag("assume"));
        if (anchor == null)
            throw new CommandException(Messages.ANCHOR_MISSING, args.getFlag("assume"));
        npc.teleport(anchor.getLocation(), TeleportCause.COMMAND);
    } else if (args.hasValueFlag("remove")) {
        if (args.getFlag("remove").isEmpty())
            throw new CommandException(Messages.INVALID_ANCHOR_NAME);
        if (trait.removeAnchor(trait.getAnchor(args.getFlag("remove"))))
            Messaging.sendTr(sender, Messages.ANCHOR_REMOVED);
        else
            throw new CommandException(Messages.ANCHOR_MISSING, args.getFlag("remove"));
    } else if (!args.hasFlag('a')) {
        Paginator paginator = new Paginator().header("Anchors");
        paginator.addLine("<e>Key: <a>ID  <b>Name  <c>World  <d>Location (X,Y,Z)");
        for (int i = 0; i < trait.getAnchors().size(); i++) {
            if (trait.getAnchors().get(i).isLoaded()) {
                String line = "<a>" + i + "<b>  " + trait.getAnchors().get(i).getName() + "<c>  " + trait.getAnchors().get(i).getLocation().getWorld().getName() + "<d>  " + trait.getAnchors().get(i).getLocation().getBlockX() + ", " + trait.getAnchors().get(i).getLocation().getBlockY() + ", " + trait.getAnchors().get(i).getLocation().getBlockZ();
                paginator.addLine(line);
            } else {
                String[] parts = trait.getAnchors().get(i).getUnloadedValue();
                String line = "<a>" + i + "<b>  " + trait.getAnchors().get(i).getName() + "<c>  " + parts[0] + "<d>  " + parts[1] + ", " + parts[2] + ", " + parts[3] + " <f>(unloaded)";
                paginator.addLine(line);
            }
        }
        int page = args.getInteger(1, 1);
        if (!paginator.sendPage(sender, page))
            throw new CommandException(Messages.COMMAND_PAGE_MISSING);
    }
    // Assume Player's position
    if (!args.hasFlag('a'))
        return;
    if (sender instanceof ConsoleCommandSender)
        throw new ServerCommandException();
    npc.teleport(args.getSenderLocation(), TeleportCause.COMMAND);
}
Also used : Anchors(net.citizensnpcs.trait.Anchors) Anchor(net.citizensnpcs.util.Anchor) ServerCommandException(net.citizensnpcs.api.command.exception.ServerCommandException) ServerCommandException(net.citizensnpcs.api.command.exception.ServerCommandException) CommandException(net.citizensnpcs.api.command.exception.CommandException) ConsoleCommandSender(org.bukkit.command.ConsoleCommandSender) Paginator(net.citizensnpcs.api.util.Paginator) Command(net.citizensnpcs.api.command.Command)

Example 5 with Anchor

use of net.citizensnpcs.util.Anchor in project Denizen-For-Bukkit by DenizenScript.

the class NPCTag method registerTags.

public static void registerTags() {
    AbstractFlagTracker.registerFlagHandlers(tagProcessor);
    // Defined in EntityTag
    tagProcessor.registerTag(ElementTag.class, "is_npc", (attribute, object) -> {
        return new ElementTag(true);
    });
    // Defined in EntityTag
    tagProcessor.registerTag(ObjectTag.class, "location", (attribute, object) -> {
        if (attribute.startsWith("previous_location", 2)) {
            attribute.fulfill(1);
            Deprecations.npcPreviousLocationTag.warn(attribute.context);
            return NPCTagBase.previousLocations.get(object.getId());
        }
        if (object.isSpawned()) {
            return new EntityTag(object).doLocationTag(attribute);
        }
        return object.getLocation();
    });
    // <--[tag]
    // @attribute <NPCTag.previous_location>
    // @returns LocationTag
    // @description
    // Returns the NPC's previous navigated location.
    // -->
    tagProcessor.registerTag(LocationTag.class, "previous_location", (attribute, object) -> {
        return NPCTagBase.previousLocations.get(object.getId());
    });
    // Defined in EntityTag
    tagProcessor.registerTag(LocationTag.class, "eye_location", (attribute, object) -> {
        return object.getEyeLocation();
    });
    // <--[tag]
    // @attribute <NPCTag.has_nickname>
    // @returns ElementTag(Boolean)
    // @description
    // Returns true if the NPC has a nickname.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_nickname", (attribute, object) -> {
        NPC citizen = object.getCitizen();
        return new ElementTag(citizen.hasTrait(NicknameTrait.class) && citizen.getOrAddTrait(NicknameTrait.class).hasNickname());
    });
    // <--[tag]
    // @attribute <NPCTag.is_sitting>
    // @returns ElementTag(Boolean)
    // @description
    // Returns true if the NPC is sitting. Relates to <@link command sit>.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_sitting", (attribute, object) -> {
        NPC citizen = object.getCitizen();
        return new ElementTag(citizen.hasTrait(SittingTrait.class) && citizen.getOrAddTrait(SittingTrait.class).isSitting());
    });
    // <--[tag]
    // @attribute <NPCTag.is_sleeping>
    // @returns ElementTag(Boolean)
    // @description
    // Returns true if the NPC is sleeping. Relates to <@link command sleep>.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_sleeping", (attribute, object) -> {
        NPC citizen = object.getCitizen();
        return new ElementTag(citizen.hasTrait(SleepingTrait.class) && citizen.getOrAddTrait(SleepingTrait.class).isSleeping());
    });
    // <--[tag]
    // @attribute <NPCTag.nickname>
    // @returns ElementTag
    // @description
    // Returns the NPC's display name, as set by the Nickname trait (or the default NPC name).
    // -->
    tagProcessor.registerTag(ElementTag.class, "nickname", (attribute, object) -> {
        return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class).getNickname() : object.getName());
    });
    // Documented in EntityTag
    tagProcessor.registerTag(ElementTag.class, "name", (attribute, object) -> {
        if (attribute.startsWith("nickname", 2)) {
            Deprecations.npcNicknameTag.warn(attribute.context);
            attribute.fulfill(1);
            return new ElementTag(object.getCitizen().hasTrait(NicknameTrait.class) ? object.getCitizen().getOrAddTrait(NicknameTrait.class).getNickname() : object.getName());
        }
        return new ElementTag(object.getName());
    });
    // <--[tag]
    // @attribute <NPCTag.traits>
    // @returns ListTag
    // @description
    // Returns a list of all of the NPC's traits.
    // -->
    tagProcessor.registerTag(ListTag.class, "traits", (attribute, object) -> {
        List<String> list = new ArrayList<>();
        for (Trait trait : object.getCitizen().getTraits()) {
            list.add(trait.getName());
        }
        return new ListTag(list);
    }, "list_traits");
    // <--[tag]
    // @attribute <NPCTag.has_trait[<trait>]>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC has a specified trait.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_trait", (attribute, object) -> {
        if (attribute.hasParam()) {
            Class<? extends Trait> trait = CitizensAPI.getTraitFactory().getTraitClass(attribute.getParam());
            if (trait != null) {
                return new ElementTag(object.getCitizen().hasTrait(trait));
            }
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.pushable>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is pushable.
    // -->
    tagProcessor.registerTag(ElementTag.class, "pushable", (attribute, object) -> {
        return new ElementTag(object.getPushableTrait().isPushable());
    }, "is_pushable");
    // <--[tag]
    // @attribute <NPCTag.has_trigger[<trigger>]>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC has a specified trigger.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_trigger", (attribute, object) -> {
        if (!attribute.hasParam()) {
            return null;
        }
        if (!object.getCitizen().hasTrait(TriggerTrait.class)) {
            return new ElementTag(false);
        }
        TriggerTrait trait = object.getCitizen().getOrAddTrait(TriggerTrait.class);
        return new ElementTag(trait.hasTrigger(attribute.getParam()));
    });
    // <--[tag]
    // @attribute <NPCTag.has_anchors>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC has anchors assigned.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_anchors", (attribute, object) -> {
        return (new ElementTag(object.getCitizen().getOrAddTrait(Anchors.class).getAnchors().size() > 0));
    });
    // <--[tag]
    // @attribute <NPCTag.list_anchors>
    // @returns ListTag
    // @description
    // Returns a list of anchor names currently assigned to the NPC.
    // -->
    tagProcessor.registerTag(ListTag.class, "list_anchors", (attribute, object) -> {
        ListTag list = new ListTag();
        for (Anchor anchor : object.getCitizen().getOrAddTrait(Anchors.class).getAnchors()) {
            list.add(anchor.getName());
        }
        return list;
    });
    // <--[tag]
    // @attribute <NPCTag.anchor[<name>]>
    // @returns LocationTag
    // @description
    // Returns the location associated with the specified anchor, or null if it doesn't exist.
    // -->
    tagProcessor.registerTag(ObjectTag.class, "anchor", (attribute, object) -> {
        Anchors trait = object.getCitizen().getOrAddTrait(Anchors.class);
        if (attribute.hasParam()) {
            Anchor anchor = trait.getAnchor(attribute.getParam());
            if (anchor != null) {
                return new LocationTag(anchor.getLocation());
            } else {
                attribute.echoError("NPC Anchor '" + attribute.getParam() + "' is not defined.");
                return null;
            }
        } else if (attribute.startsWith("list", 2)) {
            attribute.fulfill(1);
            Deprecations.npcAnchorListTag.warn(attribute.context);
            ListTag list = new ListTag();
            for (Anchor anchor : trait.getAnchors()) {
                list.add(anchor.getName());
            }
            return list;
        } else {
            attribute.echoError("npc.anchor[...] tag must have an input.");
        }
        return null;
    }, "anchors");
    // <--[tag]
    // @attribute <NPCTag.constant[<constant_name>]>
    // @returns ElementTag
    // @description
    // Returns the specified constant from the NPC.
    // -->
    tagProcessor.registerTag(ElementTag.class, "constant", (attribute, object) -> {
        if (attribute.hasParam()) {
            if (object.getCitizen().hasTrait(ConstantsTrait.class) && object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(attribute.getParam()) != null) {
                return new ElementTag(object.getCitizen().getOrAddTrait(ConstantsTrait.class).getConstant(attribute.getParam()));
            } else {
                return null;
            }
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.has_pose[<name>]>
    // @returns ElementTag(Boolean)
    // @description
    // Returns true if the NPC has the specified pose, otherwise returns false.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_pose", (attribute, object) -> {
        if (attribute.hasParam()) {
            return new ElementTag(object.getCitizen().getOrAddTrait(Poses.class).hasPose(attribute.getParam()));
        } else {
            return null;
        }
    });
    // <--[tag]
    // @attribute <NPCTag.pose[<name>]>
    // @returns LocationTag
    // @description
    // Returns the pose as a LocationTag with x, y, and z set to 0, and the world set to the first
    // possible available world Bukkit knows about.
    // -->
    tagProcessor.registerTag(LocationTag.class, "pose", (attribute, object) -> {
        if (attribute.hasParam()) {
            Pose pose = object.getCitizen().getOrAddTrait(Poses.class).getPose(attribute.getParam());
            return new LocationTag(org.bukkit.Bukkit.getWorlds().get(0), 0, 0, 0, pose.getYaw(), pose.getPitch());
        } else {
            return null;
        }
    }, "get_pose");
    // <--[tag]
    // @attribute <NPCTag.name_hologram_npc>
    // @returns NPCTag
    // @description
    // Returns the NPCTag of a hologram attached to this NPC as its nameplate (if any).
    // Note that this can regenerate at any time.
    // -->
    tagProcessor.registerTag(ObjectTag.class, "name_hologram_npc", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(HologramTrait.class)) {
            return null;
        }
        HologramTrait hologram = object.getCitizen().getTraitNullable(HologramTrait.class);
        Entity entity = hologram.getNameEntity();
        if (entity == null) {
            return null;
        }
        return new EntityTag(entity).getDenizenObject();
    });
    // <--[tag]
    // @attribute <NPCTag.hologram_npcs>
    // @returns ListTag(NPCTag)
    // @description
    // Returns the list of hologram NPCs attached to an NPC (if any).
    // Note that these can regenerate at any time.
    // -->
    tagProcessor.registerTag(ListTag.class, "hologram_npcs", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(HologramTrait.class)) {
            return null;
        }
        HologramTrait hologram = object.getCitizen().getTraitNullable(HologramTrait.class);
        Collection<ArmorStand> stands = hologram.getHologramEntities();
        if (stands == null || stands.isEmpty()) {
            return null;
        }
        ListTag output = new ListTag();
        for (ArmorStand stand : stands) {
            output.addObject(new EntityTag(stand).getDenizenObject());
        }
        return output;
    });
    // <--[tag]
    // @attribute <NPCTag.hologram_lines>
    // @returns ListTag
    // @mechanism NPCTag.hologram_lines
    // @description
    // Returns the list of hologram lines attached to an NPC.
    // -->
    tagProcessor.registerTag(ListTag.class, "hologram_lines", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(HologramTrait.class)) {
            return null;
        }
        HologramTrait hologram = object.getCitizen().getTraitNullable(HologramTrait.class);
        return new ListTag(hologram.getLines());
    });
    // <--[tag]
    // @attribute <NPCTag.hologram_direction>
    // @returns ElementTag
    // @mechanism NPCTag.hologram_direction
    // @description
    // Returns the direction of an NPC's hologram as "BOTTOM_UP" or "TOP_DOWN".
    // -->
    tagProcessor.registerTag(ElementTag.class, "hologram_direction", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(HologramTrait.class)) {
            return null;
        }
        HologramTrait hologram = object.getCitizen().getTraitNullable(HologramTrait.class);
        return new ElementTag(hologram.getDirection().name());
    });
    // <--[tag]
    // @attribute <NPCTag.hologram_line_height>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.hologram_line_height
    // @description
    // Returns the line height for an NPC's hologram. Can be -1, indicating a default value should be used.
    // -->
    tagProcessor.registerTag(ElementTag.class, "hologram_line_height", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(HologramTrait.class)) {
            return null;
        }
        HologramTrait hologram = object.getCitizen().getTraitNullable(HologramTrait.class);
        return new ElementTag(hologram.getLineHeight());
    });
    // <--[tag]
    // @attribute <NPCTag.is_sneaking>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is currently sneaking. Only works for player-type NPCs.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_sneaking", (attribute, object) -> {
        if (!object.isSpawned() && object.getEntity() instanceof Player) {
            return null;
        }
        return new ElementTag(((Player) object.getEntity()).isSneaking());
    });
    // <--[tag]
    // @attribute <NPCTag.engaged[(<player>)]>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is currently engaged.
    // See <@link command engage>
    // -->
    tagProcessor.registerTag(ElementTag.class, "engaged", (attribute, object) -> {
        return new ElementTag(EngageCommand.getEngaged(object.getCitizen(), attribute.hasParam() ? attribute.paramAsType(PlayerTag.class) : null));
    }, "is_engaged");
    // <--[tag]
    // @attribute <NPCTag.invulnerable>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is currently invulnerable.
    // See <@link command vulnerable>
    // -->
    tagProcessor.registerTag(ElementTag.class, "invulnerable", (attribute, object) -> {
        return new ElementTag(object.getCitizen().data().get(NPC.DEFAULT_PROTECTED_METADATA, true));
    }, "vulnerable");
    // <--[tag]
    // @attribute <NPCTag.id>
    // @returns ElementTag(Number)
    // @description
    // Returns the NPC's ID number.
    // -->
    tagProcessor.registerTag(ElementTag.class, "id", (attribute, object) -> {
        return new ElementTag(object.getId());
    });
    // <--[tag]
    // @attribute <NPCTag.owner>
    // @returns PlayerTag
    // @mechanism NPCTag.owner
    // @description
    // Returns the owner of the NPC as a PlayerTag, if any.
    // -->
    tagProcessor.registerTag(ObjectTag.class, "owner", (attribute, object) -> {
        UUID owner = object.getOwner();
        if (owner == null) {
            return null;
        }
        OfflinePlayer player = Bukkit.getOfflinePlayer(owner);
        if (player.isOnline() || player.hasPlayedBefore()) {
            return new PlayerTag(player);
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.has_skin>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.skin
    // @description
    // Returns whether the NPC has a custom skin.
    // -->
    tagProcessor.registerTag(ElementTag.class, "has_skin", (attribute, object) -> {
        return new ElementTag(object.getCitizen().hasTrait(SkinTrait.class) && object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName() != null);
    });
    // <--[tag]
    // @attribute <NPCTag.skin_blob>
    // @returns ElementTag
    // @mechanism NPCTag.skin_blob
    // @description
    // Returns the NPC's custom skin blob, if any.
    // In the format: "texture;signature" (two values separated by a semicolon).
    // See also <@link language Player Entity Skins (Skin Blobs)>.
    // -->
    tagProcessor.registerTag(ElementTag.class, "skin_blob", (attribute, object) -> {
        if (object.getCitizen().hasTrait(SkinTrait.class)) {
            SkinTrait skin = object.getCitizen().getOrAddTrait(SkinTrait.class);
            String tex = skin.getTexture();
            String sign = "";
            if (skin.getSignature() != null) {
                sign = ";" + skin.getSignature();
            }
            return new ElementTag(tex + sign);
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.skull_skin>
    // @returns ElementTag
    // @description
    // Returns the NPC's current skin blob, formatted for input to a Player Skull item.
    // In the format: "UUID|Texture" (two values separated by pipes).
    // See also <@link language Player Entity Skins (Skin Blobs)>.
    // -->
    tagProcessor.registerTag(ElementTag.class, "skull_skin", (attribute, object) -> {
        if (!object.getCitizen().hasTrait(SkinTrait.class)) {
            return null;
        }
        SkinTrait skin = object.getCitizen().getOrAddTrait(SkinTrait.class);
        return new ElementTag(skin.getSkinName() + "|" + skin.getTexture());
    });
    // <--[tag]
    // @attribute <NPCTag.skin>
    // @returns ElementTag
    // @mechanism NPCTag.skin
    // @description
    // Returns the NPC's custom skin, if any.
    // -->
    tagProcessor.registerTag(ElementTag.class, "skin", (attribute, object) -> {
        if (object.getCitizen().hasTrait(SkinTrait.class)) {
            return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).getSkinName());
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.auto_update_skin>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.auto_update_skin
    // @description
    // Returns whether the NPC is set to automatically update skins from name.
    // -->
    tagProcessor.registerTag(ElementTag.class, "auto_update_skin", (attribute, object) -> {
        if (object.getCitizen().hasTrait(SkinTrait.class)) {
            return new ElementTag(object.getCitizen().getOrAddTrait(SkinTrait.class).shouldUpdateSkins());
        }
        return null;
    });
    // <--[tag]
    // @attribute <NPCTag.inventory>
    // @returns InventoryTag
    // @description
    // Returns the InventoryTag of the NPC.
    // -->
    tagProcessor.registerTag(InventoryTag.class, "inventory", (attribute, object) -> {
        return object.getDenizenInventory();
    });
    // <--[tag]
    // @attribute <NPCTag.is_spawned>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is spawned.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_spawned", (attribute, object) -> {
        return new ElementTag(object.isSpawned());
    });
    // <--[tag]
    // @attribute <NPCTag.is_protected>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is protected.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_protected", (attribute, object) -> {
        return new ElementTag(object.getCitizen().isProtected());
    });
    // <--[tag]
    // @attribute <NPCTag.lookclose>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.lookclose
    // @description
    // Returns whether the NPC has lookclose enabled.
    // -->
    tagProcessor.registerTag(ElementTag.class, "lookclose", (attribute, object) -> {
        NPC citizen = object.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.getOrAddTrait(LookClose.class).toString();
            lookclose = lookclose.substring(10, lookclose.length() - 1);
            return new ElementTag(Boolean.valueOf(lookclose));
        }
        return new ElementTag(false);
    });
    // <--[tag]
    // @attribute <NPCTag.controllable>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.controllable
    // @description
    // Returns whether the NPC has controllable enabled.
    // -->
    tagProcessor.registerTag(ElementTag.class, "controllable", (attribute, object) -> {
        if (object.getCitizen().hasTrait(Controllable.class)) {
            return new ElementTag(object.getCitizen().getOrAddTrait(Controllable.class).isEnabled());
        }
        return new ElementTag(false);
    });
    // <--[tag]
    // @attribute <NPCTag.targetable>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.targetable
    // @description
    // Returns whether the NPC is targetable.
    // -->
    tagProcessor.registerTag(ElementTag.class, "targetable", (attribute, object) -> {
        boolean targetable = object.getCitizen().data().get(NPC.TARGETABLE_METADATA, object.getCitizen().data().get(NPC.DEFAULT_PROTECTED_METADATA, true));
        return new ElementTag(targetable);
    });
    // <--[tag]
    // @attribute <NPCTag.teleport_on_stuck>
    // @returns ElementTag(Boolean)
    // @mechanism NPCTag.teleport_on_stuck
    // @description
    // Returns whether the NPC teleports when it is stuck.
    // -->
    tagProcessor.registerTag(ElementTag.class, "teleport_on_stuck", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getDefaultParameters().stuckAction() == TeleportStuckAction.INSTANCE);
    });
    tagProcessor.registerTag(ElementTag.class, "has_script", (attribute, object) -> {
        Deprecations.hasScriptTags.warn(attribute.context);
        NPC citizen = object.getCitizen();
        return new ElementTag(citizen.hasTrait(AssignmentTrait.class));
    });
    // <--[tag]
    // @attribute <NPCTag.script>
    // @returns ScriptTag
    // @deprecated Use 'NPCTag.scripts' (plural) instead.
    // @description
    // Deprecated variant of <@link tag NPCTag.scripts>.
    // -->
    tagProcessor.registerTag(ScriptTag.class, "script", (attribute, object) -> {
        Deprecations.npcScriptSingle.warn(attribute.context);
        NPC citizen = object.getCitizen();
        if (!citizen.hasTrait(AssignmentTrait.class)) {
            return null;
        } else {
            for (AssignmentScriptContainer container : citizen.getOrAddTrait(AssignmentTrait.class).containerCache) {
                if (container != null) {
                    return new ScriptTag(container);
                }
            }
            return null;
        }
    });
    // <--[tag]
    // @attribute <NPCTag.scripts>
    // @returns ListTag(ScriptTag)
    // @description
    // Returns a list of all assignment scripts on the NPC. Returns null if none.
    // -->
    tagProcessor.registerTag(ListTag.class, "scripts", (attribute, object) -> {
        NPC citizen = object.getCitizen();
        if (!citizen.hasTrait(AssignmentTrait.class)) {
            return null;
        } else {
            ListTag result = new ListTag();
            for (AssignmentScriptContainer container : citizen.getOrAddTrait(AssignmentTrait.class).containerCache) {
                if (container != null) {
                    result.addObject(new ScriptTag(container));
                }
            }
            return result;
        }
    });
    // <--[tag]
    // @attribute <NPCTag.distance_margin>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.distance_margin
    // @description
    // Returns the NPC's current pathfinding distance margin. That is, how close it needs to get to its destination (in block-lengths).
    // -->
    tagProcessor.registerTag(ElementTag.class, "distance_margin", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getDefaultParameters().distanceMargin());
    });
    // <--[tag]
    // @attribute <NPCTag.path_distance_margin>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.path_distance_margin
    // @description
    // Returns the NPC's current pathfinding distance margin. That is, how close it needs to get to individual points along its path.
    // -->
    tagProcessor.registerTag(ElementTag.class, "path_distance_margin", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getDefaultParameters().pathDistanceMargin());
    });
    // <--[tag]
    // @attribute <NPCTag.is_navigating>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is currently navigating.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_navigating", (attribute, object) -> {
        return new ElementTag(object.getNavigator().isNavigating());
    });
    // <--[tag]
    // @attribute <NPCTag.speed>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.speed
    // @description
    // Returns the current speed of the NPC.
    // -->
    tagProcessor.registerTag(ElementTag.class, "speed", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().speed());
    });
    // <--[tag]
    // @attribute <NPCTag.range>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.range
    // @description
    // Returns the NPC's current maximum pathfinding range.
    // -->
    tagProcessor.registerTag(ElementTag.class, "range", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().range());
    });
    // <--[tag]
    // @attribute <NPCTag.attack_range>
    // @returns ElementTag(Decimal)
    // @mechanism NPCTag.attack_range
    // @description
    // Returns the NPC's current navigator attack range limit.
    // -->
    tagProcessor.registerTag(ElementTag.class, "attack_range", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().attackRange());
    });
    // <--[tag]
    // @attribute <NPCTag.attack_strategy>
    // @returns ElementTag
    // @description
    // Returns the NPC's current navigator attack strategy.
    // Not related to Sentinel combat.
    // -->
    tagProcessor.registerTag(ElementTag.class, "attack_strategy", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().attackStrategy().toString());
    });
    // <--[tag]
    // @attribute <NPCTag.speed_modifier>
    // @returns ElementTag(Decimal)
    // @description
    // Returns the NPC's current movement speed modifier (a multiplier applied over their base speed).
    // -->
    tagProcessor.registerTag(ElementTag.class, "speed_modifier", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().speedModifier());
    });
    // <--[tag]
    // @attribute <NPCTag.base_speed>
    // @returns ElementTag(Decimal)
    // @description
    // Returns the NPC's base navigation speed.
    // -->
    tagProcessor.registerTag(ElementTag.class, "base_speed", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().baseSpeed());
    });
    // <--[tag]
    // @attribute <NPCTag.avoid_water>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC will avoid water.
    // -->
    tagProcessor.registerTag(ElementTag.class, "avoid_water", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getLocalParameters().avoidWater());
    });
    // <--[tag]
    // @attribute <NPCTag.target_location>
    // @returns LocationTag
    // @description
    // Returns the location the NPC is currently navigating towards (if any).
    // -->
    tagProcessor.registerTag(LocationTag.class, "target_location", (attribute, object) -> {
        if (object.getNavigator().getTargetAsLocation() == null) {
            return null;
        }
        return new LocationTag(object.getNavigator().getTargetAsLocation());
    });
    // <--[tag]
    // @attribute <NPCTag.navigator_look_at>
    // @returns LocationTag
    // @mechanism NPCTag.navigator_look_at
    // @description
    // Returns the location the NPC will currently look at while moving, if any.
    // -->
    tagProcessor.registerTag(LocationTag.class, "navigator_look_at", (attribute, object) -> {
        if (object.getNavigator().getLocalParameters().lookAtFunction() == null) {
            return null;
        }
        Location res = object.getNavigator().getLocalParameters().lookAtFunction().apply(object.getNavigator());
        if (res == null) {
            return null;
        }
        return new LocationTag(res);
    });
    // <--[tag]
    // @attribute <NPCTag.is_fighting>
    // @returns ElementTag(Boolean)
    // @description
    // Returns whether the NPC is currently targeting an entity for the Citizens internal punching pathfinder.
    // Not compatible with Sentinel.
    // -->
    tagProcessor.registerTag(ElementTag.class, "is_fighting", (attribute, object) -> {
        return new ElementTag(object.getNavigator().getEntityTarget() != null && object.getNavigator().getEntityTarget().isAggressive());
    });
    // <--[tag]
    // @attribute <NPCTag.target_type>
    // @returns ElementTag
    // @description
    // Returns the entity type of the NPC's current navigation target (if any).
    // -->
    tagProcessor.registerTag(ElementTag.class, "target_type", (attribute, object) -> {
        if (object.getNavigator().getTargetType() == null) {
            return null;
        }
        return new ElementTag(object.getNavigator().getTargetType().toString());
    });
    // <--[tag]
    // @attribute <NPCTag.target_entity>
    // @returns EntityTag
    // @description
    // Returns the entity being targeted by the NPC's current navigation (if any).
    // -->
    tagProcessor.registerTag(EntityTag.class, "target_entity", (attribute, object) -> {
        if (object.getNavigator().getEntityTarget() == null || object.getNavigator().getEntityTarget().getTarget() == null) {
            return null;
        }
        return new EntityTag(object.getNavigator().getEntityTarget().getTarget());
    });
    // <--[tag]
    // @attribute <NPCTag.registry_name>
    // @returns ElementTag
    // @description
    // Returns the name of the registry this NPC came from.
    // -->
    tagProcessor.registerTag(ElementTag.class, "registry_name", (attribute, object) -> {
        return new ElementTag(object.getCitizen().getOwningRegistry().getName());
    });
    // <--[tag]
    // @attribute <NPCTag.citizens_data[<key>]>
    // @returns ElementTag
    // @description
    // Returns the value of a Citizens NPC metadata key.
    // -->
    tagProcessor.registerTag(ElementTag.class, "citizens_data", (attribute, object) -> {
        if (!attribute.hasParam()) {
            return null;
        }
        Object val = object.getCitizen().data().get(attribute.getParam());
        if (val == null) {
            return null;
        }
        return new ElementTag(val.toString());
    });
    // <--[tag]
    // @attribute <NPCTag.citizens_data_keys>
    // @returns ListTag
    // @description
    // Returns a list of Citizens NPC metadata keys.
    // -->
    tagProcessor.registerTag(ListTag.class, "citizens_data_keys", (attribute, object) -> {
        DataKey holder = new MemoryDataKey();
        object.getCitizen().data().saveTo(holder);
        ListTag result = new ListTag();
        for (DataKey key : holder.getSubKeys()) {
            result.addObject(new ElementTag(key.name(), true));
        }
        return result;
    });
    tagProcessor.registerTag(NPCTag.class, "navigator", (attribute, object) -> {
        Deprecations.oldNPCNavigator.warn(attribute.context);
        return object;
    });
}
Also used : NPC(net.citizensnpcs.api.npc.NPC) SkinnableEntity(net.citizensnpcs.npc.skin.SkinnableEntity) DataKey(net.citizensnpcs.api.util.DataKey) MemoryDataKey(net.citizensnpcs.api.util.MemoryDataKey) AssignmentScriptContainer(com.denizenscript.denizen.scripts.containers.core.AssignmentScriptContainer) Pose(net.citizensnpcs.util.Pose) MemoryDataKey(net.citizensnpcs.api.util.MemoryDataKey) ListTag(com.denizenscript.denizencore.objects.core.ListTag) Anchor(net.citizensnpcs.util.Anchor) ScriptTag(com.denizenscript.denizencore.objects.core.ScriptTag) FlaggableObject(com.denizenscript.denizencore.flags.FlaggableObject) ElementTag(com.denizenscript.denizencore.objects.core.ElementTag) Trait(net.citizensnpcs.api.trait.Trait)

Aggregations

Anchor (net.citizensnpcs.util.Anchor)7 Anchors (net.citizensnpcs.trait.Anchors)4 ElementTag (com.denizenscript.denizencore.objects.core.ElementTag)2 NPC (net.citizensnpcs.api.npc.NPC)2 Trait (net.citizensnpcs.api.trait.Trait)2 DataKey (net.citizensnpcs.api.util.DataKey)2 Pose (net.citizensnpcs.util.Pose)2 LocationTag (com.denizenscript.denizen.objects.LocationTag)1 NPCTag (com.denizenscript.denizen.objects.NPCTag)1 AssignmentScriptContainer (com.denizenscript.denizen.scripts.containers.core.AssignmentScriptContainer)1 FlaggableObject (com.denizenscript.denizencore.flags.FlaggableObject)1 ListTag (com.denizenscript.denizencore.objects.core.ListTag)1 ScriptTag (com.denizenscript.denizencore.objects.core.ScriptTag)1 ArrayList (java.util.ArrayList)1 Pattern (java.util.regex.Pattern)1 BukkitScriptEntryData (net.aufdemrand.denizen.BukkitScriptEntryData)1 FlagManager (net.aufdemrand.denizen.flags.FlagManager)1 net.aufdemrand.denizen.objects.dLocation (net.aufdemrand.denizen.objects.dLocation)1 net.aufdemrand.denizen.objects.dNPC (net.aufdemrand.denizen.objects.dNPC)1 Element (net.aufdemrand.denizencore.objects.Element)1