Skip to content

Commit

Permalink
Make If command able to run multiple commands, thus removing a great …
Browse files Browse the repository at this point in the history
…and ancient source of suffering from Denizen and life in general.

Fully working example script provided in a comment for this commit.
  • Loading branch information
davidcernat committed Jun 18, 2013
1 parent 898e954 commit 600ea75
Showing 1 changed file with 176 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
package net.aufdemrand.denizen.scripts.commands.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import net.aufdemrand.denizen.exceptions.CommandExecutionException;
import net.aufdemrand.denizen.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizen.exceptions.ScriptEntryCreationException;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.ScriptRegistry;
import net.aufdemrand.denizen.scripts.commands.AbstractCommand;
import net.aufdemrand.denizen.scripts.containers.core.TaskScriptContainer;
import net.aufdemrand.denizen.utilities.arguments.aH;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.citizensnpcs.api.CitizensAPI;

import org.bukkit.ChatColor;
import org.bukkit.entity.Player;

/**
* Core dScript IF command.
*
* @author Jeremy Schroeder
* @author Jeremy Schroeder, David Cernat
*/

public class IfCommand extends AbstractCommand {
Expand Down Expand Up @@ -56,27 +54,45 @@ public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException
// Initialize necessary fields
List<Comparable> comparables = new ArrayList<Comparable>();

String outcomeCommand = null;
ArrayList<String> outcomeArgs = new ArrayList<String>();
String elseCommand = null;
ArrayList<String> elseArgs = new ArrayList<String>();
TreeMap<Integer, ArrayList<String>> outcomeCommands = new TreeMap<Integer, ArrayList<String>>();
TreeMap<Integer, ArrayList<String>> elseCommands = new TreeMap<Integer, ArrayList<String>>();

// Keep track of this to avoid Denizen overlooking comparedTo when an operator is used
// with a value that matches the name of a command. (Good find dimensionZ!)
boolean usedOperator = false;

// Track whether we are inside the Else argument or not
boolean insideElse = false;

// Track whether we are adding a new command or not
boolean newCommand = false;

// Track whether we are inside recursive brackets whose contents
// should be added as arguments to our current If, not as commands
int bracketsEntered = 0;

comparables.add(new Comparable());
int index = 0;

// Iterate through the arguments, build comparables
for (String arg : scriptEntry.getArguments()) {

// Trim unwanted spaces
arg = arg.trim();

if (outcomeCommand == null) {

// Read "-" as meaning we are moving to a new command, unless we
// are inside nested brackets (i.e. bracketsEntered of at least 2)
// in which case we just treat what follows as arguments
if (aH.matchesArg("-", arg) && bracketsEntered < 2) {

newCommand = true;
}

else if (outcomeCommands.isEmpty()) {

// Set logic (Optional, default is REGULAR)
if (arg.startsWith("!")) {
if (arg.startsWith("!")) {
comparables.get(index).logic = Logic.NEGATIVE;
if ( arg.length() == 1)
continue;
Expand Down Expand Up @@ -113,38 +129,132 @@ else if (comparables.get(index).comparable == null) {
// If using MATCHES operator, keep as string.
comparables.get(index).comparable = findObjectType(arg);
}

// Set outcomeCommand first since compared-to is technically optional.

// If we find a bracket, add it to the number of brackets we
// are inside (which should probably always be 1 at this point)
else if (aH.matchesArg("{", arg)) {

bracketsEntered++;
}

// Add outcomeCommand first since compared-to is technically optional.
// If using an operator though, skip on to compared-to!
else if (!usedOperator && denizen.getCommandRegistry().get(arg.replace("^", "")) != null)
outcomeCommand = arg;

// Set compared-to
else if (!usedOperator && denizen.getCommandRegistry().get(arg.replace("^", "")) != null) {

// Only add a new command here if the list of commands is empty,
// so as to not add two commands when people use an optional -
// in front of their first (and sometimes only) command
if (outcomeCommands.size() == 0) {

outcomeCommands.put(outcomeCommands.size(), new ArrayList<String>());
outcomeCommands.get(outcomeCommands.lastKey()).add(arg.toUpperCase());
newCommand = false;
}

}
// Set compared-to
else {

comparables.get(index).comparedto = matchObjectType(comparables.get(index), arg);
usedOperator = false;
}
}
// Process outcome commands
else if (insideElse == false) {
// Move to else commands if we read an "else" and we're not
// currently going through nested arguments
if (aH.matchesArg("else", arg) && bracketsEntered == 0) {

// Set outcome command.
} else if (elseCommand == null) {
if (aH.matchesArg("ELSE", arg)) elseCommand = "";
else outcomeArgs.add(arg);
insideElse = true;
}

// Set ELSE command
} else {
// Specify ELSE command
if (elseCommand.equals("")) elseCommand = arg;
// Add elseArgs arguments
else elseArgs.add(arg);
// If we find a bracket, and we're already inside
// nested brackets, add the bracket to the current
// command's arguments
else if (aH.matchesArg("{", arg)) {

bracketsEntered++;

if (bracketsEntered > 1) {

outcomeCommands.get(outcomeCommands.lastKey()).add(arg);
}
}

else if (aH.matchesArg("}", arg)) {

bracketsEntered--;

if (bracketsEntered > 0) {

outcomeCommands.get(outcomeCommands.lastKey()).add(arg);
}
}
// Add new outcome command if the last argument was a non-nested "-"
else if (newCommand == true) {

newCommand = false;
outcomeCommands.put(outcomeCommands.size(), new ArrayList<String>());
outcomeCommands.get(outcomeCommands.lastKey()).add(arg.toUpperCase());
}
// Add new outcome argument
else {

outcomeCommands.get(outcomeCommands.lastKey()).add(arg);
}
}
// Process else commands
else {
// If we find a bracket, and we're already inside
// nested brackets, add the bracket to the current
// command's arguments
if (aH.matchesArg("{", arg)) {

bracketsEntered++;

if (bracketsEntered > 1) {

elseCommands.get(elseCommands.lastKey()).add(arg);
}
}

else if (aH.matchesArg("}", arg)) {

bracketsEntered--;

if (bracketsEntered > 0) {

elseCommands.get(elseCommands.lastKey()).add(arg);
}
}
// Add new else command if the last argument was a non-nested "-"
// or if it was "else" and we have no else commands yet
else if (newCommand == true || elseCommands.size() == 0) {

newCommand = false;
elseCommands.put(elseCommands.size(), new ArrayList<String>());
elseCommands.get(elseCommands.lastKey()).add(arg.toUpperCase());

// If we find an "if", act like we entered a set of
// brackets, so we treat the if's commands as arguments
// and don't add them to our current else commands
if (aH.matchesArg("if", arg)) {

bracketsEntered++;
}
}
// Add new else argument
else {

elseCommands.get(elseCommands.lastKey()).add(arg);
}
}
}

// Stash objects required to execute() into the ScriptEntry
scriptEntry.addObject("comparables", comparables);
scriptEntry.addObject("outcome-command", outcomeCommand);
scriptEntry.addObject("outcome-command-args", outcomeArgs.toArray());
scriptEntry.addObject("else-command", elseCommand);
scriptEntry.addObject("else-command-args", elseArgs.toArray());
scriptEntry.addObject("outcomeCommands", outcomeCommands);
scriptEntry.addObject("elseCommands", elseCommands);
}

@SuppressWarnings({ "unchecked", "incomplete-switch" })
Expand Down Expand Up @@ -384,8 +494,8 @@ else if (((String) com.comparedto).equalsIgnoreCase("item")) {
}

// Determine outcome -- do, or else?
if (ormet > 0 && andcount == andmet) doCommand(scriptEntry);
else doElse(scriptEntry);
if (ormet > 0 && andcount == andmet) doCommands(scriptEntry, "outcomeCommands");
else doCommands(scriptEntry, "elseCommands");
}


Expand Down Expand Up @@ -469,57 +579,39 @@ else if (comparable instanceof List) {

// Runs the outcome-command if the evaluation of the statement == true

private void doCommand(ScriptEntry scriptEntry) {
String outcomeCommand = ((String) scriptEntry.getObject("outcome-command")).toUpperCase();
String[] outcomeArgs = Arrays.copyOf((Object[]) scriptEntry.getObject("outcome-command-args"),
((Object[]) scriptEntry.getObject("outcome-command-args")).length, String[].class);

try { ScriptEntry entry = new ScriptEntry(outcomeCommand, outcomeArgs,
scriptEntry.getScript().getContainer())
.setPlayer(scriptEntry.getPlayer())
.setNPC(scriptEntry.getNPC()).setInstant(true)
.addObject("reqId", scriptEntry.getObject("reqId"));
scriptEntry.getResidingQueue().injectEntry(entry, 0);
} catch (ScriptEntryCreationException e) {
dB.echoError("There has been a problem running the Command. Check syntax.");
if (dB.showStackTraces) {
dB.echoDebug("STACKTRACE follows:");
e.printStackTrace();
}
else dB.echoDebug("Use '/denizen debug -s' for the nitty-gritty.");
}
}


// If ELSE command is specified, runs it if the evaluation of the statement == false

private void doElse(ScriptEntry scriptEntry) {

String elseCommand = null;
if (scriptEntry.getObject("else-command") != null)
elseCommand = ((String) scriptEntry.getObject("else-command")).toUpperCase();
String[] elseArgs = null;
if (scriptEntry.getObject("else-command-args") != null)
elseArgs = Arrays.copyOf((Object[]) scriptEntry.getObject("else-command-args"),
((Object[]) scriptEntry.getObject("else-command-args")).length, String[].class);
if (elseCommand == null) return;

try { ScriptEntry entry = new ScriptEntry(elseCommand, elseArgs,
scriptEntry.getScript().getContainer())
.setPlayer(scriptEntry.getPlayer())
.setNPC(scriptEntry.getNPC()).setInstant(true)
.addObject("reqId", scriptEntry.getObject("reqId"));
scriptEntry.getResidingQueue().injectEntry(entry, 0);
} catch (ScriptEntryCreationException e) {
dB.echoError("There has been a problem running the ELSE Command. Check syntax.");
if (dB.showStackTraces) {
dB.echoDebug("STACKTRACE follows:");
e.printStackTrace();
@SuppressWarnings("unchecked")
private void doCommands(ScriptEntry scriptEntry, String map) {

TreeMap<Integer, ArrayList<String>> commandMap = (TreeMap<Integer, ArrayList<String>>) scriptEntry.getObject(map);

List<ScriptEntry> entries = new ArrayList<ScriptEntry>();

for (Map.Entry<Integer, ArrayList<String>> pairs : commandMap.entrySet())
{
ArrayList<String> commandArray = pairs.getValue();
String command = commandArray.get(0);
commandArray.remove(0);
String[] arguments = commandArray.toArray(new String[commandArray.size()]);

try {
ScriptEntry entry = new ScriptEntry(command, arguments,
scriptEntry.getScript().getContainer())
.setPlayer(scriptEntry.getPlayer())
.setNPC(scriptEntry.getNPC()).setInstant(true)
.addObject("reqId", scriptEntry.getObject("reqId"));

entries.add(entry);

} catch (ScriptEntryCreationException e) {
dB.echoError("There has been a problem running the Command. Check syntax.");
if (dB.showStackTraces) {
dB.echoDebug("STACKTRACE follows:");
e.printStackTrace();
}
else dB.echoDebug("Use '/denizen debug -s' for the nitty-gritty.");
}
else dB.echoDebug("Use '/denizen debug -s' for the nitty-gritty.");
}

}
scriptEntry.getResidingQueue().injectEntries(entries, 0);
}


}

2 comments on commit 600ea75

@davidcernat
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, folks:

If Complicated:
  type: assignment

  interact scripts:
  - 10 If Complicated Test

If Complicated Test:
  type: interact

  steps:
    1:
      click trigger:
        script:
        - chat "<white>Say apple, melon, cookie, carrot or egg!"
      chat trigger:
        '1':
          Trigger: /REGEX:\w+/
          Script:
          - flag "Input:<player.chat_history>"
          - if "<flag.p:Input>" == apple {
            - chat "You said apple."
            - chat "Do you have an apple in your hand?"
            - if "<player.item_in_hand.material>" == apple {
              - chat "Yes, you do."
              - chat "Do you have more than 1 apple in your inventory?"
              - if "<player.inventory.qty[apple]>" > 1 {
                - chat "Yes, you have more than 1 apple."
                }
                else chat "Seems like you only have that one apple."
              - if "<player.inventory.qty[apple]>" > 2
                chat "In fact, you even have more than 2 apples."
              }
              else if "<player.item_in_hand.material>" == melon {
              - chat "Actually, it looks like you're holding a melon."
              }
              else {
              - chat "No, you do not."
              - chat "That's too bad."
              }
            }
            else if "<flag.p:Input>" == melon {
            - chat "You said melon."
            - chat "Do you have an melon in your hand?"
            - if "<player.item_in_hand.material>" == melon {
              - chat "Yes, you do."
              - chat "Do you have more than 1 melon in your inventory?"
              - if "<player.inventory.qty[melon]>" > 1 {
                - chat "Yes, you have more than 1 melon."
                }
                else chat "Seems like you only have that one melon."
              - if "<player.inventory.qty[melon]>" > 2
                chat "In fact, you even have more than 2 melons."
              }
              else if "<player.item_in_hand.material>" == apple {
              - chat "Actually, it looks like you're holding an apple."
              }
              else {
              - chat "No, you do not."
              - chat "That's too bad."
              }
            }
            else if "<flag.p:Input>" == cookie {
            - chat "You said cookie."
            - chat "Do you have an cookie in your hand?"
            - if "<player.item_in_hand.material>" == cookie {
              - chat "Yes, you do."
              - chat "Do you have more than 1 cookie in your inventory?"
              - if "<player.inventory.qty[cookie]>" > 1 {
                - chat "Yes, you have more than 1 cookie."
                }
                else chat "Seems like you only have that one cookie."
              - if "<player.inventory.qty[cookie]>" > 2
                chat "In fact, you even have more than 2 cookies."
              }
              else if "<player.item_in_hand.material>" == melon {
              - chat "Actually, it looks like you're holding a melon."
              }
              else {
              - chat "No, you do not."
              - chat "That's too bad."
              }
            }
            else if "<flag.p:Input>" == carrot {
            - chat "You said carrot."
            - chat "Do you have an carrot in your hand?"
            - if "<player.item_in_hand.material>" == carrot {
              - chat "Yes, you do."
              - chat "Do you have more than 1 carrot in your inventory?"
              - if "<player.inventory.qty[carrot]>" > 1 {
                - chat "Yes, you have more than 1 carrot."
                }
                else chat "Seems like you only have that one carrot."
              - if "<player.inventory.qty[carrot]>" > 2
                chat "In fact, you even have more than 2 carrots."
              }
              else if "<player.item_in_hand.material>" == melon {
              - chat "Actually, it looks like you're holding a melon."
              }
              else {
              - chat "No, you do not."
              - chat "That's too bad."
              }
            }
            else if "<flag.p:Input>" == egg {
            - chat "You said egg."
            - chat "Do you have an egg in your hand?"
            - if "<player.item_in_hand.material>" == egg {
              - chat "Yes, you do."
              - chat "Do you have more than 1 egg in your inventory?"
              - if "<player.inventory.qty[egg]>" > 1 {
                - chat "Yes, you have more than 1 egg."
                }
                else chat "Seems like you only have that one egg."
              - if "<player.inventory.qty[egg]>" > 2
                chat "In fact, you even have more than 2 eggs."
              }
              else if "<player.item_in_hand.material>" == melon {
              - chat "Actually, it looks like you're holding a melon."
              }
              else {
              - chat "No, you do not."
              - chat "That's too bad."
              }
            }
            else chat "You did not say any of the things I reply to."
          - if "<flag.p:Input>" == apple
            chat "Anyway, I could talk about apples all day."
            else if "<flag.p:Input>" == melon
            chat "I have to admit I don't like melons as much as apples though."
            else if "<flag.p:Input>" == cookie
            chat "I eat a lot of cookies every day."
            else if "<flag.p:Input>" == carrot
            chat "I'm not that keen on carrots, to be honest."
            else if "<flag.p:Input>" == egg
            chat "So who crossed the road first<&co> the chicken or the egg? Wait, that's not how it goes..."

Obviously, the script above is repetitious only for testing purposes. :p

@spaceemotion
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You, sir - deserve a 🍪!

Please sign in to comment.