Merge branch 'master' of https://github.com/Anuken/Mindustry into tileable-logic-displays
# Conflicts: # core/assets/icons/icons.properties # core/assets/logicids.dat
This commit is contained in:
@@ -61,6 +61,8 @@ public class LExecutor{
|
||||
|
||||
//yes, this is a minor memory leak, but it's probably not significant enough to matter
|
||||
protected static IntFloatMap unitTimeouts = new IntFloatMap();
|
||||
//lookup variable by name, lazy init.
|
||||
protected @Nullable ObjectIntMap<String> nameMap;
|
||||
|
||||
static{
|
||||
Events.on(ResetEvent.class, e -> unitTimeouts.clear());
|
||||
@@ -92,6 +94,7 @@ public class LExecutor{
|
||||
|
||||
/** Loads with a specified assembler. Resets all variables. */
|
||||
public void load(LAssembler builder){
|
||||
nameMap = null;
|
||||
vars = builder.vars.values().toSeq().retainAll(var -> !var.constant).toArray(LVar.class);
|
||||
for(int i = 0; i < vars.length; i++){
|
||||
vars[i].id = i;
|
||||
@@ -106,6 +109,17 @@ public class LExecutor{
|
||||
|
||||
//region utility
|
||||
|
||||
|
||||
public @Nullable LVar optionalVar(String name){
|
||||
if(nameMap == null){
|
||||
nameMap = new ObjectIntMap<>();
|
||||
for(int i = 0; i < vars.length; i++){
|
||||
nameMap.put(vars[i].name, i);
|
||||
}
|
||||
}
|
||||
return optionalVar(nameMap.get(name, -1));
|
||||
}
|
||||
|
||||
/** @return a Var from this processor. May be null if out of bounds. */
|
||||
public @Nullable LVar optionalVar(int index){
|
||||
return index < 0 || index >= vars.length ? null : vars[index];
|
||||
@@ -557,6 +571,15 @@ public class LExecutor{
|
||||
|
||||
if(from instanceof MemoryBuild mem && (exec.privileged || (from.team == exec.team && !mem.block.privileged))){
|
||||
output.setnum(address < 0 || address >= mem.memory.length ? 0 : mem.memory[address]);
|
||||
}else if(from instanceof LogicBuild logic && (exec.privileged || (from.team == exec.team && !from.block.privileged)) && position.isobj && position.objval instanceof String name){
|
||||
LVar fromVar = logic.executor.optionalVar(name);
|
||||
if(fromVar != null && !output.constant){
|
||||
output.objval = fromVar.objval;
|
||||
output.numval = fromVar.numval;
|
||||
output.isobj = fromVar.isobj;
|
||||
}
|
||||
}else if(target.isobj && target.objval instanceof CharSequence str){
|
||||
output.setnum(address < 0 || address >= str.length() ? Double.NaN : (int)str.charAt(address));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,6 +603,13 @@ public class LExecutor{
|
||||
|
||||
if(from instanceof MemoryBuild mem && (exec.privileged || (from.team == exec.team && !mem.block.privileged)) && address >= 0 && address < mem.memory.length){
|
||||
mem.memory[address] = value.num();
|
||||
}else if(from instanceof LogicBuild logic && (exec.privileged || (from.team == exec.team && !from.block.privileged)) && position.isobj && position.objval instanceof String name){
|
||||
LVar toVar = logic.executor.optionalVar(name);
|
||||
if(toVar != null && !toVar.constant){
|
||||
toVar.objval = value.objval;
|
||||
toVar.numval = value.numval;
|
||||
toVar.isobj = value.isobj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -622,6 +652,10 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(target instanceof CharSequence seq && sense == LAccess.size){
|
||||
to.setnum(seq.length());
|
||||
return;
|
||||
}
|
||||
to.setobj(null);
|
||||
}
|
||||
}
|
||||
@@ -984,6 +1018,29 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class PrintCharI implements LInstruction{
|
||||
public LVar value;
|
||||
|
||||
public PrintCharI(LVar value){
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
PrintCharI(){}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
|
||||
if(exec.textBuffer.length() >= maxTextBuffer) return;
|
||||
if(value.isobj){
|
||||
if(!(value.objval instanceof UnlockableContent cont)) return;
|
||||
exec.textBuffer.append((char)cont.emojiChar());
|
||||
return;
|
||||
}
|
||||
|
||||
exec.textBuffer.append((char)Math.floor(value.numval));
|
||||
}
|
||||
}
|
||||
|
||||
public static class FormatI implements LInstruction{
|
||||
public LVar value;
|
||||
|
||||
@@ -1376,10 +1433,10 @@ public class LExecutor{
|
||||
|
||||
Team t = team.team();
|
||||
|
||||
if(type.obj() instanceof UnitType type && !type.internal && !type.hidden && t != null && Units.canCreate(t, type)){
|
||||
if(t != null && type.obj() instanceof UnitType type && !type.internal && Units.canCreate(t, type)){
|
||||
//random offset to prevent stacking
|
||||
var unit = type.spawn(t, World.unconv(x.numf()) + Mathf.range(0.01f), World.unconv(y.numf()) + Mathf.range(0.01f));
|
||||
spawner.spawnEffect(unit, rotation.numf());
|
||||
spawner.spawnEffect(unit);
|
||||
result.setobj(unit);
|
||||
}
|
||||
}
|
||||
@@ -1485,6 +1542,7 @@ public class LExecutor{
|
||||
case dropZoneRadius -> state.rules.dropZoneRadius = value.numf() * 8f;
|
||||
case unitCap -> state.rules.unitCap = Math.max(value.numi(), 0);
|
||||
case lighting -> state.rules.lighting = value.bool();
|
||||
case canGameOver -> state.rules.canGameOver = value.bool();
|
||||
case mapArea -> {
|
||||
int x = p1.numi(), y = p2.numi(), w = p3.numi(), h = p4.numi();
|
||||
if(!checkMapArea(x, y, w, h, false)){
|
||||
@@ -1511,7 +1569,7 @@ public class LExecutor{
|
||||
state.rules.bannedUnits.remove(u);
|
||||
}
|
||||
}
|
||||
case unitHealth, unitBuildSpeed, unitCost, unitDamage, blockHealth, blockDamage, buildSpeed, rtsMinSquad, rtsMinWeight -> {
|
||||
case unitHealth, unitBuildSpeed, unitMineSpeed, unitCost, unitDamage, blockHealth, blockDamage, buildSpeed, rtsMinSquad, rtsMinWeight -> {
|
||||
Team team = p1.team();
|
||||
if(team != null){
|
||||
float num = value.numf();
|
||||
@@ -1519,6 +1577,7 @@ public class LExecutor{
|
||||
case buildSpeed -> team.rules().buildSpeedMultiplier = Mathf.clamp(num, 0.001f, 50f);
|
||||
case unitHealth -> team.rules().unitHealthMultiplier = Math.max(num, 0.001f);
|
||||
case unitBuildSpeed -> team.rules().unitBuildSpeedMultiplier = Mathf.clamp(num, 0f, 50f);
|
||||
case unitMineSpeed -> team.rules().unitMineSpeedMultiplier = Math.max(num, 0f);
|
||||
case unitCost -> team.rules().unitCostMultiplier = Math.max(num, 0f);
|
||||
case unitDamage -> team.rules().unitDamageMultiplier = Math.max(num, 0f);
|
||||
case blockHealth -> team.rules().blockHealthMultiplier = Math.max(num, 0.001f);
|
||||
@@ -1546,11 +1605,12 @@ public class LExecutor{
|
||||
}else if(full){
|
||||
//disable the rule, covers the whole map
|
||||
if(set){
|
||||
int prevX = state.rules.limitX, prevY = state.rules.limitY, prevW = state.rules.limitWidth, prevH = state.rules.limitHeight;
|
||||
state.rules.limitMapArea = false;
|
||||
if(!headless){
|
||||
renderer.updateAllDarkness();
|
||||
}
|
||||
world.checkMapArea();
|
||||
world.checkMapArea(prevX, prevY, prevW, prevH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1559,12 +1619,20 @@ public class LExecutor{
|
||||
}
|
||||
|
||||
if(set){
|
||||
int prevX = state.rules.limitX, prevY = state.rules.limitY, prevW = state.rules.limitWidth, prevH = state.rules.limitHeight;
|
||||
if(!state.rules.limitMapArea){
|
||||
//it was never on in the first place, so the old bounds don't apply
|
||||
prevW = 0;
|
||||
prevH = 0;
|
||||
prevX = -1;
|
||||
prevY = -1;
|
||||
}
|
||||
state.rules.limitMapArea = true;
|
||||
state.rules.limitX = x;
|
||||
state.rules.limitY = y;
|
||||
state.rules.limitWidth = w;
|
||||
state.rules.limitHeight = h;
|
||||
world.checkMapArea();
|
||||
world.checkMapArea(prevX, prevY, prevW, prevH);
|
||||
|
||||
if(!headless){
|
||||
renderer.updateAllDarkness();
|
||||
@@ -1876,9 +1944,7 @@ public class LExecutor{
|
||||
for(int i = 0; i < spawned; i++){
|
||||
Tmp.v1.rnd(spread);
|
||||
|
||||
Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1);
|
||||
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
|
||||
Vars.spawner.spawnEffect(unit);
|
||||
spawner.spawnUnit(group, spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user