예제 #1
0
  public boolean doAction(
      String actionName,
      dNPC npc,
      dPlayer player,
      AssignmentScriptContainer assignment,
      Map<String, dObject> context) {
    if (assignment == null) {
      // dB.echoDebug("Tried to do 'on " + actionName + ":' but couldn't find a matching script.");
      return false;
    }

    if (!assignment.contains("actions.on " + actionName)) return false;

    dB.report(
        "Action",
        aH.debugObj("Type", "On " + actionName)
            + aH.debugObj("NPC", npc.toString())
            + assignment.getAsScriptArg().debug()
            + (player != null ? aH.debugObj("Player", player.getName()) : ""));

    // Fetch script from Actions
    List<ScriptEntry> script = assignment.getEntries(player, npc, "actions.on " + actionName);
    if (script.isEmpty()) return false;

    dB.echoDebug(
        DebugElement.Header,
        "Building action 'On " + actionName.toUpperCase() + "' for " + npc.toString());

    // Add entries and context to the queue
    ScriptQueue queue = InstantQueue.getQueue(null).addEntries(script);

    if (context != null) {
      for (Map.Entry<String, dObject> entry : context.entrySet()) {
        queue.addContext(entry.getKey(), entry.getValue());
      }
    }

    // Start the queue!
    queue.start();

    // TODO: Read determination to see if the event behind action should be cancelled.

    return false;
  }
예제 #2
0
  // Technically defined in TriggerTrait, but placing here instead.
  // <--[action]
  // @Actions
  // chat
  //
  // @Triggers when a player chats to the NPC.
  //
  // @Context
  // <context.message> returns the triggering message
  // <context.keyword> returns the keyword matched by a RegEx trigger
  //
  // -->
  public Boolean process(Player player, String message) {

    // Check if there is an NPC within range of a player to chat to.
    dNPC npc = Utilities.getClosestNPC_ChatTrigger(player.getLocation(), 25);
    dPlayer denizenPlayer = dPlayer.mirrorBukkitPlayer(player);

    // No NPC? Nothing else to do here.
    if (npc == null) return false;

    // If the NPC doesn't have triggers, or the triggers are not enabled, then
    // just return false.
    if (!npc.getCitizen().hasTrait(TriggerTrait.class)) return false;
    if (!npc.getCitizen().getTrait(TriggerTrait.class).isEnabled(name)) return false;

    // Check range
    if (npc.getTriggerTrait().getRadius(name) < npc.getLocation().distance(player.getLocation()))
      return false;

    // The Denizen config can require some other criteria for a successful chat-with-npc.
    // Should we check 'line of sight'? Players cannot talk to NPCs through walls
    // if enabled. Should the Player chat only when looking at the NPC? This may
    // reduce accidental chats with NPCs.

    if (Settings.ChatMustSeeNPC()) if (!player.hasLineOfSight(npc.getEntity())) return false;

    if (Settings.ChatMustLookAtNPC())
      if (!Rotation.isFacingEntity(player, npc.getEntity(), 45)) return false;

    Boolean ret = false;

    // Denizen should be good to interact with. Let's get the script.
    InteractScriptContainer script = npc.getInteractScript(denizenPlayer, ChatTrigger.class);

    Map<String, dObject> context = new HashMap<String, dObject>();
    context.put("message", new Element(message));

    // If engaged or not cool, calls On Unavailable, if cool, calls On Chat
    // If available (not engaged, and cool) sets cool down and returns true.
    if (!npc.getTriggerTrait().trigger(ChatTrigger.this, denizenPlayer, context)) {
      // If the NPC is not interactable, Settings may allow the chat to filter
      // through. Check the Settings if this is enabled.
      if (Settings.ChatGloballyIfUninteractable()) {
        dB.echoDebug(
            script,
            ChatColor.YELLOW
                + "Resuming. "
                + ChatColor.WHITE
                + "The NPC is currently cooling down or engaged.");
        return false;
      } else {
        ret = true;
      }
    }

    // Debugger
    dB.report(
        script,
        name,
        aH.debugObj("Player", player.getName())
            + aH.debugObj("NPC", npc.toString())
            + aH.debugObj(
                "Radius(Max)",
                npc.getLocation().distance(player.getLocation())
                    + "("
                    + npc.getTriggerTrait().getRadius(name)
                    + ")")
            + aH.debugObj("Trigger text", message)
            + aH.debugObj("LOS", String.valueOf(player.hasLineOfSight(npc.getEntity())))
            + aH.debugObj(
                "Facing", String.valueOf(Rotation.isFacingEntity(player, npc.getEntity(), 45))));

    if (script == null) return false;

    // Check if the NPC has Chat Triggers for this step.
    if (!script.containsTriggerInStep(
        InteractScriptHelper.getCurrentStep(denizenPlayer, script.getName()), ChatTrigger.class)) {

      // If this is a Chatbot, make it chat anything it wants if
      // it has no chat triggers for this step
      if (npc.getCitizen().hasTrait(ChatbotTrait.class)) {
        Utilities.talkToNPC(message, denizenPlayer, npc, Settings.ChatToNpcOverhearingRange());
        npc.getCitizen().getTrait(ChatbotTrait.class).chatTo(player, message);
        return true;
      }
      // No chat trigger for this step.. do we chat globally, or to the NPC?
      else if (!Settings.ChatGloballyIfNoChatTriggers()) {
        dB.echoDebug(
            script,
            player.getName() + " says to " + npc.getNicknameTrait().getNickname() + ", " + message);
        return true;
      } else return ret;
    }

    // Parse the script and match Triggers.. if found, cancel the text! The
    // parser will take care of everything else.
    String id = null;
    boolean matched = false;
    String replacementText = null;
    String regexId = null;
    String regexMessage = null;

    // Use TreeMap to sort chat triggers alphabetically
    TreeMap<String, String> idMap = new TreeMap<String, String>();
    idMap.putAll(script.getIdMapFor(ChatTrigger.class, denizenPlayer));

    if (!idMap.isEmpty()) {
      // Iterate through the different id entries in the step's chat trigger
      for (Map.Entry<String, String> entry : idMap.entrySet()) {

        // Check if the chat trigger specified in the specified id's 'trigger:' key
        // matches the text the player has said
        String triggerText = TagManager.tag(denizenPlayer, npc, entry.getValue());
        Matcher matcher = triggerPattern.matcher(triggerText);
        while (matcher.find()) {
          if (!script.checkSpecificTriggerScriptRequirementsFor(
              ChatTrigger.class, denizenPlayer, npc, entry.getKey())) continue;
          String keyword = TagManager.tag(denizenPlayer, npc, matcher.group().replace("/", ""));
          // Check if the trigger is REGEX, but only if we don't have a REGEX
          // match already (thus using alphabetical priority for triggers)
          if (regexId == null && isKeywordRegex(keyword)) {
            Pattern pattern = Pattern.compile(keyword.substring(6));
            Matcher m = pattern.matcher(message);
            if (m.find()) {
              // REGEX matches are left for last, so save it in case non-REGEX
              // matches don't exist
              regexId = entry.getKey();
              regexMessage = triggerText.replace(matcher.group(), m.group());
              dB.log(
                  "entry value: "
                      + triggerText
                      + "  keyword: "
                      + keyword
                      + "  m.group: "
                      + m.group()
                      + "  matcher.group: "
                      + matcher.group());
              context.put("keyword", new Element(m.group()));
            }
          } else if (isKeywordStrict(keyword)) {
            if (message.toUpperCase().equalsIgnoreCase(keyword.toUpperCase())) {
              // Trigger matches
              id = entry.getKey();
              replacementText = triggerText.replace("/", "");
              matched = true;
            }
          } else if (message.toUpperCase().contains(keyword.toUpperCase())) {
            // Trigger matches
            id = entry.getKey();
            replacementText = triggerText.replace("/", "");
            matched = true;
          }
        }
        if (matched) break;
      }
    }

    if (!matched && regexId != null) {
      id = regexId;
      replacementText = regexMessage;
    }

    // If there was a match, the id of the match should have been returned.
    if (id != null) {
      Utilities.talkToNPC(
          replacementText, denizenPlayer, npc, Settings.ChatToNpcOverhearingRange());
      parse(npc, denizenPlayer, script, id, context);
      return true;
    } else {
      // If this is a Chatbot, make it chat anything it wants if
      // none of its chat triggers worked
      if (npc.getCitizen().hasTrait(ChatbotTrait.class)) {
        Utilities.talkToNPC(message, denizenPlayer, npc, Settings.ChatToNpcOverhearingRange());
        npc.getCitizen().getTrait(ChatbotTrait.class).chatTo(player, message);
        return true;
      } else if (!Settings.ChatGloballyIfFailedChatTriggers()) {
        Utilities.talkToNPC(message, denizenPlayer, npc, Settings.ChatToNpcOverhearingRange());
        return true;
      }
      // No matching chat triggers, and the config.yml says we
      // should just ignore the interaction...
    }
    return ret;
  }