Finalized launch pad mechanics

This commit is contained in:
Anuken
2025-02-02 18:10:15 -05:00
parent c6d82bec66
commit 7aee34bafa
19 changed files with 310 additions and 52 deletions

View File

@@ -1,6 +1,8 @@
package mindustry.world.blocks.campaign;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
@@ -8,6 +10,7 @@ import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
@@ -16,6 +19,7 @@ import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.liquid.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
@@ -32,10 +36,19 @@ public class LandingPad extends Block{
});
}
public float cooldownTime = 12f;
public @Load(value = "@-pod", fallback = "advanced-launch-pad-pod") TextureRegion podRegion;
public float arrivalDuration = 150f;
public float cooldownTime = 180f;
public float consumeLiquidAmount = 100f;
public Liquid consumeLiquid = Liquids.water;
public Effect landEffect = Fx.podLandShockwave;
public Effect coolingEffect = Fx.none;
public float coolingEffectChance = 0.2f;
public float liquidPad = 2f;
public Color bottomColor = Pal.darkerMetal;
public LandingPad(String name){
super(name);
@@ -45,6 +58,8 @@ public class LandingPad extends Block{
update = true;
configurable = true;
acceptsItems = false;
emitLight = true;
lightRadius = 90f;
config(Item.class, (LandingPadBuild build, Item item) -> build.config = item);
configClear((LandingPadBuild build) -> build.config = null);
@@ -97,21 +112,19 @@ public class LandingPad extends Block{
public @Nullable Item config;
//priority collisions are possible, but should be extremely rare
public int priority = Mathf.rand.nextInt();
public float cooldown = 0f;
public float cooldown = 0f, landParticleTimer;
public float arrivingTimer = 0f;
public @Nullable Item arriving;
public float liquidRemoved;
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);
arriving = config;
arrivingTimer = 0f;
liquidRemoved = 0f;
state.rules.sector.info.importCooldownTimers.put(config, 0f);
}
@@ -128,6 +141,9 @@ public class LandingPad extends Block{
float framesBetweenArrival = itemCapacity / importedPerFrame;
state.rules.sector.info.importCooldownTimers.increment(item, 0f, 1f / framesBetweenArrival * Time.delta);
}else{
//nothing is being imported, so reset the timer
state.rules.sector.info.importCooldownTimers.put(item, 0f);
}
}
@@ -140,32 +156,144 @@ public class LandingPad extends Block{
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 draw(){
if(consumeLiquid != null){
Draw.color(bottomColor);
Fill.square(x, y, size * tilesize/2f - liquidPad);
Draw.color();
LiquidBlock.drawTiledFrames(block.size, x, y, liquidPad, liquidPad, liquidPad, liquidPad, consumeLiquid, liquids.get(consumeLiquid) / liquidCapacity);
}
super.draw();
if(arriving != null){
float fin = Mathf.clamp(arrivingTimer), fout = 1f - fin;
float alpha = Interp.pow5Out.apply(fin);
float scale = (1f - alpha) * 1.3f + 1f;
float
cx = x,
cy = y + Interp.pow4In.apply(fout) * (100f + Mathf.randomSeedRange(id() + 2, 30f));
float rotation = fout * (90f + Mathf.randomSeedRange(id(), 50f));
Draw.z(Layer.effect + 0.001f);
Draw.color(Pal.engine);
float rad = 0.15f + Interp.pow5Out.apply(Mathf.slope(fin));
Fill.light(cx, cy, 10, 25f * (rad + scale-1f), Tmp.c2.set(Pal.engine).a(alpha), Tmp.c1.set(Pal.engine).a(0f));
Draw.alpha(alpha);
for(int i = 0; i < 4; i++){
Drawf.tri(cx, cy, 6f, 40f * (rad + scale-1f), i * 90f + rotation);
}
Draw.color();
Draw.z(Layer.weather - 1);
scale *= podRegion.scl();
float rw = podRegion.width * scale, rh = podRegion.height * scale;
Draw.alpha(alpha);
Drawf.shadow(cx, cy, size * tilesize, fin);
Draw.rect(podRegion, cx, cy, rw, rh, rotation);
Tmp.v1.trns(225f, Interp.pow3In.apply(fout) * 250f);
Draw.z(Layer.flyingUnit + 1);
Draw.color(0, 0, 0, 0.22f * alpha);
Draw.rect(podRegion, cx + Tmp.v1.x, cy + Tmp.v1.y, rw, rh, rotation);
}else if(cooldown > 0f){
Drawf.shadow(x, y, size * tilesize, cooldown);
Draw.alpha(cooldown);
Draw.mixcol(Pal.accent, 1f - cooldown);
Draw.rect(podRegion, x, y);
}
Draw.reset();
}
@Override
public void drawLight(){
Drawf.light(x, y, lightRadius, Pal.accent, Mathf.clamp(Math.max(cooldown, arrivingTimer * 1.5f)));
}
@Override
public void updateTile(){
updateTimers();
if(arriving != null){
if(!headless){ //pod particles
float fin = arrivingTimer;
float tsize = Interp.pow5Out.apply(fin);
landParticleTimer += tsize * Time.delta / 2f;
if(landParticleTimer >= 1f){
tile.getLinkedTiles(t -> {
if(Mathf.chance(0.1f)){
Fx.podLandDust.at(t.worldx(), t.worldy(), angleTo(t.worldx(), t.worldy()) + Mathf.range(30f), Tmp.c1.set(t.floor().mapColor).mul(1.5f + Mathf.range(0.15f)));
}
});
landParticleTimer = 0f;
}
}
arrivingTimer += Time.delta / arrivalDuration;
float toRemove = Math.min(consumeLiquidAmount / arrivalDuration * Time.delta, consumeLiquidAmount - liquidRemoved);
liquidRemoved += toRemove;
liquids.remove(consumeLiquid, toRemove);
if(Mathf.chanceDelta(coolingEffectChance * Interp.pow5Out.apply(arrivingTimer))){
coolingEffect.at(this);
}
if(arrivingTimer >= 1f){
//remove any leftovers to make sure it's precise
liquids.remove(consumeLiquid, consumeLiquidAmount - liquidRemoved);
landEffect.at(this);
Effect.shake(3f, 3f, this);
items.set(arriving, itemCapacity);
state.getSector().info.handleItemImport(arriving, itemCapacity);
arriving = null;
arrivingTimer = 0f;
}
}
if(items.total() > 0){
dumpAccumulate(config == null || items.get(config) != items.total() ? null : config);
}
if(arriving == null){
cooldown -= delta() / cooldownTime;
cooldown = Mathf.clamp(cooldown);
}
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){
if(cooldown <= 0f && efficiency > 0f && items.total() == 0 && state.rules.sector.info.getImportRate(state.getPlanet(), config) > 0f && state.rules.sector.info.importCooldownTimers.get(config, 0f) >= 1f){
//queue landing for next frame
waiting.get(config, Seq::new).add(this);
@@ -184,6 +312,58 @@ public class LandingPad extends Block{
@Override
public void buildConfiguration(Table table){
ItemSelection.buildTable(LandingPad.this, table, content.items(), () -> config, this::configure, selectionRows, selectionColumns);
if(!net.client()){
table.row();
table.table(t -> {
t.background(Styles.black6);
t.button(Icon.downOpen, Styles.clearNonei, 40f, () -> {
if(config != null && state.isCampaign()){
for(Sector sector : state.getPlanet().sectors){
if(sector.hasBase() && sector != state.getSector() && sector.info.destination != state.getSector() && sector.info.hasExport(config)){
sector.info.destination = state.getSector();
sector.saveInfo();
}
}
state.getSector().info.refreshImportRates(state.getPlanet());
}
}).disabled(b -> config == null || !state.isCampaign() || (!state.getPlanet().sectors.contains(s -> s.hasBase() && s.info.hasExport(config) && s.info.destination != state.getSector())))
.tooltip("@sectors.redirect").get();
}).fillX().left();
}
}
@Override
public void display(Table table){
super.display(table);
if(!state.isCampaign() || net.client() || team != player.team()) return;
table.row();
table.label(() -> {
if(config == null || !state.isCampaign()){
return "";
}
int sources = 0;
float perSecond = 0f;
for(var s : state.getPlanet().sectors){
if(s != state.getSector() && s.hasBase() && s.info.destination == state.getSector()){
float amount = s.info.getExport(config);
if(amount > 0){
sources ++;
perSecond += s.info.getExport(config);
}
}
}
String str = Core.bundle.format("landing.sources", sources == 0 ? Core.bundle.get("none") : sources);
if(perSecond > 0){
str += "\n" + Core.bundle.format("landing.import", config.emoji(), (int)(perSecond * 60f));
}
return str;
}).pad(4).wrap().width(200f).left();
}
@Override

View File

@@ -22,6 +22,7 @@ import mindustry.logic.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.liquid.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -36,6 +37,13 @@ public class LaunchPad extends Block{
public Color lightColor = Color.valueOf("eab678");
public boolean acceptMultipleItems = false;
public float lightStep = 1f;
public int lightSteps = 3;
public float liquidPad = 2f;
public @Nullable Liquid drawLiquid;
public Color bottomColor = Pal.darkerMetal;
public LaunchPad(String name){
super(name);
hasItems = true;
@@ -87,6 +95,13 @@ public class LaunchPad extends Block{
@Override
public void draw(){
if(hasLiquids && drawLiquid != null){
Draw.color(bottomColor);
Fill.square(x, y, size * tilesize/2f - liquidPad);
Draw.color();
LiquidBlock.drawTiledFrames(block.size, x, y, liquidPad, liquidPad, liquidPad, liquidPad, drawLiquid, liquids.get(drawLiquid) / liquidCapacity);
}
super.draw();
if(!state.isCampaign()) return;
@@ -94,13 +109,11 @@ public class LaunchPad extends Block{
if(lightRegion.found()){
Draw.color(lightColor);
float progress = Math.min((float)items.total() / itemCapacity, launchCounter / launchTime);
int steps = 3;
float step = 1f;
for(int i = 0; i < 4; i++){
for(int j = 0; j < steps; j++){
float alpha = Mathf.curve(progress, (float)j / steps, (j+1f) / steps);
float offset = -(j - 1f) * step;
for(int j = 0; j < lightSteps; j++){
float alpha = Mathf.curve(progress, (float)j / lightSteps, (j+1f) / lightSteps);
float offset = -(j - 1f) * lightStep;
Draw.color(Pal.metalGrayDark, lightColor, alpha);
Draw.rect(lightRegion, x + Geometry.d8edge(i).x * offset, y + Geometry.d8edge(i).y * offset, i * 90);
@@ -110,6 +123,7 @@ public class LaunchPad extends Block{
Draw.reset();
}
Drawf.shadow(x, y, size * tilesize);
Draw.rect(podRegion, x, y);
Draw.reset();
@@ -169,7 +183,11 @@ public class LaunchPad extends Block{
table.button(Icon.upOpen, Styles.cleari, () -> {
ui.planet.showSelect(state.rules.sector, other -> {
if(state.isCampaign() && other.planet == state.rules.sector.planet){
var prev = state.rules.sector.info.destination;
state.rules.sector.info.destination = other;
if(prev != null){
prev.info.refreshImportRates(state.getPlanet());
}
}
});
deselect();

View File

@@ -150,7 +150,7 @@ public class StatValues{
t.add(Strings.autoFixed(amount, 2)).style(Styles.outlineLabel);
add(t);
}
}}).size(iconMed).padRight(3 + (amount != 0 && Strings.autoFixed(amount, 2).length() > 2 ? 8 : 0)).with(s -> withTooltip(s, liquid, false));
}}).size(iconMed).padRight(3 + (amount != 0 ? (Strings.autoFixed(amount, 2).length() - 1) * 10 : 0)).with(s -> withTooltip(s, liquid, false));
if(perSecond && amount != 0){
t.add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray).style(Styles.outlineLabel);