Finalized launch pad mechanics
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user