package com.laytonsmith.core.functions;
import com.laytonsmith.PureUtilities.Common.StringUtils;
import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.abstraction.MCCommandSender;
import com.laytonsmith.abstraction.MCLocation;
import com.laytonsmith.abstraction.MCNote;
import com.laytonsmith.abstraction.MCPlayer;
import com.laytonsmith.abstraction.MCWorld;
import com.laytonsmith.abstraction.StaticLayer;
import com.laytonsmith.abstraction.blocks.MCBlock;
import com.laytonsmith.abstraction.blocks.MCCommandBlock;
import com.laytonsmith.abstraction.blocks.MCMaterial;
import com.laytonsmith.abstraction.blocks.MCSign;
import com.laytonsmith.abstraction.enums.MCBiomeType;
import com.laytonsmith.abstraction.enums.MCInstrument;
import com.laytonsmith.abstraction.enums.MCSound;
import com.laytonsmith.abstraction.enums.MCSoundCategory;
import com.laytonsmith.abstraction.enums.MCTone;
import com.laytonsmith.abstraction.enums.MCTreeType;
import com.laytonsmith.annotations.api;
import com.laytonsmith.annotations.noboilerplate;
import com.laytonsmith.core.CHVersion;
import com.laytonsmith.core.ObjectGenerator;
import com.laytonsmith.core.Static;
import com.laytonsmith.core.constructs.CArray;
import com.laytonsmith.core.constructs.CBoolean;
import com.laytonsmith.core.constructs.CInt;
import com.laytonsmith.core.constructs.CNull;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.CVoid;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.environments.CommandHelperEnvironment;
import com.laytonsmith.core.exceptions.CRE.CREBadEntityException;
import com.laytonsmith.core.exceptions.CRE.CRECastException;
import com.laytonsmith.core.exceptions.CRE.CREFormatException;
import com.laytonsmith.core.exceptions.CRE.CREInvalidWorldException;
import com.laytonsmith.core.exceptions.CRE.CRELengthException;
import com.laytonsmith.core.exceptions.CRE.CRENotFoundException;
import com.laytonsmith.core.exceptions.CRE.CREPlayerOfflineException;
import com.laytonsmith.core.exceptions.CRE.CRERangeException;
import com.laytonsmith.core.exceptions.CRE.CREThrowable;
import com.laytonsmith.core.exceptions.CancelCommandException;
import com.laytonsmith.core.exceptions.ConfigRuntimeException;
/**
*
*/
public class Environment {
public static String docs() {
return "Allows you to manipulate the environment around the player";
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_block_at extends AbstractFunction {
@Override
public String getName() {
return "get_block_at";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2, 3, 4};
}
@Override
public String docs() {
return "string {x, y, z, [world] | xyzArray, [world]} Gets the id of the block at x, y, z. This function expects "
+ "either 1 or 3 arguments. If 1 argument is passed, it should be an array with the x, y, z"
+ " coordinates. The format of the return will be x:y where x is the id of the block, and"
+ " y is the meta data for the block. All blocks will return in this format, but blocks"
+ " that don't have meta data normally will return 0 in y. If world isn't specified, the current"
+ " player's world is used.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class,
CRELengthException.class, CREInvalidWorldException.class, CRENotFoundException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_2;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment env, Construct... args)
throws CancelCommandException, ConfigRuntimeException {
int x;
int y;
int z;
MCWorld w = null;
MCPlayer player = env.getEnv(CommandHelperEnvironment.class).GetPlayer();
if (player != null) {
w = player.getWorld();
}
if (args.length < 3) {
if (!(args[0] instanceof CArray)) {
throw new CRECastException("get_block_at expects param 1 to be an array", t);
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
x = loc.getBlockX();
y = loc.getBlockY();
z = loc.getBlockZ();
w = loc.getWorld();
if (args.length == 2) {
w = Static.getServer().getWorld(args[1].val());
if (w == null) {
throw new CREInvalidWorldException("The specified world " + args[1].val() + " doesn't exist", t);
}
}
} else {
x = (int) java.lang.Math.floor(Static.getNumber(args[0], t));
y = (int) java.lang.Math.floor(Static.getNumber(args[1], t));
z = (int) java.lang.Math.floor(Static.getNumber(args[2], t));
if (args.length == 4) {
w = Static.getServer().getWorld(args[3].val());
if (w == null) {
throw new CREInvalidWorldException("The specified world " + args[4].val() + " doesn't exist", t);
}
}
}
if (w == null) {
throw new CREInvalidWorldException("No world was provided", t);
}
MCBlock b = w.getBlockAt(x, y, z);
if (b == null) {
throw new CRENotFoundException(
"Could not find the block in " + this.getName() + " (are you running in cmdline mode?)", t);
}
return new CString(b.getTypeId() + ":" + b.getData(), t);
}
@Override
public Boolean runAsync() {
return false;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class set_block_at extends AbstractFunction {
@Override
public String getName() {
return "set_block_at";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3, 4, 5, 6};
}
@Override
public String docs() {
return "void {x, y, z, id, [world] [physics] | locationArray, id, [physics]} Sets the id of the block at"
+ " the x y z coordinates specified. If the first argument passed is an array,"
+ " it should be x, y, z, world coordinates. Id must be a blocktype identifier similar to the type"
+ " returned from get_block_at, except if the meta value is not specified, 0 is used."
+ " If world isn't specified, the current player's world is used. Physics (which defaults to true)"
+ " specifies whether or not to update the surrounding blocks when this block is set.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRELengthException.class,
CREFormatException.class, CREInvalidWorldException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_0_2;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment env, Construct... args)
throws CancelCommandException, ConfigRuntimeException {
int x;
int y;
int z;
boolean physics = true;
String id;
MCWorld w = null;
MCPlayer player = env.getEnv(CommandHelperEnvironment.class).GetPlayer();
if (player != null) {
w = player.getWorld();
}
if (args.length < 4) {
if (!(args[0] instanceof CArray)) {
throw new CRECastException("set_block_at expects param 1 to be an array", t);
}
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
x = l.getBlockX();
y = l.getBlockY();
z = l.getBlockZ();
w = l.getWorld();
id = args[1].val();
if (args.length == 3) {
physics = Static.getBoolean(args[2]);
}
} else {
x = (int) java.lang.Math.floor(Static.getNumber(args[0], t));
y = (int) java.lang.Math.floor(Static.getNumber(args[1], t));
z = (int) java.lang.Math.floor(Static.getNumber(args[2], t));
id = args[3].val();
if (args.length >= 5) {
w = Static.getServer().getWorld(args[4].val());
if (w == null) {
throw new CREInvalidWorldException("The specified world " + args[4].val() + " doesn't exist", t);
}
} else if (w == null) {
throw new CREInvalidWorldException("No world was provided", t);
}
if (args.length == 6) {
physics = Static.getBoolean(args[2]);
}
}
MCBlock b = w.getBlockAt(x, y, z);
String[] dataAndMeta = id.split(":");
int data;
byte meta = 0;
try {
if(dataAndMeta.length == 2) {
meta = Byte.parseByte(dataAndMeta[1]); // Throws NumberFormatException.
}
data = Integer.parseInt(dataAndMeta[0]); // Throws NumberFormatException.
} catch(NumberFormatException e) {
throw new CREFormatException("id must be formatted as such: 'x:y' where x and y are integers", t);
}
MCMaterial mat = StaticLayer.GetConvertor().getMaterial(data);
if (mat == null || !mat.isBlock()) {
throw new CRECastException("Not a block ID: " + data
+ ". Attempting to set an invalid id can corrupt chunks!", t);
}
try {
b.setTypeAndData(data, meta, physics);
} catch(IllegalArgumentException ex){
throw new CREFormatException("Invalid block meta data: \"" + id + "\"", t);
}
return CVoid.VOID;
}
@Override
public Boolean runAsync() {
return false;
}
}
@api(environments = {CommandHelperEnvironment.class})
@noboilerplate //This function seems to cause a OutOfMemoryError for some reason?
public static class set_sign_text extends AbstractFunction {
@Override
public String getName() {
return "set_sign_text";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3, 4, 5};
}
@Override
public String docs() {
return "void {xyzLocation, lineArray | xyzLocation, line1, [line2, [line3, [line4]]]}"
+ " Sets the text of the sign at the given location. If the block at x,y,z isn't a sign,"
+ " a RangeException is thrown. If the text on a line overflows 15 characters, it is simply"
+ " truncated.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRERangeException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCWorld w = null;
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
if (l.getBlock().isSign()) {
String line1 = "";
String line2 = "";
String line3 = "";
String line4 = "";
if (args.length == 2 && args[1] instanceof CArray) {
CArray ca = (CArray) args[1];
if (ca.size() >= 1) {
line1 = ca.get(0, t).val();
}
if (ca.size() >= 2) {
line2 = ca.get(1, t).val();
}
if (ca.size() >= 3) {
line3 = ca.get(2, t).val();
}
if (ca.size() >= 4) {
line4 = ca.get(3, t).val();
}
} else {
if (args.length >= 2) {
line1 = args[1].val();
}
if (args.length >= 3) {
line2 = args[2].val();
}
if (args.length >= 4) {
line3 = args[3].val();
}
if (args.length >= 5) {
line4 = args[4].val();
}
}
MCSign s = l.getBlock().getSign();
s.setLine(0, line1);
s.setLine(1, line2);
s.setLine(2, line3);
s.setLine(3, line4);
return CVoid.VOID;
} else {
throw new CRERangeException("The block at the specified location is not a sign", t);
}
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_sign_text extends AbstractFunction {
@Override
public String getName() {
return "get_sign_text";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "array {xyzLocation} Given a location array, returns an array of 4 strings of the text in the sign at that"
+ " location. If the location given isn't a sign, then a RangeException is thrown.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRERangeException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
MCWorld w = null;
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
if (l.getBlock().isSign()) {
MCSign s = l.getBlock().getSign();
CString line1 = new CString(s.getLine(0), t);
CString line2 = new CString(s.getLine(1), t);
CString line3 = new CString(s.getLine(2), t);
CString line4 = new CString(s.getLine(3), t);
return new CArray(t, line1, line2, line3, line4);
} else {
throw new CRERangeException("The block at the specified location is not a sign", t);
}
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class is_sign_at extends AbstractFunction {
@Override
public String getName() {
return "is_sign_at";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "boolean {xyzLocation} Returns true if the block at this location is a sign.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
MCWorld w = null;
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
return CBoolean.get(l.getBlock().isSign());
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class break_block extends AbstractFunction {
@Override
public String getName() {
return "break_block";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "void {locationArray} Mostly simulates a block break at a location. Does not trigger an event. Only works with"
+ " craftbukkit.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_0;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCLocation l;
MCPlayer p;
p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCWorld w = (p != null ? p.getWorld() : null);
l = ObjectGenerator.GetGenerator().location(args[0], w, t);
l.breakBlock();
return CVoid.VOID;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class set_biome extends AbstractFunction {
@Override
public String getName() {
return "set_biome";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3, 4};
}
@Override
public String docs() {
return "void {x, z, [world], biome | locationArray, biome} Sets the biome of the specified block column."
+ " The location array's y value is ignored. ----"
+ " Biome may be one of the following: " + StringUtils.Join(MCBiomeType.types(), ", ", ", or ");
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class,
CRENotFoundException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
int x;
int z;
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
MCWorld w = null;
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
if (args.length == 2) {
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
x = l.getBlockX();
z = l.getBlockZ();
w = l.getWorld();
} else {
x = Static.getInt32(args[0], t);
z = Static.getInt32(args[1], t);
if (args.length != 3) {
w = Static.getServer().getWorld(args[2].val());
}
}
MCBiomeType bt;
try {
bt = MCBiomeType.valueOf(args[args.length - 1].val());
if (bt == null) {
throw new CRENotFoundException(
"Could not find the internal biome type object (are you running in cmdline mode?)", t);
}
} catch (IllegalArgumentException e) {
throw new CREFormatException("The biome type \"" + args[1].val() + "\" does not exist.", t);
}
if (w == null) {
throw new CREInvalidWorldException("The specified world doesn't exist, or no world was provided", t);
}
w.setBiome(x, z, bt);
return CVoid.VOID;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_biome extends AbstractFunction {
@Override
public String getName() {
return "get_biome";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2, 3};
}
@Override
public String docs() {
return "string {x, z, [world] | locationArray} Returns the biome type of this block column. The location array's"
+ " y value is ignored. ---- The value returned"
+ " may be one of the following: " + StringUtils.Join(MCBiomeType.types(), ", ", ", or ");
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class,
CREInvalidWorldException.class, CRENotFoundException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
int x;
int z;
MCCommandSender sender = environment.getEnv(CommandHelperEnvironment.class).GetCommandSender();
MCWorld w = null;
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
if (args.length == 1) {
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], w, t);
x = l.getBlockX();
z = l.getBlockZ();
w = l.getWorld();
} else {
x = Static.getInt32(args[0], t);
z = Static.getInt32(args[1], t);
if (args.length != 2) {
w = Static.getServer().getWorld(args[2].val());
}
}
if (w == null) {
throw new CREInvalidWorldException("The specified world doesn't exist, or no world was provided", t);
}
MCBiomeType bt = w.getBiome(x, z);
if (bt == null) {
throw new CRENotFoundException("Could not find the biome type (are you running in cmdline mode?)", t);
}
return new CString(bt.name(), t);
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_highest_block_at extends AbstractFunction {
@Override
public String getName() {
return "get_highest_block_at";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2, 3};
}
@Override
public String docs() {
return "array {x, z, [world] | xyzArray, [world]} Gets the xyz of the highest block at a x and a z."
+ "It works the same as get_block_at, except that it doesn't matter now what the Y is."
+ "You can set it to -1000 or to 92374 it will just be ignored.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class,
CRELengthException.class, CREInvalidWorldException.class,
CRENotFoundException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
double x = 0;
double z = 0;
MCWorld w = null;
String world = null;
MCCommandSender sender = env.getEnv(CommandHelperEnvironment.class).GetCommandSender();
if (sender instanceof MCPlayer) {
w = ((MCPlayer) sender).getWorld();
}
if (args[0] instanceof CArray && !(args.length == 3)) {
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
x = loc.getX();
z = loc.getZ();
world = loc.getWorld().getName();
if (args.length == 2) {
world = args[1].val();
}
} else if (args.length == 2 || args.length == 3) {
x = Static.getDouble(args[0], t);
z = Static.getDouble(args[1], t);
if (args.length == 3) {
world = args[2].val();
}
}
if (world != null) {
w = Static.getServer().getWorld(world);
}
if (w == null) {
throw new CREInvalidWorldException("The specified world " + world + " doesn't exist", t);
}
MCBlock highestBlock = w.getHighestBlockAt((int) java.lang.Math.floor(x), (int) java.lang.Math.floor(z));
if (highestBlock == null) {
throw new CRENotFoundException(
"Could not find the highest block in " + this.getName() + " (are you running in cmdline mode?)", t);
}
return ObjectGenerator.GetGenerator().location(highestBlock.getLocation(), false);
}
@Override
public Boolean runAsync() {
return false;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class explosion extends AbstractFunction {
@Override
public String getName() {
return "explosion";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2, 3};
}
@Override
public String docs() {
return "void {Locationarray, [size], [safe]} Creates an explosion with the given size at the given location."
+ "Size defaults to size of a creeper (3), and null uses the default. If safe is true, (defaults to false)"
+ " the explosion"
+ " won't hurt the surrounding blocks. If size is 0, and safe is true, you will still see the animation"
+ " and hear the sound, but players won't be hurt, and neither will the blocks.";
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREFormatException.class, CRECastException.class, CRELengthException.class, CREInvalidWorldException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment env, Construct... args) throws CancelCommandException, ConfigRuntimeException {
double x = 0;
double y = 0;
double z = 0;
float size = 3;
MCWorld w = null;
MCPlayer m = null;
boolean safe = false;
if (args.length >= 3) {
safe = Static.getBoolean(args[2]);
}
if (args.length >= 2) {
if (!(args[1] instanceof CNull)) {
size = Static.getInt(args[1], t);
}
}
if (size > 100) {
throw new CRERangeException("A bit excessive, don't you think? Let's scale that back some, huh?", t);
}
if (!(args[0] instanceof CArray)) {
throw new CRECastException("Expecting an array at parameter 1 of explosion", t);
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
w = loc.getWorld();
x = loc.getX();
z = loc.getZ();
y = loc.getY();
if (w == null) {
if (!(env.getEnv(CommandHelperEnvironment.class).GetCommandSender() instanceof MCPlayer)) {
throw new CREPlayerOfflineException(this.getName() + " needs a world in the location array, or a player so it can take the current world of that player.", t);
}
m = env.getEnv(CommandHelperEnvironment.class).GetPlayer();
w = m.getWorld();
}
w.explosion(x, y, z, size, safe);
return CVoid.VOID;
}
@Override
public Boolean runAsync() {
return false;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class play_note extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CRERangeException.class,
CREFormatException.class, CREPlayerOfflineException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCPlayer p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCInstrument i = null;
MCNote n = null;
MCLocation l;
int instrumentOffset;
int noteOffset;
if (args.length == 2) {
Static.AssertPlayerNonNull(p, t);
instrumentOffset = 0;
noteOffset = 1;
l = p.getLocation();
} else if (args.length == 4) {
p = Static.GetPlayer(args[0], t);
instrumentOffset = 1;
noteOffset = 2;
l = ObjectGenerator.GetGenerator().location(args[3], p.getWorld(), t);
} else {
if (!(args[1] instanceof CArray) && args[2] instanceof CArray) {
//Player provided, location not
instrumentOffset = 1;
noteOffset = 2;
p = Static.GetPlayer(args[0], t);
l = p.getLocation();
} else {
//location provided, player not
instrumentOffset = 0;
noteOffset = 1;
Static.AssertPlayerNonNull(p, t);
l = ObjectGenerator.GetGenerator().location(args[2], p.getWorld(), t);
}
}
try {
i = MCInstrument.valueOf(args[instrumentOffset].val().toUpperCase().trim());
} catch (IllegalArgumentException e) {
throw new CREFormatException("Instrument provided is not a valid type, required one of: " + StringUtils.Join(MCInstrument.values(), ", ", ", or "), t);
}
MCTone tone = null;
if (args[noteOffset] instanceof CArray) {
int octave = Static.getInt32(((CArray) args[noteOffset]).get("octave", t), t);
if (octave < 0 || octave > 2) {
throw new CRERangeException("The octave must be 0, 1, or 2, but was " + octave, t);
}
String ttone = ((CArray) args[noteOffset]).get("tone", t).val().toUpperCase().trim();
try {
tone = MCTone.valueOf(ttone.trim().replaceAll("#", ""));
} catch (IllegalArgumentException e) {
throw new CREFormatException("Expected the tone parameter to be one of: "
+ StringUtils.Join(MCTone.values(), ", ", ", or ") + " but it was " + ttone, t);
}
boolean sharped = false;
if (ttone.trim().endsWith("#")) {
sharped = true;
}
try{
n = StaticLayer.GetConvertor().GetNote(octave, tone, sharped);
} catch(IllegalArgumentException e){
throw new CREFormatException(e.getMessage(), t);
}
} else {
throw new CRECastException("Expected an array for note parameter, but " + args[noteOffset] + " found instead", t);
}
Static.AssertPlayerNonNull(p, t);
p.playNote(l, i, n);
return CVoid.VOID;
}
@Override
public String getName() {
return "play_note";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3, 4};
}
@Override
public String docs() {
return "void {[player], instrument, note, [location]} Plays a note for the given player, at the given location."
+ " Player defaults to the current player, and location defaults to the player's location. Instrument may be one of:"
+ " " + StringUtils.Join(MCInstrument.values(), ", ", ", or ") + ", and note is an associative array with 2 values,"
+ " array(octave: 0, tone: 'F#') where octave is either 0, 1, or 2, and tone is one of the notes "
+ StringUtils.Join(MCTone.values(), ", ", ", or ") + ", optionally suffixed with a pound symbol, which denotes a sharp."
+ " (Not all notes can be sharped.)";
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api
public static class play_sound extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREInvalidWorldException.class,
CRECastException.class, CREFormatException.class,
CREPlayerOfflineException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t,
com.laytonsmith.core.environments.Environment environment,
Construct... args) throws ConfigRuntimeException {
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
MCSound sound;
MCSoundCategory category = null;
float volume = 1, pitch = 1;
if (!(args[1] instanceof CArray)) {
throw new CREFormatException("An array was expected but recieved " + args[1], t);
}
CArray sa = (CArray) args[1];
if (sa.containsKey("sound")) {
try {
sound = MCSound.valueOf(sa.get("sound", t).val().toUpperCase());
} catch (IllegalArgumentException iae) {
throw new CREFormatException("Sound name '" + sa.get("sound", t).val() + "' is invalid.", t);
}
} else {
throw new CREFormatException("Sound field was missing.", t);
}
if (sa.containsKey("category")) {
try {
category = MCSoundCategory.valueOf(sa.get("category", t).val().toUpperCase());
} catch (IllegalArgumentException iae){
throw new CREFormatException("Sound category '" + sa.get("category", t).val() + "' is invalid.", t);
}
}
if (sa.containsKey("volume")) {
volume = Static.getDouble32(sa.get("volume", t), t);
}
if (sa.containsKey("pitch")) {
pitch = Static.getDouble32(sa.get("pitch", t), t);
}
if (args.length == 3) {
java.util.List<MCPlayer> players = new java.util.ArrayList<MCPlayer>();
if (args[2] instanceof CArray) {
for (String key : ((CArray) args[2]).stringKeySet()) {
players.add(Static.GetPlayer(((CArray) args[2]).get(key, t), t));
}
} else {
players.add(Static.GetPlayer(args[2], t));
}
if(category == null) {
for (MCPlayer p : players) {
p.playSound(loc, sound, volume, pitch);
}
} else {
for (MCPlayer p : players) {
p.playSound(loc, sound, category, volume, pitch);
}
}
} else if(category == null){
loc.getWorld().playSound(loc, sound, volume, pitch);
} else {
loc.getWorld().playSound(loc, sound, category, volume, pitch);
}
return CVoid.VOID;
}
@Override
public String getName() {
return "play_sound";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3};
}
@Override
public String docs() {
return "void {locationArray, soundArray[, players]} Plays a sound at the"
+ " given location. SoundArray is in an associative array with"
+ " keys 'sound', 'category', 'volume', 'pitch', where all are optional except sound."
+ " Volume and pitch default to 1. Players can be a single"
+ " player or an array of players to play the sound to, if"
+ " not given, all players can potentially hear it. ---- Possible categories: "
+ StringUtils.Join(MCSoundCategory.values(), ", ", ", or ", " or ") + "."
+ " ---- Possible sounds: "
+ StringUtils.Join(MCSound.types(), ", ", ", or ", " or ");
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api
public static class play_named_sound extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CREInvalidWorldException.class,
CRECastException.class, CREFormatException.class,
CREPlayerOfflineException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t,
com.laytonsmith.core.environments.Environment environment,
Construct... args) throws ConfigRuntimeException {
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
String path;
MCSoundCategory category = null;
float volume = 1, pitch = 1;
if (!(args[1] instanceof CArray)) {
throw new CREFormatException("An array was expected but recieved " + args[1], t);
}
CArray sa = (CArray) args[1];
if (!sa.containsKey("sound")) {
throw new CREFormatException("Sound field was missing.", t);
}
path = sa.get("sound", t).val();
if (sa.containsKey("category")) {
try {
category = MCSoundCategory.valueOf(sa.get("category", t).val().toUpperCase());
} catch (IllegalArgumentException iae){
throw new CREFormatException("Sound category '" + sa.get("category", t).val() + "' is invalid.", t);
}
}
if (sa.containsKey("volume")) {
volume = Static.getDouble32(sa.get("volume", t), t);
}
if (sa.containsKey("pitch")) {
pitch = Static.getDouble32(sa.get("pitch", t), t);
}
if (args.length == 3) {
java.util.List<MCPlayer> players = new java.util.ArrayList<MCPlayer>();
if (args[2] instanceof CArray) {
for (String key : ((CArray) args[2]).stringKeySet()) {
players.add(Static.GetPlayer(((CArray) args[2]).get(key, t), t));
}
} else {
players.add(Static.GetPlayer(args[2], t));
}
if(category == null) {
for (MCPlayer p : players) {
p.playSound(loc, path, volume, pitch);
}
} else {
for (MCPlayer p : players) {
p.playSound(loc, path, category, volume, pitch);
}
}
} else if(category == null){
loc.getWorld().playSound(loc, path, volume, pitch);
} else {
loc.getWorld().playSound(loc, path, category, volume, pitch);
}
return CVoid.VOID;
}
@Override
public String getName() {
return "play_named_sound";
}
@Override
public Integer[] numArgs() {
return new Integer[]{2, 3};
}
@Override
public String docs() {
return "void {locationArray, soundArray[, players]} Plays a sound at the"
+ " given location. SoundArray is in an associative array with"
+ " keys 'sound', 'category', 'volume', 'pitch', where all are optional except sound."
+ " Volume and pitch default to 1. Players can be a single"
+ " player or an array of players to play the sound to, if"
+ " not given, all players can potentially hear it. Sound is"
+ " a sound path, separated by periods. ---- Possible categories: "
+ StringUtils.Join(MCSoundCategory.values(), ", ", ", or ", " or ") + ".";
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_block_info extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCPlayer p = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCLocation l = ObjectGenerator.GetGenerator().location(args[0], p == null ? null : p.getWorld(), t);
MCBlock b = l.getBlock();
if(args.length == 2) {
switch(args[1].val()) {
case "solid":
return CBoolean.get(b.isSolid());
case "flammable":
return CBoolean.get(b.isFlammable());
case "transparent":
return CBoolean.get(b.isTransparent());
case "occluding":
return CBoolean.get(b.isOccluding());
case "burnable":
return CBoolean.get(b.isBurnable());
default:
throw new CREFormatException("Invalid argument for block info", t);
}
}
CArray array = CArray.GetAssociativeArray(t);
array.set("solid", CBoolean.get(b.isSolid()), t);
array.set("flammable", CBoolean.get(b.isFlammable()), t);
array.set("transparent", CBoolean.get(b.isTransparent()), t);
array.set("occluding", CBoolean.get(b.isOccluding()), t);
array.set("burnable", CBoolean.get(b.isBurnable()), t);
return array;
}
@Override
public String getName() {
return "get_block_info";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1,2};
}
@Override
public String docs() {
return "mixed {locationArray, [index]} Returns an associative array with various information about a block."
+ " If an index is specified, it will return a boolean. ---- <ul>"
+ " <li>solid: If a block is solid (i.e. dirt or stone, as opposed to a torch or water)</li>"
+ " <li>flammable: Indicates if a block can catch fire</li>"
+ " <li>transparent: Indicates if light can pass through</li>"
+ " <li>occluding: indicates If the block fully blocks vision</li>"
+ " <li>burnable: Indicates if the block can burn away</li>"
+ "</ul>";
}
@Override
public CHVersion since() {
return CHVersion.V3_3_1;
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_light_at extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREInvalidWorldException.class,
CREFormatException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String getName() {
return "get_light_at";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "int {locationArray} Returns the combined light level at a block, taking into account all sources.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
MCWorld w = null;
MCPlayer pl = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
if (pl instanceof MCPlayer) {
w = pl.getWorld();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
return new CInt(loc.getBlock().getLightLevel(), t);
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class is_block_powered extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREInvalidWorldException.class,
CREFormatException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String getName() {
return "is_block_powered";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public String docs() {
return "boolean {locationArray, [checkMode]} Returns whether or not a block is being supplied with power."
+ "checkMode can be: \"BOTH\" (Check both direct and indirect power), \"DIRECT_ONLY\" (Check direct power only)"
+ " or \"INDIRECT_ONLY\" (Check indirect power only). CheckMode defaults to \"BOTH\".";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
MCWorld w = null;
MCPlayer pl = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
if (pl instanceof MCPlayer) {
w = pl.getWorld();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
CheckMode mode;
if(args.length == 2) {
try {
mode = CheckMode.valueOf(args[1].val().toUpperCase());
} catch (IllegalArgumentException e) {
throw new CREFormatException("Invalid checkMode: " + args[1].val() + ".", t);
}
} else {
mode = CheckMode.BOTH; // Default to BOTH to make it backwards compatible.
}
boolean ret;
switch(mode) {
case BOTH: {
ret = loc.getBlock().isBlockPowered() || loc.getBlock().isBlockIndirectlyPowered();
break;
}
case DIRECT_ONLY: {
ret = loc.getBlock().isBlockPowered();
break;
}
case INDIRECT_ONLY: {
ret = loc.getBlock().isBlockIndirectlyPowered();
break;
}
default: { // Should not be able to run.
throw new CREFormatException("Invalid checkMode: " + args[1].val() + ".", t);
}
}
return CBoolean.get(ret);
}
public enum CheckMode {
BOTH,
DIRECT_ONLY,
INDIRECT_ONLY
}
}
@api(environments = {CommandHelperEnvironment.class})
public static class get_block_power extends AbstractFunction {
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREInvalidWorldException.class,
CREFormatException.class};
}
@Override
public boolean isRestricted() {
return false;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String getName() {
return "get_block_power";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public String docs() {
return "int {locationArray} Returns the redstone power level that is supplied to this block [0-15]."
+ " If is_block_powered(locationArray, 'DIRECT_ONLY') returns true, a redstone ore placed at the"
+ " given location would be powered the return value - 1.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
MCWorld w = null;
MCPlayer pl = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
if (pl instanceof MCPlayer) {
w = pl.getWorld();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], w, t);
return new CInt(loc.getBlock().getBlockPower(), t);
}
}
@api
public static class generate_tree extends AbstractFunction {
@Override
public String getName() {
return "generate_tree";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREBadEntityException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String docs() {
return "boolean {locationArray, [treeType]} Generates a tree at the given location and returns if the generation succeeded or not."
+ " treeType can be " + StringUtils.Join(MCTreeType.values(), ", ", ", or ", " or ") + ", defaulting to TREE.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args) throws ConfigRuntimeException {
MCTreeType treeType;
if (args.length == 1) {
treeType = MCTreeType.TREE;
} else {
try {
treeType = MCTreeType.valueOf(args[1].val().toUpperCase());
} catch (IllegalArgumentException exception) {
throw new CREFormatException("The tree type \"" + args[1].val() + "\" does not exist.", t);
}
}
MCPlayer psender = environment.getEnv(CommandHelperEnvironment.class).GetPlayer();
MCLocation location = ObjectGenerator.GetGenerator().location(args[0], (psender != null ? psender.getWorld() : null), t);
return CBoolean.get(location.getWorld().generateTree(location, treeType));
}
}
@api
public static class get_block_command extends AbstractFunction {
@Override
public String getName() {
return "get_block_command";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String docs() {
return "string {locationArray} Returns the command string in the Command Block at the given location.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
if(loc.getBlock().isCommandBlock()) {
MCCommandBlock cb = loc.getBlock().getCommandBlock();
return new CString(cb.getCommand(), t);
} else {
throw new CREFormatException("The block at the specified location is not a command block", t);
}
}
}
@api
public static class set_block_command extends AbstractFunction {
@Override
public String getName() {
return "set_block_command";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String docs() {
return "void {locationArray, [cmd]} Sets a command to a Command Block at the given location."
+ "If no command is given or parameter is null, it clears the Command Block.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
String cmd = null;
if(args.length == 2 && !(args[1] instanceof CNull)) {
if(!(args[1] instanceof CString)) {
throw new CRECastException("Parameter 2 of " + getName() + " must be a string or null", t);
}
cmd = args[1].val();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
if(loc.getBlock().isCommandBlock()) {
MCCommandBlock cb = loc.getBlock().getCommandBlock();
cb.setCommand(cmd);
return CVoid.VOID;
} else {
throw new CREFormatException("The block at the specified location is not a command block", t);
}
}
}
@api
public static class get_command_block_name extends AbstractFunction {
@Override
public String getName() {
return "get_command_block_name";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1};
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String docs() {
return "string {locationArray} Returns the name of the Command Block at the given location.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args)
throws ConfigRuntimeException {
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
if(loc.getBlock().isCommandBlock()) {
MCCommandBlock cb = loc.getBlock().getCommandBlock();
return new CString(cb.getName(), t);
} else {
throw new CREFormatException("The block at the specified location is not a command block", t);
}
}
}
@api
public static class set_command_block_name extends AbstractFunction {
@Override
public String getName() {
return "set_command_block_name";
}
@Override
public Integer[] numArgs() {
return new Integer[]{1, 2};
}
@Override
public Class<? extends CREThrowable>[] thrown() {
return new Class[]{CRECastException.class, CREFormatException.class};
}
@Override
public boolean isRestricted() {
return true;
}
@Override
public Boolean runAsync() {
return false;
}
@Override
public String docs() {
return "void {locationArray, [name]} Sets the name of the Command Block at the given location."
+ "If no name is given or name is null, the Command Block's name is reset to @.";
}
@Override
public Version since() {
return CHVersion.V3_3_1;
}
@Override
public Construct exec(Target t, com.laytonsmith.core.environments.Environment environment, Construct... args
) throws ConfigRuntimeException {
String name = null;
if(args.length == 2 && !(args[1] instanceof CNull)) {
if(!(args[1] instanceof CString)) {
throw new CRECastException("Parameter 2 of " + getName() + " must be a string or null", t);
}
name = args[1].val();
}
MCLocation loc = ObjectGenerator.GetGenerator().location(args[0], null, t);
if(loc.getBlock().isCommandBlock()) {
MCCommandBlock cb = loc.getBlock().getCommandBlock();
cb.setName(name);
return CVoid.VOID;
} else {
throw new CREFormatException("The block at the specified location is not a command block", t);
}
}
}
}