WIP logic particle effect instruction
This commit is contained in:
@@ -2,6 +2,7 @@ package mindustry.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.files.*;
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
@@ -81,6 +82,13 @@ public class GlobalVars{
|
||||
}
|
||||
}
|
||||
|
||||
for(var entry : Colors.getColors().entries()){
|
||||
//ignore uppercase variants, they are duplicates
|
||||
if(Character.isUpperCase(entry.key.charAt(0))) continue;
|
||||
|
||||
put("@color" + Strings.capitalize(entry.key), entry.value.toDoubleBits());
|
||||
}
|
||||
|
||||
//used as a special value for any environmental solid block
|
||||
put("@solid", Blocks.stoneWall);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import mindustry.entities.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.logic.LogicFx.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
@@ -122,6 +123,11 @@ public class LExecutor{
|
||||
return index < 0 ? logicVars.get(-index) : vars[index];
|
||||
}
|
||||
|
||||
/** @return a Var from this processor, never a global constant. May be null if out of bounds. */
|
||||
public @Nullable Var optionalVar(int index){
|
||||
return index < 0 || index >= vars.length ? null : vars[index];
|
||||
}
|
||||
|
||||
public @Nullable Building building(int index){
|
||||
Object o = var(index).objval;
|
||||
return var(index).isobj && o instanceof Building building ? building : null;
|
||||
@@ -203,6 +209,9 @@ public class LExecutor{
|
||||
public Object objval;
|
||||
public double numval;
|
||||
|
||||
//ms timestamp for when this was last synced; used in the sync instruction
|
||||
public long syncTime;
|
||||
|
||||
public Var(String name){
|
||||
this.name = name;
|
||||
}
|
||||
@@ -1557,6 +1566,35 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class EffectI implements LInstruction{
|
||||
public EffectEntry type;
|
||||
public int x, y, rotation, color, data;
|
||||
|
||||
public EffectI(EffectEntry type, int x, int y, int rotation, int color, int data){
|
||||
this.type = type;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rotation = rotation;
|
||||
this.color = color;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public EffectI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(type != null){
|
||||
double col = exec.num(color);
|
||||
//limit size so people don't create lag with ridiculous numbers (some explosions scale with size)
|
||||
float rot = type.rotate ? exec.numf(rotation) :
|
||||
Math.min(exec.numf(rotation), 1000f);
|
||||
|
||||
type.effect.at(World.unconv(exec.numf(x)), World.unconv(exec.numf(y)), rot, Tmp.c1.fromDouble(col), exec.obj(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExplosionI implements LInstruction{
|
||||
public int team, x, y, radius, damage, air, ground, pierce;
|
||||
|
||||
@@ -1617,6 +1655,47 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(unreliable = true)
|
||||
public static void syncVariable(Building building, int variable, Object value){
|
||||
if(building instanceof LogicBuild build){
|
||||
Var v = build.executor.optionalVar(variable);
|
||||
if(v != null && !v.constant){
|
||||
if(value instanceof Double d){
|
||||
v.isobj = false;
|
||||
v.numval = d;
|
||||
}else{
|
||||
v.isobj = true;
|
||||
v.objval =value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SyncI implements LInstruction{
|
||||
//10 syncs per second
|
||||
static final long syncInterval = 1000 / 10;
|
||||
|
||||
public int variable;
|
||||
|
||||
public SyncI(int variable){
|
||||
this.variable = variable;
|
||||
}
|
||||
|
||||
public SyncI(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(exec.build != null && exec.build.block.privileged){
|
||||
Var v = exec.var(variable);
|
||||
if(!v.constant && Time.timeSinceMillis(v.syncTime) > syncInterval){
|
||||
v.syncTime = Time.millis();
|
||||
Call.syncVariable(exec.build, variable, v.isobj ? v.objval : v.numval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetFlagI implements LInstruction{
|
||||
public int result, flag;
|
||||
|
||||
@@ -1638,6 +1717,15 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void setFlag(String flag, boolean add){
|
||||
if(add){
|
||||
state.rules.objectiveFlags.add(flag);
|
||||
}else{
|
||||
state.rules.objectiveFlags.remove(flag);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetFlagI implements LInstruction{
|
||||
public int flag, value;
|
||||
|
||||
@@ -1651,12 +1739,9 @@ public class LExecutor{
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
if(exec.obj(flag) instanceof String str){
|
||||
if(!exec.bool(value)){
|
||||
state.rules.objectiveFlags.remove(str);
|
||||
}else{
|
||||
state.rules.objectiveFlags.add(str);
|
||||
}
|
||||
//don't invoke unless the flag state actually changes
|
||||
if(exec.obj(flag) instanceof String str && state.rules.objectiveFlags.contains(str) != exec.bool(value)){
|
||||
Call.setFlag(str, exec.bool(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.LCanvas.*;
|
||||
import mindustry.logic.LExecutor.*;
|
||||
import mindustry.logic.LogicFx.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.meta.*;
|
||||
@@ -1506,6 +1508,80 @@ public class LStatements{
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("effect")
|
||||
public static class EffectStatement extends LStatement{
|
||||
public String type = "warn", x = "0", y = "0", sizerot = "2", color = "%ffaaff", data = "";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
table.clearChildren();
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> type).growX().wrap().labelAlign(Align.center);
|
||||
b.clicked(() -> ui.effects.show(entry -> {
|
||||
type = entry.name;
|
||||
build(table);
|
||||
}));
|
||||
}, Styles.logict, () -> {}).size(150f, 40f).margin(5f).pad(4f).color(table.color).colspan(2);
|
||||
|
||||
EffectEntry entry = LogicFx.get(type);
|
||||
|
||||
row(table);
|
||||
|
||||
fields(table, "x", x, str -> x = str);
|
||||
fields(table, "y", y, str -> y = str);
|
||||
row(table);
|
||||
|
||||
if(entry != null){
|
||||
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);
|
||||
}
|
||||
|
||||
row(table);
|
||||
|
||||
if(entry.size || entry.rotate){
|
||||
fields(table, entry.size ? "size" : "rotation", sizerot, str -> sizerot = str);
|
||||
}
|
||||
|
||||
if(entry.data != null){
|
||||
fields(table, "data", data, str -> data = str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler b){
|
||||
return new EffectI(LogicFx.get(type), b.var(x), b.var(y), b.var(sizerot), b.var(color), b.var(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
|
||||
@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";
|
||||
@@ -1626,6 +1702,32 @@ public class LStatements{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: test this first
|
||||
//@RegisterStatement("sync")
|
||||
public static class SyncStatement extends LStatement{
|
||||
public String variable = "var";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
fields(table, variable, str -> variable = str).width(190f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new SyncI(builder.var(variable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.world;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("getflag")
|
||||
public static class GetFlagStatement extends LStatement{
|
||||
public String result = "result", flag = "\"flag\"";
|
||||
|
||||
106
core/src/mindustry/logic/LogicFx.java
Normal file
106
core/src/mindustry/logic/LogicFx.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
public class LogicFx{
|
||||
private static OrderedMap<String, EffectEntry> map = new OrderedMap<>();
|
||||
|
||||
static{
|
||||
map.putAll(
|
||||
"warn", new EffectEntry(Fx.unitCapKill),
|
||||
"cross", new EffectEntry(Fx.unitEnvKill),
|
||||
"blockFall", new EffectEntry(Fx.blockCrash).data(Block.class).bounds(100f),
|
||||
"placeBlock", new EffectEntry(Fx.placeBlock).size(),
|
||||
"placeBlockSpark", new EffectEntry(Fx.coreLaunchConstruct).size(),
|
||||
"breakBlock", new EffectEntry(Fx.breakBlock).size(),
|
||||
"spawn", new EffectEntry(Fx.spawn),
|
||||
"trail", new EffectEntry(Fx.colorTrail).size().color(),
|
||||
"breakProp", new EffectEntry(Fx.breakProp).size().color(),
|
||||
"smokeCloud", new EffectEntry(Fx.missileTrailSmoke).color(),
|
||||
"vapor", new EffectEntry(Fx.vapor).color(),
|
||||
"hit", new EffectEntry(Fx.hitBulletColor).color(),
|
||||
"hitSquare", new EffectEntry(Fx.hitSquaresColor).color(),
|
||||
"shootSmall", new EffectEntry(Fx.shootSmall).color().rotate(),
|
||||
"shootBig", new EffectEntry(Fx.shootTitan).color().rotate(),
|
||||
"smokeSmall", new EffectEntry(Fx.shootSmallSmoke).rotate(),
|
||||
"smokeBig", new EffectEntry(Fx.shootBigSmoke).rotate(),
|
||||
"smokeColor", new EffectEntry(Fx.shootSmokeTitan).rotate().color(),
|
||||
"smokeSquare", new EffectEntry(Fx.shootSmokeSquare).rotate().color(),
|
||||
"smokeSquareBig", new EffectEntry(Fx.shootSmokeSquareBig).rotate().color(),
|
||||
"spark", new EffectEntry(Fx.hitLaserBlast).color(),
|
||||
"sparkBig", new EffectEntry(Fx.circleColorSpark).color(),
|
||||
"sparkShoot", new EffectEntry(Fx.colorSpark).rotate().color(),
|
||||
"sparkShootBig", new EffectEntry(Fx.randLifeSpark).rotate().color(),
|
||||
"drill", new EffectEntry(Fx.mine).color(),
|
||||
"drillBig", new EffectEntry(Fx.mineHuge).color(),
|
||||
"lightBlock", new EffectEntry(Fx.lightBlock).size().color(),
|
||||
"explosion", new EffectEntry(Fx.dynamicExplosion).size(),
|
||||
"smokePuff", new EffectEntry(Fx.smokePuff).color(),
|
||||
"sparkExplosion", new EffectEntry(Fx.titanExplosion).color(),
|
||||
"crossExplosion", new EffectEntry(Fx.dynamicSpikes).size().color(),
|
||||
"wave", new EffectEntry(Fx.dynamicWave).size(),
|
||||
"bubble", new EffectEntry(Fx.airBubble)
|
||||
);
|
||||
|
||||
map.each((n, e) -> e.name = n);
|
||||
}
|
||||
|
||||
public static Iterable<EffectEntry> entries(){
|
||||
return map.orderedKeys().map(s -> map.get(s));
|
||||
}
|
||||
|
||||
public static @Nullable EffectEntry get(String name){
|
||||
return map.get(name);
|
||||
}
|
||||
|
||||
public static String[] all(){
|
||||
return map.orderedKeys().toArray(String.class);
|
||||
}
|
||||
|
||||
public static class EffectEntry{
|
||||
public String name = "";
|
||||
public Effect effect;
|
||||
public boolean size, rotate, color;
|
||||
public @Nullable Class<?> data;
|
||||
/** cached bounds for this effect, negative if unset */
|
||||
public float bounds = -1f;
|
||||
|
||||
public EffectEntry(Effect effect){
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public EffectEntry bounds(float bounds){
|
||||
this.bounds = bounds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EffectEntry name(String name){
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EffectEntry size(){
|
||||
size = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EffectEntry rotate(){
|
||||
rotate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EffectEntry color(){
|
||||
color = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EffectEntry data(Class<?> data){
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user