Added field for running logic code upon objective completion

This commit is contained in:
Anuken 2026-02-06 22:46:17 -05:00
parent 7d88eeee77
commit 67d3a9feb0
4 changed files with 39 additions and 20 deletions

View file

@ -47,6 +47,10 @@ public class MapObjectivesDialog extends BaseDialog{
if(field != null && field.isAnnotationPresent(Multiline.class)){
cont.area(get.get(), set).height(100f).growX();
}else if(field != null && field.isAnnotationPresent(LogicCode.class)){
cont.button(b -> b.image(Icon.pencil).size(iconSmall), () -> {
ui.logic.show(get.get(), null, true, set::get);
}).pad(4f);
}else{
cont.field(get.get(), set).growX();
}

View file

@ -179,6 +179,7 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public static abstract class MapObjective{
public boolean hidden;
public @Nullable @Multiline String details;
public @Nullable @LogicCode String completionLogicCode;
public @Unordered String[] flagsAdded = {};
public @Unordered String[] flagsRemoved = {};
public ObjectiveMarker[] markers = {};
@ -207,9 +208,13 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
state.rules.objectiveFlags.removeAll(flagsRemoved);
state.rules.objectiveFlags.addAll(flagsAdded);
completed = true;
if(completionLogicCode != null && !completionLogicCode.isEmpty()){
LExecutor.runLogicScript(completionLogicCode);
}
}
/** @return True if all {@link #parents} are completed, rendering this objective able to execute. */
/** @return true if all {@link #parents} are completed, rendering this objective able to execute. */
public final boolean dependencyFinished(){
if(depFinished) return true;
@ -220,7 +225,7 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
return depFinished = true;
}
/** @return True if this objective is done (practically, has been removed from the executor). */
/** @return true if this objective is done (practically, has been removed from the executor). */
public final boolean isCompleted(){
return completed;
}
@ -1493,6 +1498,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
@Retention(RUNTIME)
public @interface Multiline{}
/** For {@link String}; indicates that text corresponds to logic code. */
@Target(FIELD)
@Retention(RUNTIME)
public @interface LogicCode{}
/** For {@code float}; multiplies the UI input by 60. */
@Target(FIELD)
@Retention(RUNTIME)

View file

@ -67,6 +67,28 @@ public class LExecutor{
Events.on(ResetEvent.class, e -> unitTimeouts.clear());
}
public static void runLogicScript(String code){
runLogicScript(code, 100_000, false);
}
public static void runLogicScript(String code, int maxInstructions, boolean loop){
LExecutor executor = new LExecutor();
executor.privileged = true;
try{
//assembler has no variables, all the standard ones are null
executor.load(LAssembler.assemble(code, true));
}catch(Throwable ignored){
return;
}
//executions are limited to prevent a game freeze
for(int i = 1; i < maxInstructions; i++){
if((!loop && executor.counter.numval >= executor.instructions.length || executor.counter.numval < 0) || executor.yield) break;
executor.runOnce();
}
}
boolean timeoutDone(Unit unit, float delay){
return Time.time >= unitTimeouts.get(unit.id) + delay;
}

View file

@ -1,7 +1,6 @@
package mindustry.maps.filters;
import arc.scene.ui.layout.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.logic.*;
import mindustry.maps.filters.FilterOption.*;
@ -38,26 +37,10 @@ public class LogicFilter extends GenerateFilter{
@Override
public void apply(Tiles tiles, GenerateInput in){
LExecutor executor = new LExecutor();
executor.privileged = true;
try{
//assembler has no variables, all the standard ones are null
executor.load(LAssembler.assemble(code, true));
}catch(Throwable ignored){
//if loading code
return;
}
//this updates map width/height global variables
logicVars.update();
//NOTE: all tile operations will call setNet for tiles, but that should have no overhead during world loading
//executions are limited to prevent infinite generation
for(int i = 1; i < maxInstructionsExecution; i++){
if(!loop && (executor.counter.numval >= executor.instructions.length || executor.counter.numval < 0)) break;
executor.runOnce();
}
LExecutor.runLogicScript(code, maxInstructionsExecution, loop);
}
@Override