Merge branch 'master' into pr-readwrite
This commit is contained in:
@@ -27,34 +27,63 @@ public class GlobalVars{
|
||||
public static final Rand rand = new Rand();
|
||||
|
||||
//non-constants that depend on state
|
||||
private static int varTime, varTick, varSecond, varMinute, varWave, varWaveTime;
|
||||
private static int varTime, varTick, varSecond, varMinute, varWave, varWaveTime, varMapW, varMapH, varServer, varClient, varClientLocale, varClientUnit, varClientName, varClientTeam, varClientMobile;
|
||||
|
||||
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
|
||||
private Seq<Var> vars = new Seq<>(Var.class);
|
||||
private Seq<VarEntry> varEntries = new Seq<>();
|
||||
private IntSet privilegedIds = new IntSet();
|
||||
private UnlockableContent[][] logicIdToContent;
|
||||
private int[][] contentIdToLogicId;
|
||||
|
||||
public void init(){
|
||||
put("the end", null);
|
||||
putEntryOnly("sectionProcessor");
|
||||
|
||||
putEntryOnly("@this");
|
||||
putEntryOnly("@thisx");
|
||||
putEntryOnly("@thisy");
|
||||
putEntryOnly("@links");
|
||||
putEntryOnly("@ipt");
|
||||
|
||||
putEntryOnly("sectionGeneral");
|
||||
|
||||
put("the end", null, false, true);
|
||||
//add default constants
|
||||
put("false", 0);
|
||||
put("true", 1);
|
||||
put("null", null);
|
||||
putEntry("false", 0);
|
||||
putEntry("true", 1);
|
||||
put("null", null, false, true);
|
||||
|
||||
//math
|
||||
put("@pi", Mathf.PI);
|
||||
put("π", Mathf.PI); //for the "cool" kids
|
||||
put("@e", Mathf.E);
|
||||
put("@degToRad", Mathf.degRad);
|
||||
put("@radToDeg", Mathf.radDeg);
|
||||
putEntry("@pi", Mathf.PI);
|
||||
put("π", Mathf.PI, false, true); //for the "cool" kids
|
||||
putEntry("@e", Mathf.E);
|
||||
putEntry("@degToRad", Mathf.degRad);
|
||||
putEntry("@radToDeg", Mathf.radDeg);
|
||||
|
||||
putEntryOnly("sectionMap");
|
||||
|
||||
//time
|
||||
varTime = put("@time", 0);
|
||||
varTick = put("@tick", 0);
|
||||
varSecond = put("@second", 0);
|
||||
varMinute = put("@minute", 0);
|
||||
varWave = put("@waveNumber", 0);
|
||||
varWaveTime = put("@waveTime", 0);
|
||||
varTime = putEntry("@time", 0);
|
||||
varTick = putEntry("@tick", 0);
|
||||
varSecond = putEntry("@second", 0);
|
||||
varMinute = putEntry("@minute", 0);
|
||||
varWave = putEntry("@waveNumber", 0);
|
||||
varWaveTime = putEntry("@waveTime", 0);
|
||||
|
||||
varMapW = putEntry("@mapw", 0);
|
||||
varMapH = putEntry("@maph", 0);
|
||||
|
||||
putEntryOnly("sectionNetwork");
|
||||
|
||||
varServer = putEntry("@server", 0, true);
|
||||
varClient = putEntry("@client", 0, true);
|
||||
|
||||
//privileged desynced client variables
|
||||
varClientLocale = putEntry("@clientLocale", null, true);
|
||||
varClientUnit = putEntry("@clientUnit", null, true);
|
||||
varClientName = putEntry("@clientName", null, true);
|
||||
varClientTeam = putEntry("@clientTeam", 0, true);
|
||||
varClientMobile = putEntry("@clientMobile", 0, true);
|
||||
|
||||
//special enums
|
||||
put("@ctrlProcessor", ctrlProcessor);
|
||||
@@ -104,6 +133,8 @@ public class GlobalVars{
|
||||
logicIdToContent = new UnlockableContent[ContentType.all.length][];
|
||||
contentIdToLogicId = new int[ContentType.all.length][];
|
||||
|
||||
putEntryOnly("sectionLookup");
|
||||
|
||||
Fi ids = Core.files.internal("logicids.dat");
|
||||
if(ids.exists()){
|
||||
//read logic ID mapping data (generated in ImagePacker)
|
||||
@@ -114,7 +145,7 @@ public class GlobalVars{
|
||||
contentIdToLogicId[ctype.ordinal()] = new int[Vars.content.getBy(ctype).size];
|
||||
|
||||
//store count constants
|
||||
put("@" + ctype.name() + "Count", amount);
|
||||
putEntry("@" + ctype.name() + "Count", amount);
|
||||
|
||||
for(int i = 0; i < amount; i++){
|
||||
String name = in.readUTF();
|
||||
@@ -147,6 +178,26 @@ public class GlobalVars{
|
||||
//wave state
|
||||
vars.items[varWave].numval = state.wave;
|
||||
vars.items[varWaveTime].numval = state.wavetime / 60f;
|
||||
|
||||
vars.items[varMapW].numval = world.width();
|
||||
vars.items[varMapH].numval = world.height();
|
||||
|
||||
//network
|
||||
vars.items[varServer].numval = (net.server() || !net.active()) ? 1 : 0;
|
||||
vars.items[varClient].numval = net.client() ? 1 : 0;
|
||||
|
||||
//client
|
||||
if(!net.server() && player != null){
|
||||
vars.items[varClientLocale].objval = player.locale();
|
||||
vars.items[varClientUnit].objval = player.unit();
|
||||
vars.items[varClientName].objval = player.name();
|
||||
vars.items[varClientTeam].numval = player.team().id;
|
||||
vars.items[varClientMobile].numval = mobile ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Seq<VarEntry> getEntries(){
|
||||
return varEntries;
|
||||
}
|
||||
|
||||
/** @return a piece of content based on its logic ID. This is not equivalent to content ID. */
|
||||
@@ -161,23 +212,35 @@ public class GlobalVars{
|
||||
return arr != null && content.id >= 0 && content.id < arr.length ? arr[content.id] : -1;
|
||||
}
|
||||
|
||||
/** @return a constant ID > 0 if there is a constant with this name, otherwise -1. */
|
||||
/**
|
||||
* @return a constant ID > 0 if there is a constant with this name, otherwise -1.
|
||||
* Attempt to get privileged variable id from non-privileged logic executor returns null constant id.
|
||||
*/
|
||||
public int get(String name){
|
||||
return namesToIds.get(name, -1);
|
||||
}
|
||||
|
||||
/** @return a constant variable by ID. ID is not bound checked and must be positive. */
|
||||
public Var get(int id){
|
||||
/**
|
||||
* @return a constant variable by ID. ID is not bound checked and must be positive.
|
||||
* Attempt to get privileged variable from non-privileged logic executor returns null constant
|
||||
*/
|
||||
public Var get(int id, boolean privileged){
|
||||
if(!privileged && privilegedIds.contains(id)) return vars.get(namesToIds.get("null"));
|
||||
return vars.items[id];
|
||||
}
|
||||
|
||||
/** Sets a global variable by an ID returned from put(). */
|
||||
public void set(int id, double value){
|
||||
get(id).numval = value;
|
||||
get(id, true).numval = value;
|
||||
}
|
||||
|
||||
/** Adds a constant value by name. */
|
||||
public int put(String name, Object value){
|
||||
public int put(String name, Object value, boolean privileged){
|
||||
return put(name, value, privileged, true);
|
||||
}
|
||||
|
||||
/** Adds a constant value by name. */
|
||||
public int put(String name, Object value, boolean privileged, boolean hidden){
|
||||
int existingIdx = namesToIds.get(name, -1);
|
||||
if(existingIdx != -1){ //don't overwrite existing vars (see #6910)
|
||||
Log.debug("Failed to add global logic variable '@', as it already exists.", name);
|
||||
@@ -195,7 +258,46 @@ public class GlobalVars{
|
||||
|
||||
int index = vars.size;
|
||||
namesToIds.put(name, index);
|
||||
if(privileged) privilegedIds.add(index);
|
||||
vars.add(var);
|
||||
|
||||
if(!hidden){
|
||||
varEntries.add(new VarEntry(index, name, "", "", privileged));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public int put(String name, Object value){
|
||||
return put(name, value, false);
|
||||
}
|
||||
|
||||
public int putEntry(String name, Object value){
|
||||
return put(name, value, false, false);
|
||||
}
|
||||
|
||||
public int putEntry(String name, Object value, boolean privileged){
|
||||
return put(name, value, privileged, false);
|
||||
}
|
||||
|
||||
public void putEntryOnly(String name){
|
||||
varEntries.add(new VarEntry(0, name, "", "", false));
|
||||
}
|
||||
|
||||
/** An entry that describes a variable for documentation purposes. This is *only* used inside UI for global variables. */
|
||||
public static class VarEntry{
|
||||
public int id;
|
||||
public String name, description, icon;
|
||||
public boolean privileged;
|
||||
|
||||
public VarEntry(int id, String name, String description, String icon, boolean privileged){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.icon = icon;
|
||||
this.privileged = privileged;
|
||||
}
|
||||
|
||||
public VarEntry(){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
61
core/src/mindustry/logic/GlobalVarsDialog.java
Normal file
61
core/src/mindustry/logic/GlobalVarsDialog.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
|
||||
public class GlobalVarsDialog extends BaseDialog{
|
||||
|
||||
public GlobalVarsDialog(){
|
||||
super("@logic.globals");
|
||||
|
||||
addCloseButton();
|
||||
shown(this::setup);
|
||||
onResize(this::setup);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
float prefWidth = Math.min(Core.graphics.getWidth() * 0.9f / Scl.scl(1f) - 240f, 600f);
|
||||
cont.clearChildren();
|
||||
|
||||
cont.pane(t -> {
|
||||
t.margin(10f).marginRight(16f);
|
||||
t.defaults().fillX().fillY();
|
||||
for(var entry : Vars.logicVars.getEntries()){
|
||||
|
||||
if(entry.name.startsWith("section")){
|
||||
Color color = Pal.accent;
|
||||
t.add("@lglobal." + entry.name).fillX().center().labelAlign(Align.center).colspan(4).color(color).padTop(4f).padBottom(2f).row();
|
||||
t.image(Tex.whiteui).height(4f).color(color).colspan(4).padBottom(8f).row();
|
||||
}else{
|
||||
Color varColor = Pal.gray;
|
||||
float stub = 8f, mul = 0.5f, pad = 4;
|
||||
|
||||
String desc = entry.description;
|
||||
if(desc == null || desc.isEmpty()){
|
||||
desc = Core.bundle.get("lglobal." + entry.name, "");
|
||||
}
|
||||
|
||||
String fdesc = desc;
|
||||
|
||||
t.add(new Image(Tex.whiteui, varColor.cpy().mul(mul))).width(stub);
|
||||
t.stack(new Image(Tex.whiteui, varColor), new Label(" " + entry.name + " ", Styles.outlineLabel)).padRight(pad);
|
||||
|
||||
t.add(new Image(Tex.whiteui, Pal.gray.cpy().mul(mul))).width(stub);
|
||||
t.table(Tex.pane, out -> out.add(fdesc).style(Styles.outlineLabel).width(prefWidth).padLeft(2).padRight(2).wrap()).padRight(pad);
|
||||
|
||||
t.row();
|
||||
|
||||
t.add().fillX().colspan(4).height(4).row();
|
||||
}
|
||||
}
|
||||
}).grow();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public enum LAccess{
|
||||
maxHealth,
|
||||
heat,
|
||||
shield,
|
||||
armor,
|
||||
efficiency,
|
||||
progress,
|
||||
timescale,
|
||||
@@ -29,6 +30,10 @@ public enum LAccess{
|
||||
y,
|
||||
shootX,
|
||||
shootY,
|
||||
cameraX,
|
||||
cameraY,
|
||||
cameraWidth,
|
||||
cameraHeight,
|
||||
size,
|
||||
dead,
|
||||
range,
|
||||
@@ -62,7 +67,7 @@ public enum LAccess{
|
||||
all = values(),
|
||||
senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class),
|
||||
controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class),
|
||||
settable = {x, y, rotation, team, flag, health, totalPower, payloadType};
|
||||
settable = {x, y, rotation, speed, armor, health, team, flag, totalPower, payloadType};
|
||||
|
||||
LAccess(String... params){
|
||||
this.params = params;
|
||||
|
||||
@@ -15,6 +15,7 @@ public class LAssembler{
|
||||
private static final int invalidNum = Integer.MIN_VALUE;
|
||||
|
||||
private int lastVar;
|
||||
private boolean privileged;
|
||||
/** Maps names to variable IDs. */
|
||||
public ObjectMap<String, BVar> vars = new ObjectMap<>();
|
||||
/** All instructions to be executed. */
|
||||
@@ -35,6 +36,7 @@ public class LAssembler{
|
||||
Seq<LStatement> st = read(data, privileged);
|
||||
|
||||
asm.instructions = st.map(l -> l.build(asm)).retainAll(l -> l != null).toArray(LInstruction.class);
|
||||
asm.privileged = privileged;
|
||||
return asm;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,13 @@ import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.MapObjectives.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.logic.LogicFx.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.blocks.logic.*;
|
||||
@@ -48,6 +51,7 @@ public class LExecutor{
|
||||
public Var[] vars = {};
|
||||
public Var counter;
|
||||
public int[] binds;
|
||||
public boolean yield;
|
||||
|
||||
public int iptIndex = -1;
|
||||
public LongSeq graphicsBuffer = new LongSeq();
|
||||
@@ -59,10 +63,14 @@ public class LExecutor{
|
||||
public boolean privileged = false;
|
||||
|
||||
//yes, this is a minor memory leak, but it's probably not significant enough to matter
|
||||
protected IntFloatMap unitTimeouts = new IntFloatMap();
|
||||
protected static IntFloatMap unitTimeouts = new IntFloatMap();
|
||||
//lookup variable by name, lazy init.
|
||||
protected ObjectIntMap<String> nameMap;
|
||||
|
||||
static{
|
||||
Events.on(ResetEvent.class, e -> unitTimeouts.clear());
|
||||
}
|
||||
|
||||
boolean timeoutDone(Unit unit, float delay){
|
||||
return Time.time >= unitTimeouts.get(unit.id) + delay;
|
||||
}
|
||||
@@ -122,7 +130,7 @@ public class LExecutor{
|
||||
|
||||
public Var var(int index){
|
||||
//global constants have variable IDs < 0, and they are fetched from the global constants object after being negated
|
||||
return index < 0 ? logicVars.get(-index) : vars[index];
|
||||
return index < 0 ? logicVars.get(-index, privileged) : vars[index];
|
||||
}
|
||||
|
||||
public @Nullable Var optionalVar(String name){
|
||||
@@ -178,11 +186,23 @@ public class LExecutor{
|
||||
return v.isobj ? v.objval != null ? 1 : 0 : invalid(v.numval) ? 0 : v.numval;
|
||||
}
|
||||
|
||||
/** Get num value from variable, convert null to NaN to handle it differently in some instructions */
|
||||
public double numOrNan(int index){
|
||||
Var v = var(index);
|
||||
return v.isobj ? v.objval != null ? 1 : Double.NaN : invalid(v.numval) ? 0 : v.numval;
|
||||
}
|
||||
|
||||
public float numf(int index){
|
||||
Var v = var(index);
|
||||
return v.isobj ? v.objval != null ? 1 : 0 : invalid(v.numval) ? 0 : (float)v.numval;
|
||||
}
|
||||
|
||||
/** Get float value from variable, convert null to NaN to handle it differently in some instructions */
|
||||
public float numfOrNan(int index){
|
||||
Var v = var(index);
|
||||
return v.isobj ? v.objval != null ? 1 : Float.NaN : invalid(v.numval) ? 0 : (float)v.numval;
|
||||
}
|
||||
|
||||
public int numi(int index){
|
||||
return (int)num(index);
|
||||
}
|
||||
@@ -446,7 +466,6 @@ public class LExecutor{
|
||||
case unbind -> {
|
||||
//TODO is this a good idea? will allocate
|
||||
unit.resetController();
|
||||
exec.setobj(varUnit, null);
|
||||
}
|
||||
case within -> {
|
||||
exec.setnum(p4, unit.within(x1, y1, d1) ? 1 : 0);
|
||||
@@ -893,8 +912,10 @@ public class LExecutor{
|
||||
|
||||
if(!v.constant){
|
||||
if(f.isobj){
|
||||
v.objval = f.objval;
|
||||
v.isobj = true;
|
||||
if(to != varCounter){
|
||||
v.objval = f.objval;
|
||||
v.isobj = true;
|
||||
}
|
||||
}else{
|
||||
v.numval = invalid(f.numval) ? 0 : f.numval;
|
||||
v.isobj = false;
|
||||
@@ -976,12 +997,6 @@ public class LExecutor{
|
||||
//graphics on headless servers are useless.
|
||||
if(Vars.headless || exec.graphicsBuffer.size >= maxGraphicsBuffer) return;
|
||||
|
||||
int num1 = exec.numi(p1);
|
||||
|
||||
if(type == LogicDisplay.commandImage){
|
||||
num1 = exec.obj(p1) instanceof UnlockableContent u ? u.iconId : 0;
|
||||
}
|
||||
|
||||
//explicitly unpack colorPack, it's pre-processed here
|
||||
if(type == LogicDisplay.commandColorPack){
|
||||
double packed = exec.num(x);
|
||||
@@ -993,7 +1008,63 @@ public class LExecutor{
|
||||
a = ((value & 0x000000ff));
|
||||
|
||||
exec.graphicsBuffer.add(DisplayCmd.get(LogicDisplay.commandColor, pack(r), pack(g), pack(b), pack(a), 0, 0));
|
||||
}else if(type == LogicDisplay.commandPrint){
|
||||
CharSequence str = exec.textBuffer;
|
||||
|
||||
if(str.length() > 0){
|
||||
var data = Fonts.logic.getData();
|
||||
int advance = (int)data.spaceXadvance, lineHeight = (int)data.lineHeight;
|
||||
|
||||
int xOffset, yOffset;
|
||||
int align = p1; //p1 is not a variable, it's a raw align value. what a massive hack
|
||||
|
||||
int maxWidth = 0, lines = 1, lineWidth = 0;
|
||||
for(int i = 0; i < str.length(); i++){
|
||||
char next = str.charAt(i);
|
||||
if(next == '\n'){
|
||||
maxWidth = Math.max(maxWidth, lineWidth);
|
||||
lineWidth = 0;
|
||||
lines ++;
|
||||
}else{
|
||||
lineWidth ++;
|
||||
}
|
||||
}
|
||||
maxWidth = Math.max(maxWidth, lineWidth);
|
||||
|
||||
float
|
||||
width = maxWidth * advance,
|
||||
height = lines * lineHeight,
|
||||
ha = ((Align.isLeft(align) ? -1f : 0f) + 1f + (Align.isRight(align) ? 1f : 0f))/2f,
|
||||
va = ((Align.isBottom(align) ? -1f : 0f) + 1f + (Align.isTop(align) ? 1f : 0f))/2f;
|
||||
|
||||
xOffset = -(int)(width * ha);
|
||||
yOffset = -(int)(height * va) + (lines - 1) * lineHeight;
|
||||
|
||||
|
||||
int curX = exec.numi(x), curY = exec.numi(y);
|
||||
for(int i = 0; i < str.length(); i++){
|
||||
char next = str.charAt(i);
|
||||
if(next == '\n'){
|
||||
//move Y down when newline is encountered
|
||||
curY -= lineHeight;
|
||||
curX = exec.numi(x); //reset
|
||||
continue;
|
||||
}
|
||||
if(Fonts.logic.getData().hasGlyph(next)){
|
||||
exec.graphicsBuffer.add(DisplayCmd.get(LogicDisplay.commandPrint, packSign(curX + xOffset), packSign(curY + yOffset), next, 0, 0, 0));
|
||||
}
|
||||
curX += advance;
|
||||
}
|
||||
|
||||
exec.textBuffer.setLength(0);
|
||||
}
|
||||
}else{
|
||||
int num1 = exec.numi(p1);
|
||||
|
||||
if(type == LogicDisplay.commandImage){
|
||||
num1 = exec.obj(p1) instanceof UnlockableContent u ? u.iconId : 0;
|
||||
}
|
||||
|
||||
//add graphics calls, cap graphics buffer size
|
||||
exec.graphicsBuffer.add(DisplayCmd.get(type, packSign(exec.numi(x)), packSign(exec.numi(y)), packSign(num1), packSign(exec.numi(p2)), packSign(exec.numi(p3)), packSign(exec.numi(p4))));
|
||||
}
|
||||
@@ -1079,6 +1150,55 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class FormatI implements LInstruction{
|
||||
public int value;
|
||||
|
||||
public FormatI(int value){
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
FormatI(){}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
|
||||
if(exec.textBuffer.length() >= maxTextBuffer) return;
|
||||
|
||||
int placeholderIndex = -1;
|
||||
int placeholderNumber = 10;
|
||||
|
||||
for(int i = 0; i < exec.textBuffer.length(); i++){
|
||||
if(exec.textBuffer.charAt(i) == '{' && exec.textBuffer.length() - i > 2){
|
||||
char numChar = exec.textBuffer.charAt(i + 1);
|
||||
|
||||
if(numChar >= '0' && numChar <= '9' && exec.textBuffer.charAt(i + 2) == '}'){
|
||||
if(numChar - '0' < placeholderNumber){
|
||||
placeholderNumber = numChar - '0';
|
||||
placeholderIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(placeholderIndex == -1) return;
|
||||
|
||||
//this should avoid any garbage allocation
|
||||
Var v = exec.var(value);
|
||||
if(v.isobj && value != 0){
|
||||
String strValue = PrintI.toString(v.objval);
|
||||
|
||||
exec.textBuffer.replace(placeholderIndex, placeholderIndex + 3, strValue);
|
||||
}else{
|
||||
//display integer version when possible
|
||||
if(Math.abs(v.numval - (long)v.numval) < 0.00001){
|
||||
exec.textBuffer.replace(placeholderIndex, placeholderIndex + 3, (long)v.numval + "");
|
||||
}else{
|
||||
exec.textBuffer.replace(placeholderIndex, placeholderIndex + 3, v.numval + "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PrintFlushI implements LInstruction{
|
||||
public int target;
|
||||
|
||||
@@ -1144,7 +1264,6 @@ public class LExecutor{
|
||||
public int value;
|
||||
|
||||
public float curTime;
|
||||
public long frameId;
|
||||
|
||||
public WaitI(int value){
|
||||
this.value = value;
|
||||
@@ -1160,11 +1279,8 @@ public class LExecutor{
|
||||
}else{
|
||||
//skip back to self.
|
||||
exec.var(varCounter).numval --;
|
||||
}
|
||||
|
||||
if(state.updateId != frameId){
|
||||
exec.yield = true;
|
||||
curTime += Time.delta / 60f;
|
||||
frameId = state.updateId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1175,6 +1291,7 @@ public class LExecutor{
|
||||
public void run(LExecutor exec){
|
||||
//skip back to self.
|
||||
exec.var(varCounter).numval --;
|
||||
exec.yield = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,13 +1406,20 @@ public class LExecutor{
|
||||
exec.setobj(result, i < 0 || i >= builds.size ? null : builds.get(i));
|
||||
}
|
||||
}
|
||||
case unitCount -> exec.setnum(result, data.units.size);
|
||||
case unitCount -> {
|
||||
UnitType type = exec.obj(extra) instanceof UnitType u ? u : null;
|
||||
if(type == null){
|
||||
exec.setnum(result, data.units.size);
|
||||
}else{
|
||||
exec.setnum(result, data.unitsByType[type.id].size);
|
||||
}
|
||||
}
|
||||
case coreCount -> exec.setnum(result, data.cores.size);
|
||||
case playerCount -> exec.setnum(result, data.players.size);
|
||||
case buildCount -> {
|
||||
Block block = exec.obj(extra) instanceof Block b ? b : null;
|
||||
if(block == null){
|
||||
exec.setobj(result, null);
|
||||
exec.setnum(result, data.buildings.size);
|
||||
}else{
|
||||
exec.setnum(result, data.getBuildings(block).size);
|
||||
}
|
||||
@@ -1485,6 +1609,23 @@ public class LExecutor{
|
||||
}
|
||||
case ambientLight -> state.rules.ambientLight.fromDouble(exec.num(value));
|
||||
case solarMultiplier -> state.rules.solarMultiplier = Math.max(exec.numf(value), 0f);
|
||||
case ban -> {
|
||||
Object cont = exec.obj(value);
|
||||
if(cont instanceof Block b){
|
||||
// Rebuild PlacementFragment if anything has changed
|
||||
if(state.rules.bannedBlocks.add(b) && !headless) ui.hudfrag.blockfrag.rebuild();
|
||||
}else if(cont instanceof UnitType u){
|
||||
state.rules.bannedUnits.add(u);
|
||||
}
|
||||
}
|
||||
case unban -> {
|
||||
Object cont = exec.obj(value);
|
||||
if(cont instanceof Block b){
|
||||
if(state.rules.bannedBlocks.remove(b) && !headless) ui.hudfrag.blockfrag.rebuild();
|
||||
}else if(cont instanceof UnitType u){
|
||||
state.rules.bannedUnits.remove(u);
|
||||
}
|
||||
}
|
||||
case unitHealth, unitBuildSpeed, unitCost, unitDamage, blockHealth, blockDamage, buildSpeed, rtsMinSquad, rtsMinWeight -> {
|
||||
Team team = exec.team(p1);
|
||||
if(team != null){
|
||||
@@ -1555,11 +1696,12 @@ public class LExecutor{
|
||||
|
||||
public static class FlushMessageI implements LInstruction{
|
||||
public MessageType type = MessageType.announce;
|
||||
public int duration;
|
||||
public int duration, outSuccess;
|
||||
|
||||
public FlushMessageI(MessageType type, int duration){
|
||||
public FlushMessageI(MessageType type, int duration, int outSuccess){
|
||||
this.type = type;
|
||||
this.duration = duration;
|
||||
this.outSuccess = outSuccess;
|
||||
}
|
||||
|
||||
public FlushMessageI(){
|
||||
@@ -1567,16 +1709,20 @@ public class LExecutor{
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(headless && type != MessageType.mission) return;
|
||||
//set default to success
|
||||
exec.setnum(outSuccess, 1);
|
||||
if(headless && type != MessageType.mission) {
|
||||
exec.textBuffer.setLength(0);
|
||||
return;
|
||||
}
|
||||
|
||||
//skip back to self until possible
|
||||
//TODO this is guaranteed desync on servers - I don't see a good solution
|
||||
if(
|
||||
type == MessageType.announce && ui.hasAnnouncement() ||
|
||||
type == MessageType.notify && ui.hudfrag.hasToast() ||
|
||||
type == MessageType.toast && ui.hasAnnouncement()
|
||||
){
|
||||
exec.var(varCounter).numval --;
|
||||
//set outSuccess=false to let user retry.
|
||||
exec.setnum(outSuccess, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1630,9 +1776,9 @@ public class LExecutor{
|
||||
}
|
||||
|
||||
public static class ExplosionI implements LInstruction{
|
||||
public int team, x, y, radius, damage, air, ground, pierce;
|
||||
public int team, x, y, radius, damage, air, ground, pierce, effect;
|
||||
|
||||
public ExplosionI(int team, int x, int y, int radius, int damage, int air, int ground, int pierce){
|
||||
public ExplosionI(int team, int x, int y, int radius, int damage, int air, int ground, int pierce, int effect){
|
||||
this.team = team;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -1641,6 +1787,7 @@ public class LExecutor{
|
||||
this.air = air;
|
||||
this.ground = ground;
|
||||
this.pierce = pierce;
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public ExplosionI(){
|
||||
@@ -1652,19 +1799,21 @@ public class LExecutor{
|
||||
|
||||
Team t = exec.team(team);
|
||||
//note that there is a radius cap
|
||||
Call.logicExplosion(t, World.unconv(exec.numf(x)), World.unconv(exec.numf(y)), World.unconv(Math.min(exec.numf(radius), 100)), exec.numf(damage), exec.bool(air), exec.bool(ground), exec.bool(pierce));
|
||||
Call.logicExplosion(t, World.unconv(exec.numf(x)), World.unconv(exec.numf(y)), World.unconv(Math.min(exec.numf(radius), 100)), exec.numf(damage), exec.bool(air), exec.bool(ground), exec.bool(pierce), exec.bool(effect));
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void logicExplosion(Team team, float x, float y, float radius, float damage, boolean air, boolean ground, boolean pierce){
|
||||
public static void logicExplosion(Team team, float x, float y, float radius, float damage, boolean air, boolean ground, boolean pierce, boolean effect){
|
||||
if(damage < 0f) return;
|
||||
|
||||
Damage.damage(team, x, y, radius, damage, pierce, air, ground);
|
||||
if(pierce){
|
||||
Fx.spawnShockwave.at(x, y, World.conv(radius));
|
||||
}else{
|
||||
Fx.dynamicExplosion.at(x, y, World.conv(radius) / 8f);
|
||||
if(effect){
|
||||
if(pierce){
|
||||
Fx.spawnShockwave.at(x, y, World.conv(radius));
|
||||
}else{
|
||||
Fx.dynamicExplosion.at(x, y, World.conv(radius) / 8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1856,5 +2005,148 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetMarkerI implements LInstruction{
|
||||
public LMarkerControl type = LMarkerControl.pos;
|
||||
public int id, p1, p2, p3;
|
||||
|
||||
public SetMarkerI(LMarkerControl type, int id, int p1, int p2, int p3){
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.p3 = p3;
|
||||
}
|
||||
|
||||
public SetMarkerI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(type == LMarkerControl.remove){
|
||||
state.markers.remove(exec.numi(id));
|
||||
}else{
|
||||
var marker = state.markers.get(exec.numi(id));
|
||||
if(marker == null) return;
|
||||
|
||||
if(type == LMarkerControl.flushText){
|
||||
marker.setText(exec.textBuffer.toString(), exec.bool(p1));
|
||||
exec.textBuffer.setLength(0);
|
||||
}else if(type == LMarkerControl.texture){
|
||||
if(exec.bool(p1)){
|
||||
marker.setTexture(exec.textBuffer.toString());
|
||||
exec.textBuffer.setLength(0);
|
||||
}else{
|
||||
marker.setTexture(PrintI.toString(exec.obj(p2)));
|
||||
}
|
||||
}else{
|
||||
marker.control(type, exec.numOrNan(p1), exec.numOrNan(p2), exec.numOrNan(p3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MakeMarkerI implements LInstruction{
|
||||
//TODO arbitrary number
|
||||
public static final int maxMarkers = 20000;
|
||||
|
||||
public String type = "shape";
|
||||
public int id, x, y, replace;
|
||||
|
||||
public MakeMarkerI(String type, int id, int x, int y, int replace){
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.replace = replace;
|
||||
}
|
||||
|
||||
public MakeMarkerI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
var cons = MapObjectives.markerNameToType.get(type);
|
||||
|
||||
if(cons != null && state.markers.size() < maxMarkers){
|
||||
int mid = exec.numi(id);
|
||||
if(exec.bool(replace) || !state.markers.has(mid)){
|
||||
var marker = cons.get();
|
||||
marker.control(LMarkerControl.pos, exec.num(x), exec.num(y), 0);
|
||||
state.markers.add(mid, marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, variants = Variant.both, unreliable = true)
|
||||
public static void createMarker(int id, ObjectiveMarker marker){
|
||||
state.markers.add(id, marker);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, variants = Variant.both, unreliable = true)
|
||||
public static void removeMarker(int id){
|
||||
state.markers.remove(id);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, variants = Variant.both, unreliable = true)
|
||||
public static void updateMarker(int id, LMarkerControl control, double p1, double p2, double p3){
|
||||
var marker = state.markers.get(id);
|
||||
if(marker != null){
|
||||
marker.control(control, p1, p2, p3);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, variants = Variant.both, unreliable = true)
|
||||
public static void updateMarkerText(int id, LMarkerControl type, boolean fetch, String text){
|
||||
var marker = state.markers.get(id);
|
||||
if(marker != null){
|
||||
if(type == LMarkerControl.flushText){
|
||||
marker.setText(text, fetch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, variants = Variant.both, unreliable = true)
|
||||
public static void updateMarkerTexture(int id, String textureName){
|
||||
var marker = state.markers.get(id);
|
||||
if(marker != null){
|
||||
marker.setTexture(textureName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocalePrintI implements LInstruction{
|
||||
public int name;
|
||||
|
||||
public LocalePrintI(int name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public LocalePrintI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(exec.textBuffer.length() >= maxTextBuffer) return;
|
||||
|
||||
//this should avoid any garbage allocation
|
||||
Var v = exec.var(name);
|
||||
if(v.isobj){
|
||||
String name = PrintI.toString(v.objval);
|
||||
|
||||
String strValue;
|
||||
|
||||
if(mobile){
|
||||
strValue = state.mapLocales.containsProperty(name + ".mobile") ?
|
||||
state.mapLocales.getProperty(name + ".mobile") :
|
||||
state.mapLocales.getProperty(name);
|
||||
}else{
|
||||
strValue = state.mapLocales.getProperty(name);
|
||||
}
|
||||
|
||||
exec.textBuffer.append(strValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
||||
33
core/src/mindustry/logic/LMarkerControl.java
Normal file
33
core/src/mindustry/logic/LMarkerControl.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package mindustry.logic;
|
||||
|
||||
public enum LMarkerControl{
|
||||
remove,
|
||||
world("true/false"),
|
||||
minimap("true/false"),
|
||||
autoscale("true/false"),
|
||||
pos("x", "y"),
|
||||
endPos("x", "y"),
|
||||
drawLayer("layer"),
|
||||
color("color"),
|
||||
radius("radius"),
|
||||
stroke("stroke"),
|
||||
rotation("rotation"),
|
||||
shape("sides", "fill", "outline"),
|
||||
flushText("fetch"),
|
||||
fontSize("size"),
|
||||
textHeight("height"),
|
||||
labelFlags("background", "outline"),
|
||||
texture("printFlush", "name"),
|
||||
textureSize("width", "height"),
|
||||
posi("index", "x", "y"),
|
||||
uvi("index", "x", "y"),
|
||||
colori("index", "color");
|
||||
|
||||
public final String[] params;
|
||||
|
||||
public static final LMarkerControl[] all = values();
|
||||
|
||||
LMarkerControl(String... params){
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package mindustry.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.*;
|
||||
import arc.scene.actions.*;
|
||||
@@ -10,10 +11,12 @@ import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.LCanvas.*;
|
||||
import mindustry.logic.LExecutor.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static mindustry.Vars.ui;
|
||||
import static mindustry.logic.LCanvas.*;
|
||||
|
||||
/**
|
||||
@@ -108,6 +111,35 @@ public abstract class LStatement{
|
||||
return field(table, value, setter).width(85f).padRight(10).left();
|
||||
}
|
||||
|
||||
/** Puts the text and field in one table, taking up one cell. */
|
||||
protected Cell<TextField> fieldst(Table table, String desc, String value, Cons<String> setter){
|
||||
Cell[] result = {null};
|
||||
table.table(t -> {
|
||||
t.setColor(table.color);
|
||||
t.add(desc).padLeft(10).left().self(this::param);
|
||||
result[0] = field(t, value, setter).width(85f).padRight(10).left();
|
||||
});
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
/** Adds color edit button */
|
||||
protected Cell<Button> col(Table table, String value, Cons<Color> setter){
|
||||
return table.button(b -> {
|
||||
b.image(Icon.pencilSmall);
|
||||
b.clicked(() -> {
|
||||
Color current = Pal.accent.cpy();
|
||||
if(value.startsWith("%")){
|
||||
try{
|
||||
current = Color.valueOf(value.substring(1));
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
|
||||
ui.picker.show(current, setter);
|
||||
});
|
||||
}, Styles.logict, () -> {}).size(40f).padLeft(-11).color(table.color);
|
||||
}
|
||||
|
||||
protected Cell<TextField> fields(Table table, String value, Cons<String> setter){
|
||||
return field(table, value, setter).width(85f);
|
||||
}
|
||||
@@ -132,7 +164,7 @@ public abstract class LStatement{
|
||||
if(p instanceof Enum e){
|
||||
tooltip(c, e);
|
||||
}
|
||||
}).checked(current == p).group(group));
|
||||
}).checked(current.equals(p)).group(group));
|
||||
|
||||
if(++i % cols == 0) t.row();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import arc.graphics.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.LCanvas.*;
|
||||
@@ -120,6 +122,20 @@ public class LStatements{
|
||||
|
||||
@RegisterStatement("draw")
|
||||
public static class DrawStatement extends LStatement{
|
||||
static final String[] aligns = {"center", "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"};
|
||||
//yes, boxing Integer is gross but this is easier to construct and Integers <128 don't allocate anyway
|
||||
static final ObjectMap<String, Integer> nameToAlign = ObjectMap.of(
|
||||
"center", Align.center,
|
||||
"top", Align.top,
|
||||
"bottom", Align.bottom,
|
||||
"left", Align.left,
|
||||
"right", Align.right,
|
||||
"topLeft", Align.topLeft,
|
||||
"topRight", Align.topRight,
|
||||
"bottomLeft", Align.bottomLeft,
|
||||
"bottomRight", Align.bottomRight
|
||||
);
|
||||
|
||||
public GraphicsType type = GraphicsType.clear;
|
||||
public String x = "0", y = "0", p1 = "0", p2 = "0", p3 = "0", p4 = "0";
|
||||
|
||||
@@ -146,6 +162,11 @@ public class LStatements{
|
||||
p2 = "32";
|
||||
p3 = "0";
|
||||
}
|
||||
|
||||
if(type == GraphicsType.print){
|
||||
p1 = "bottomLeft";
|
||||
}
|
||||
|
||||
rebuild(table);
|
||||
}, 2, cell -> cell.size(100, 50)));
|
||||
}, Styles.logict, () -> {}).size(90, 40).color(table.color).left().padLeft(2);
|
||||
@@ -173,6 +194,10 @@ public class LStatements{
|
||||
}
|
||||
case col -> {
|
||||
fields(s, "color", x, v -> x = v).width(144f);
|
||||
col(s, x, res -> {
|
||||
x = "%" + res.toString().substring(0, res.a >= 1f ? 6 : 8);
|
||||
build(table);
|
||||
});
|
||||
}
|
||||
case stroke -> {
|
||||
s.add().width(4);
|
||||
@@ -220,14 +245,21 @@ public class LStatements{
|
||||
row(s);
|
||||
fields(s, "rotation", p3, v -> p3 = v);
|
||||
}
|
||||
//TODO
|
||||
/*
|
||||
case character -> {
|
||||
case print -> {
|
||||
fields(s, "x", x, v -> x = v);
|
||||
fields(s, "y", y, v -> y = v);
|
||||
|
||||
row(s);
|
||||
fields(s, "char", p1, v -> p1 = v);
|
||||
}*/
|
||||
|
||||
s.add("align ");
|
||||
|
||||
s.button(b -> {
|
||||
b.label(() -> nameToAlign.containsKey(p1) ? p1 : "bottomLeft");
|
||||
b.clicked(() -> showSelect(b, aligns, p1, t -> {
|
||||
p1 = t;
|
||||
}, 2, cell -> cell.size(165, 50)));
|
||||
}, Styles.logict, () -> {}).size(165, 40).color(s.color).left().padLeft(2);
|
||||
}
|
||||
}
|
||||
}).expand().left();
|
||||
}
|
||||
@@ -242,7 +274,8 @@ public class LStatements{
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new DrawI((byte)type.ordinal(), 0, builder.var(x), builder.var(y), builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4));
|
||||
return new DrawI((byte)type.ordinal(), 0, builder.var(x), builder.var(y),
|
||||
type == GraphicsType.print ? nameToAlign.get(p1, Align.bottomLeft) : builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -272,6 +305,27 @@ public class LStatements{
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("format")
|
||||
public static class FormatStatement extends LStatement{
|
||||
public String value = "\"frog\"";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
field(table, value, str -> value = str).width(0f).growX().padRight(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new FormatI(builder.var(value));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.io;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("drawflush")
|
||||
public static class DrawFlushStatement extends LStatement{
|
||||
public String target = "display1";
|
||||
@@ -1392,6 +1446,11 @@ public class LStatements{
|
||||
row(table);
|
||||
field(table, value, s -> value = s);
|
||||
}
|
||||
case ban, unban -> {
|
||||
table.add(" block/unit ");
|
||||
|
||||
field(table, value, s -> value = s);
|
||||
}
|
||||
default -> {
|
||||
table.add(" = ");
|
||||
|
||||
@@ -1419,7 +1478,7 @@ public class LStatements{
|
||||
@RegisterStatement("message")
|
||||
public static class FlushMessageStatement extends LStatement{
|
||||
public MessageType type = MessageType.announce;
|
||||
public String duration = "3";
|
||||
public String duration = "3", outSuccess = "success";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
@@ -1438,12 +1497,14 @@ public class LStatements{
|
||||
}, Styles.logict, () -> {}).size(160f, 40f).padLeft(2).color(table.color);
|
||||
|
||||
switch(type){
|
||||
case announce, toast -> {
|
||||
case announce, toast -> {
|
||||
table.add(" for ");
|
||||
fields(table, duration, str -> duration = str);
|
||||
table.add(" secs ");
|
||||
}
|
||||
}
|
||||
table.add(" success ");
|
||||
fields(table, outSuccess, str -> outSuccess = str);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1453,7 +1514,7 @@ public class LStatements{
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new FlushMessageI(type, builder.var(duration));
|
||||
return new FlushMessageI(type, builder.var(duration), builder.var(outSuccess));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1546,22 +1607,10 @@ public class LStatements{
|
||||
if(entry.color){
|
||||
fields(table, "color", color, str -> color = str).width(120f);
|
||||
|
||||
table.button(b -> {
|
||||
b.image(Icon.pencilSmall);
|
||||
b.clicked(() -> {
|
||||
Color current = Pal.accent.cpy();
|
||||
if(color.startsWith("%")){
|
||||
try{
|
||||
current = Color.valueOf(color.substring(1));
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
|
||||
ui.picker.show(current, result -> {
|
||||
color = "%" + result.toString().substring(0, result.a >= 1f ? 6 : 8);
|
||||
build(table);
|
||||
});
|
||||
});
|
||||
}, Styles.logict, () -> {}).size(40f).padLeft(-11).color(table.color);
|
||||
col(table, color, res -> {
|
||||
color = "%" + res.toString().substring(0, res.a >= 1f ? 6 : 8);
|
||||
build(table);
|
||||
});
|
||||
}
|
||||
|
||||
row(table);
|
||||
@@ -1594,7 +1643,7 @@ public class LStatements{
|
||||
|
||||
@RegisterStatement("explosion")
|
||||
public static class ExplosionStatement extends LStatement{
|
||||
public String team = "@crux", x = "0", y = "0", radius = "5", damage = "50", air = "true", ground = "true", pierce = "false";
|
||||
public String team = "@crux", x = "0", y = "0", radius = "5", damage = "50", air = "true", ground = "true", pierce = "false", effect = "true";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
@@ -1609,6 +1658,8 @@ public class LStatements{
|
||||
row(table);
|
||||
fields(table, "ground", ground, str -> ground = str);
|
||||
fields(table, "pierce", pierce, str -> pierce = str);
|
||||
table.row();
|
||||
fields(table, "effect", effect, str -> effect = str);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1618,7 +1669,7 @@ public class LStatements{
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler b){
|
||||
return new ExplosionI(b.var(team), b.var(x), b.var(y), b.var(radius), b.var(damage), b.var(air), b.var(ground), b.var(pierce));
|
||||
return new ExplosionI(b.var(team), b.var(x), b.var(y), b.var(radius), b.var(damage), b.var(air), b.var(ground), b.var(pierce), b.var(effect));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1689,7 +1740,7 @@ public class LStatements{
|
||||
fields(table, index, i -> index = i);
|
||||
}
|
||||
|
||||
if(type == FetchType.buildCount || type == FetchType.build){
|
||||
if(type == FetchType.buildCount || type == FetchType.build || type == FetchType.unitCount){
|
||||
row(table);
|
||||
|
||||
fields(table, "block", extra, i -> extra = i);
|
||||
@@ -1912,4 +1963,162 @@ public class LStatements{
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("setmarker")
|
||||
public static class SetMarkerStatement extends LStatement{
|
||||
public LMarkerControl type = LMarkerControl.pos;
|
||||
public String id = "0", p1 = "0", p2 = "0", p3 = "0";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
rebuild(table);
|
||||
}
|
||||
|
||||
void rebuild(Table table){
|
||||
table.clearChildren();
|
||||
|
||||
table.add("set");
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> type.name());
|
||||
b.clicked(() -> showSelect(b, LMarkerControl.all, type, t -> {
|
||||
type = t;
|
||||
rebuild(table);
|
||||
}, 3, cell -> cell.size(140, 50)));
|
||||
}, Styles.logict, () -> {}).size(190, 40).color(table.color).left().padLeft(2);
|
||||
|
||||
row(table);
|
||||
|
||||
fieldst(table, "of id#", id, str -> id = str);
|
||||
|
||||
//Q: why don't you just use arrays for this?
|
||||
//A: arrays aren't as easy to serialize so the code generator doesn't handle them
|
||||
for(int f = 0; f < type.params.length; f++){
|
||||
int i = f;
|
||||
|
||||
table.table(t -> {
|
||||
t.setColor(table.color);
|
||||
|
||||
String value = i == 0 ? p1 : i == 1 ? p2 : p3;
|
||||
Cons<String> setter = i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : v -> p3 = v;
|
||||
|
||||
fields(t, type.params[i], value, setter).width(100f);
|
||||
|
||||
if(type == LMarkerControl.color || (type == LMarkerControl.colori && i == 1)){
|
||||
col(t, value, res -> {
|
||||
setter.get("%" + res.toString().substring(0, res.a >= 1f ? 6 : 8));
|
||||
build(table);
|
||||
});
|
||||
}else if(type == LMarkerControl.drawLayer){
|
||||
t.button(b -> {
|
||||
b.image(Icon.pencilSmall);
|
||||
b.clicked(() -> showSelectTable(b, (o, hide) -> {
|
||||
o.row();
|
||||
o.table(s -> {
|
||||
s.left();
|
||||
for(var field : Layer.class.getFields()){
|
||||
float layer = Reflect.get(field);
|
||||
s.button(field.getName() + " = " + layer, Styles.logicTogglet, () -> {
|
||||
p1 = Float.toString(layer);
|
||||
rebuild(table);
|
||||
hide.run();
|
||||
}).size(240f, 40f).row();
|
||||
}
|
||||
}).width(240f).left();
|
||||
}));
|
||||
}, Styles.logict, () -> {}).size(40f).padLeft(-11).color(table.color);
|
||||
}
|
||||
});
|
||||
|
||||
if(i == 0) row(table);
|
||||
if(i == 2) table.row();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new SetMarkerI(type, builder.var(id), builder.var(p1), builder.var(p2), builder.var(p3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("makemarker")
|
||||
public static class MakeMarkerStatement extends LStatement{
|
||||
public String type = "shape", id = "0", x = "0", y = "0", replace = "true";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
table.clearChildren();
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> type);
|
||||
|
||||
b.clicked(() -> showSelect(b, MapObjectives.allMarkerTypeNames.toArray(String.class), type, t -> {
|
||||
type = t;
|
||||
build(table);
|
||||
}, 2, cell -> cell.size(160, 50)));
|
||||
}, Styles.logict, () -> {}).size(190, 40).color(table.color).left().padLeft(2);
|
||||
|
||||
fieldst(table, "id", id, str -> id = str);
|
||||
|
||||
row(table);
|
||||
|
||||
fieldst(table, "x", x, v -> x = v);
|
||||
|
||||
fieldst(table, "y", y, v -> y = v);
|
||||
|
||||
row(table);
|
||||
|
||||
fieldst(table, "replace", replace, v -> replace = v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new MakeMarkerI(type, builder.var(id), builder.var(x), builder.var(y), builder.var(replace));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("localeprint")
|
||||
public static class LocalePrintStatement extends LStatement{
|
||||
public String value = "\"name\"";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
field(table, value, str -> value = str).width(0f).growX().padRight(3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new LocalePrintI(builder.var(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public class LogicDialog extends BaseDialog{
|
||||
Cons<String> consumer = s -> {};
|
||||
boolean privileged;
|
||||
@Nullable LExecutor executor;
|
||||
GlobalVarsDialog globalsDialog = new GlobalVarsDialog();
|
||||
|
||||
public LogicDialog(){
|
||||
super("logic");
|
||||
@@ -51,7 +52,7 @@ public class LogicDialog extends BaseDialog{
|
||||
add(buttons).growX().name("canvas");
|
||||
}
|
||||
|
||||
private Color typeColor(Var s, Color color){
|
||||
public static Color typeColor(Var s, Color color){
|
||||
return color.set(
|
||||
!s.isobj ? Pal.place :
|
||||
s.objval == null ? Color.darkGray :
|
||||
@@ -65,7 +66,7 @@ public class LogicDialog extends BaseDialog{
|
||||
);
|
||||
}
|
||||
|
||||
private String typeName(Var s){
|
||||
public static String typeName(Var s){
|
||||
return
|
||||
!s.isobj ? "number" :
|
||||
s.objval == null ? "null" :
|
||||
@@ -178,6 +179,8 @@ public class LogicDialog extends BaseDialog{
|
||||
});
|
||||
|
||||
dialog.addCloseButton();
|
||||
dialog.buttons.button("@logic.globals", Icon.list, () -> globalsDialog.show()).size(210f, 64f);
|
||||
|
||||
dialog.show();
|
||||
}).name("variables").disabled(b -> executor == null || executor.vars.length == 0);
|
||||
|
||||
|
||||
@@ -57,6 +57,12 @@ public class LogicFx{
|
||||
return map.get(name);
|
||||
}
|
||||
|
||||
/** Adds an effect entry to the map. */
|
||||
public static void add(String name, EffectEntry entry){
|
||||
entry.name = name;
|
||||
map.put(name, entry);
|
||||
}
|
||||
|
||||
public static String[] all(){
|
||||
return map.orderedKeys().toArray(String.class);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ public enum LogicRule{
|
||||
lighting,
|
||||
ambientLight,
|
||||
solarMultiplier,
|
||||
ban,
|
||||
unban,
|
||||
|
||||
//team specific
|
||||
buildSpeed,
|
||||
|
||||
Reference in New Issue
Block a user