Launch pad rework progress, base mechanics done

This commit is contained in:
Anuken
2025-02-01 20:46:08 -05:00
parent ab65c9d29a
commit 18b78f4bf6
12 changed files with 226 additions and 59 deletions
@@ -1,18 +1,46 @@
package mindustry.world.blocks.campaign;
import arc.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class LandingPad extends Block{
static ObjectMap<Item, Seq<LandingPadBuild>> waiting = new ObjectMap<>();
static long lastUpdateId = -1;
static{
Events.on(ResetEvent.class, e -> {
waiting.clear();
lastUpdateId = -1;
});
}
public float cooldownTime = 12f;
public float consumeLiquidAmount = 100f;
public Liquid consumeLiquid = Liquids.water;
public LandingPad(String name){
super(name);
hasItems = true;
hasLiquids = true;
solid = true;
update = true;
configurable = true;
@@ -22,19 +50,127 @@ public class LandingPad extends Block{
configClear((LandingPadBuild build) -> build.config = null);
}
@Override
public void init(){
consume(new ConsumeLiquid(consumeLiquid, consumeLiquidAmount){
@Override
public void build(Building build, Table table){
table.add(new ReqImage(liquid.uiIcon, () -> build.liquids.get(liquid) >= amount)).size(iconMed).top().left();
}
@Override
public float efficiency(Building build){
return build.liquids.get(consumeLiquid) >= amount ? 1f : 0f;
}
@Override
public void display(Stats stats){
stats.add(Stat.input, liquid, amount, false);
}
}).update(false);
super.init();
}
@Override
public void setBars(){
super.setBars();
addLiquidBar(consumeLiquid);
//TODO: does cooldown even need to exist?
addBar("heat", (LandingPadBuild entity) -> new Bar("bar.heat", Pal.lightOrange, () -> entity.cooldown));
}
@Override
public boolean outputsItems(){
return true;
}
@Remote(called = Loc.server)
public static void landingPadLanded(Tile tile){
if(tile == null || !(tile.build instanceof LandingPadBuild build)) return;
build.handleLanding();
}
public class LandingPadBuild extends Building{
public @Nullable Item config;
//priority collisions are possible, but should be extremely rare
public int priority = Mathf.rand.nextInt();
public float cooldown = 0f;
public void handleLanding(){
if(!state.isCampaign() || config == null) return;
//TODO animation, etc
cooldown = 1f;
items.set(config, itemCapacity);
liquids.remove(consumeLiquid, consumeLiquidAmount);
for(int i = 0; i < 10; i++){
Fx.steam.at(this);
}
//TODO this is a temporary effect
Fx.shockwave.at(this);
state.rules.sector.info.importCooldownTimers.put(config, 0f);
}
public void updateTimers(){
if(state.isCampaign() && lastUpdateId != state.updateId){
lastUpdateId = state.updateId;
float[] imports = state.rules.sector.info.getImportRates(state.getPlanet());
for(Item item : content.items()){
float importedPerFrame = imports[item.id]/60f;
if(importedPerFrame > 0f){
float framesBetweenArrival = itemCapacity / importedPerFrame;
state.rules.sector.info.importCooldownTimers.increment(item, 0f, 1f / framesBetweenArrival * Time.delta);
}
}
waiting.each((item, pads) -> {
if(pads.size > 0){
pads.sort(p -> p.priority);
var first = pads.first();
var head = pads.peek();
Call.landingPadLanded(first.tile);
//swap priorities, moving this block to the end of the list (if there is only one block waiting, this does nothing)
var tmp = first.priority;
first.priority = head.priority;
head.priority = tmp;
pads.clear();
}
});
}
}
@Override
public void updateTile(){
updateTimers();
if(items.total() > 0){
dumpAccumulate(config == null || items.get(config) != items.total() ? null : config);
}
if(config != null && state.isCampaign()){
cooldown -= delta() / cooldownTime;
if(cooldown <= 0f && efficiency > 0f && items.total() == 0 && state.rules.sector.info.importCooldownTimers.get(config, 0f) >= 1f){
//queue landing for next frame
waiting.get(config, Seq::new).add(this);
}
}
}
@Override
@@ -45,6 +181,11 @@ public class LandingPad extends Block{
return true;
}
@Override
public void buildConfiguration(Table table){
ItemSelection.buildTable(LandingPad.this, table, content.items(), () -> config, this::configure, selectionRows, selectionColumns);
}
@Override
public boolean acceptItem(Building source, Item item){
return false;
@@ -59,12 +200,16 @@ public class LandingPad extends Block{
public void read(Reads read, byte revision){
super.read(read, revision);
config = TypeIO.readItem(read);
priority = read.i();
cooldown = read.f();
}
@Override
public void write(Writes write){
super.write(write);
TypeIO.writeItem(write, config);
write.i(priority);
write.f(cooldown);
}
}
}
@@ -150,7 +150,7 @@ public class LaunchPad extends Block{
table.row();
table.label(() -> {
Sector dest = state.rules.sector == null ? null : state.rules.sector.info.getRealDestination();
Sector dest = state.rules.sector == null ? null : state.rules.sector.info.destination;
return Core.bundle.format("launch.destination",
dest == null || !dest.hasBase() ? Core.bundle.get("sectors.nonelaunch") :
@@ -161,7 +161,7 @@ public class LaunchPad extends Block{
@Override
public void buildConfiguration(Table table){
//TODO: this UI should be on landing pads
if(!state.isCampaign() || net.client() || true){
if(!state.isCampaign() || net.client()){
deselect();
return;
}
@@ -262,27 +262,23 @@ public class LaunchPad extends Block{
@Override
public void remove(){
if(!state.isCampaign()) return;
if(!state.isCampaign() || net.client()) return;
Sector destsec = state.rules.sector.info.getRealDestination();
Sector destsec = state.rules.sector.info.destination;
//actually launch the items upon removal
if(team() == state.rules.defaultTeam){
if(destsec != null && (destsec != state.rules.sector || net.client())){
ItemSeq dest = new ItemSeq();
if(team() == state.rules.defaultTeam && destsec != null && destsec != state.rules.sector){
ItemSeq dest = new ItemSeq();
for(ItemStack stack : stacks){
dest.add(stack);
for(ItemStack stack : stacks){
dest.add(stack);
//update export
state.rules.sector.info.handleItemExport(stack);
Events.fire(new LaunchItemEvent(stack));
}
if(!net.client()){
destsec.addItems(dest);
}
//update export statistics
state.rules.sector.info.handleItemExport(stack);
Events.fire(new LaunchItemEvent(stack));
}
destsec.addItems(dest);
}
}
}
@@ -88,6 +88,7 @@ public class ItemSource extends Block{
while(counter >= limit){
items.set(outputItem, 1);
dump(outputItem);
produced(outputItem);
items.set(outputItem, 0);
counter -= limit;
}
@@ -12,7 +12,6 @@ import static mindustry.Vars.*;
//TODO replace with ConsumeLiquids?
public class ConsumeLiquid extends ConsumeLiquidBase{
public final Liquid liquid;
public boolean trigger;
public ConsumeLiquid(Liquid liquid, float amount){
super(amount);
@@ -23,10 +22,6 @@ public class ConsumeLiquid extends ConsumeLiquidBase{
this(null, 0f);
}
public ConsumeLiquid trigger(boolean trigger){
this.trigger = trigger;
return this;
}
@Override
public void apply(Block block){
@@ -44,13 +39,6 @@ public class ConsumeLiquid extends ConsumeLiquidBase{
build.liquids.remove(liquid, amount * build.edelta() * multiplier.get(build));
}
@Override
public void trigger(Building build){
if(trigger){
build.liquids.remove(liquid, amount);
}
}
@Override
public float efficiency(Building build){
float ed = build.edelta() * build.efficiencyScale();