package net.alcuria.umbracraft.engine.scripts;
import java.util.HashSet;
import java.util.Set;
import net.alcuria.umbracraft.Config;
import net.alcuria.umbracraft.Game;
import net.alcuria.umbracraft.annotations.Order;
import net.alcuria.umbracraft.annotations.Suggest;
import net.alcuria.umbracraft.annotations.Tooltip;
import net.alcuria.umbracraft.editor.Editor;
import net.alcuria.umbracraft.engine.entities.Entity;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
/** A command to make operations on variables.
* @author Andrew Keturi */
public class ControlVariableCommand extends ScriptCommand {
/** The operations we may perform on a variable
* @author Andrew Keturi */
public static enum ControlVariableOperation {
OPT_0_ASSIGN("="), OPT_1_ADD("+"), OPT_2_SUBTRACT("-"), OPT_3_MULTIPLY("*"), OPT_4_DIVIDE("/"), OPT_5_MOD("%"), OPT_6_ABS("abs(x)");
public String friendly;
private ControlVariableOperation(String friendly) {
this.friendly = friendly;
}
@Override
public String toString() {
return friendly;
}
}
/** The methods of manipulating a variable
* @author Andrew Keturi */
public static enum ControlVariableType {
CONSTANT("Constant"), ENTITY_X_POS("Entity X Position"), ENTITY_Y_POS("Entity Y Position"), RANDOM("Random"), VARIABLE_VALUE("Variable");
public String friendly;
private ControlVariableType(String friendly) {
this.friendly = friendly;
}
/** @return the fields which should be displayed for a particular
* {@link ControlVariableType} */
public String[] getFilter() {
switch (this) {
case CONSTANT:
return new String[] { "id", "type", "operation", "constant" };
case ENTITY_X_POS:
return new String[] { "id", "type", "operation", "entityId", "self" };
case ENTITY_Y_POS:
return new String[] { "id", "type", "operation", "entityId", "self" };
case RANDOM:
return new String[] { "id", "type", "operation", "min", "max" };
case VARIABLE_VALUE:
return new String[] { "id", "type", "operation", "variableId" };
}
return new String[] { "id", "type" };
}
@Override
public String toString() {
return friendly;
}
}
@Tooltip("A constant integer value")
public int constant;
@Tooltip("The id of the entity we're referencing")
@Suggest("entities")
public String entityId;
@Tooltip("The id of the variable we want to change")
@Order(0)
public String id;
@Tooltip("The minimum value (inclusive)")
public int max;
@Tooltip("The maximum value (inclusive)")
public int min;
@Tooltip("The operation to perform")
@Order(1)
public ControlVariableOperation operation = ControlVariableOperation.OPT_0_ASSIGN;
@Tooltip("Use the id of the entity this script is attached to")
public boolean self;
@Tooltip("The method we're using to manipulate the variable")
@Order(2)
public ControlVariableType type;
@Tooltip("The id of the variable we want to copy the value from")
public String variableId;
public ControlVariableCommand() {
}
@Override
public ScriptCommand copy() {
ControlVariableCommand cmd = new ControlVariableCommand();
cmd.constant = constant;
cmd.entityId = entityId;
cmd.id = id;
cmd.max = max;
cmd.min = min;
cmd.operation = operation;
cmd.self = self;
cmd.type = type;
cmd.variableId = variableId;
return cmd;
}
@Override
public Set<String> getFilter() {
final HashSet<String> set = new HashSet<>();
if (type == null) {
type = ControlVariableType.CONSTANT;
}
final String[] filters = type.getFilter();
for (String filter : filters) {
set.add(filter);
}
return set;
}
@Override
public String getName() {
return "Control Variable: " + id + " " + operation.toString() + " " + type.toString() + "(" + params() + ")";
}
@Override
public ObjectMap<String, Array<String>> getSuggestions() {
return new ObjectMap<String, Array<String>>() {
{
put("entityId", Editor.db().entities().keys());
put("variableId", Editor.db().variables().keys());
put("id", Editor.db().variables().keys());
}
};
}
@Override
public void onCompleted() {
}
@Override
public void onStarted(Entity entity) {
// get a reference to our variable
int value = Game.variables().get(id);
// determine the value of the operand we're using to change our value
int operand = 0;
switch (type) {
case CONSTANT:
operand = constant;
break;
case ENTITY_X_POS:
final Entity e = self ? entity : Game.entities().find(entityId);
if (e != null) {
operand = (int) (e.position.x / Config.tileWidth);
} else {
Game.error("Entity not found on map: " + entityId);
}
break;
case ENTITY_Y_POS:
final Entity e2 = self ? entity : Game.entities().find(entityId);
if (e2 != null) {
operand = (int) (e2.position.y / Config.tileWidth);
} else {
Game.error("Entity not found on map: " + entityId);
}
break;
case RANDOM:
operand = MathUtils.random(min, max);
break;
case VARIABLE_VALUE:
operand = Game.variables().get(variableId);
break;
}
// determine how to manipulate our value
switch (operation) {
case OPT_1_ADD:
value += operand;
break;
case OPT_2_SUBTRACT:
value -= operand;
break;
case OPT_3_MULTIPLY:
value *= operand;
break;
case OPT_4_DIVIDE:
if (operand != 0) {
value /= operand;
} else {
Game.error("Attempting to devide by zer-AAAAAAHHHH!!");
}
break;
case OPT_5_MOD:
if (operand != 0) {
value %= operand;
} else {
Game.error("Attempting to devide by zer-AAAAAAHHHH!!");
}
break;
case OPT_0_ASSIGN:
value = operand;
break;
case OPT_6_ABS:
value = Math.abs(operand);
break;
default:
break;
}
// update our variable db
Game.variables().set(id, value);
complete();
}
private String params() {
switch (type) {
case CONSTANT:
return String.valueOf(constant);
case ENTITY_X_POS:
case ENTITY_Y_POS:
return self ? "<self>" : entityId;
case RANDOM:
return String.format("rand(%d, %d)", min, max);
case VARIABLE_VALUE:
return variableId;
}
return entityId;
}
@Override
public void update() {
}
}