WIP payload deconstructor

This commit is contained in:
Anuken
2021-06-24 10:01:01 -04:00
parent e7ec2da063
commit d54b7dc396
10 changed files with 321 additions and 42 deletions

View File

@@ -96,7 +96,7 @@ public class Blocks implements ContentList{
repairPoint, repairTurret, resupplyPoint,
//payloads
payloadConveyor, payloadRouter, payloadPropulsionTower,
payloadConveyor, payloadRouter, payloadPropulsionTower, payloadDeconstructor, blockForge, blockLoader, blockUnloader,
//logic
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank,
@@ -105,10 +105,7 @@ public class Blocks implements ContentList{
launchPad, payloadLaunchPad, interplanetaryAccelerator,
//nuclear?
nuclearWarhead, warheadAssembler, ballisticSilo, //TODO
//misc experimental
blockForge, blockLoader, blockUnloader
nuclearWarhead, warheadAssembler, ballisticSilo //TODO
;
@Override
@@ -2206,6 +2203,35 @@ public class Blocks implements ContentList{
consumes.power(6f);
}};
payloadDeconstructor = new PayloadDeconstructor("payload-deconstructor"){{
requirements(Category.units, with(Items.graphite, 30, Items.silicon, 30, Items.copper, 30));
itemCapacity = 200;
consumes.power(1f);
size = 5;
deconstructSpeed = 2f;
}};
blockForge = new BlockForge("block-forge"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
blockLoader = new BlockLoader("block-loader"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
blockUnloader = new BlockUnloader("block-unloader"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
//endregion
//region sandbox
@@ -2390,30 +2416,6 @@ public class Blocks implements ContentList{
size = 6;
}};
//endregion
//region experimental
blockForge = new BlockForge("block-forge"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
blockLoader = new BlockLoader("block-loader"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
blockUnloader = new BlockUnloader("block-unloader"){{
requirements(Category.units, BuildVisibility.debugOnly, with(Items.thorium, 100));
hasPower = true;
consumes.power(2f);
size = 3;
}};
//endregion
}
}

View File

@@ -55,6 +55,21 @@ public class ItemSeq implements Iterable<ItemStack>, JsonSerializable{
return out;
}
public ItemStack[] toArray(){
int count = 0;
for(int value : values){
if(value != 0) count++;
}
ItemStack[] result = new ItemStack[count];
int index = 0;
for(int i = 0; i < values.length; i++){
if(values[i] != 0){
result[index ++] = new ItemStack(Vars.content.item(i), values[i]);
}
}
return result;
}
public void min(int number){
for(Item item : Vars.content.items()){
set(item, Math.min(get(item), number));
@@ -90,6 +105,12 @@ public class ItemSeq implements Iterable<ItemStack>, JsonSerializable{
itemModule.each(this::add);
}
public void add(ItemStack[] stacks){
for(var s : stacks){
add(s);
}
}
public void add(ItemSeq seq){
seq.each(this::add);
}

View File

@@ -127,7 +127,9 @@ public class UnitType extends UnlockableContent{
softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion;
public TextureRegion[] wreckRegions;
protected float maxBuildTime = -1f;
protected @Nullable ItemStack[] cachedRequirements;
protected @Nullable ItemStack[] totalRequirements;
public UnitType(String name){
super(name);
@@ -460,25 +462,70 @@ public class UnitType extends UnlockableContent{
}
}
/** @return the time required to build this unit, as a maximum value that takes into account reconstructors */
public float getBuildTime(){
getTotalRequirements();
return maxBuildTime;
}
/** @return all items needed to build this unit, including reconstructor steps. */
public ItemStack[] getTotalRequirements(){
if(totalRequirements == null){
UnitType[] ret = {null};
float[] timeret = {0f};
ItemStack[] result = getRequirements(ret, timeret);
//prevents stack overflow if requirements are circular and result != null
totalRequirements = ItemStack.empty;
if(result != null){
maxBuildTime = timeret[0];
ItemSeq total = new ItemSeq();
total.add(result);
if(ret[0] != null){
total.add(ret[0].getTotalRequirements());
maxBuildTime = Math.max(ret[0].maxBuildTime, maxBuildTime);
}
totalRequirements = total.toArray();
}
}
return totalRequirements;
}
/** @return item requirements based on reconstructors or factories found; returns previous unit in array if provided */
public @Nullable ItemStack[] getRequirements(@Nullable UnitType[] prevReturn, @Nullable float[] timeReturn){
var rec = (Reconstructor)content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this));
if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){
if(prevReturn != null){
prevReturn[0] = rec.upgrades.find(u -> u[1] == this)[0];
}
if(timeReturn != null){
timeReturn[0] = rec.constructTime;
}
return ci.items;
}else{
var factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this));
if(factory != null){
var plan = factory.plans.find(p -> p.unit == this);
if(timeReturn != null){
timeReturn[0] = plan.time;
}
return plan.requirements;
}
}
return null;
}
@Override
public ItemStack[] researchRequirements(){
if(cachedRequirements != null){
return cachedRequirements;
}
ItemStack[] stacks = null;
//calculate costs based on reconstructors or factories found
Block rec = content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this));
if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){
stacks = ci.items;
}else{
UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this));
if(factory != null){
stacks = factory.plans.find(p -> p.unit == this).requirements;
}
}
ItemStack[] stacks = getRequirements(null, null);
if(stacks != null){
ItemStack[] out = new ItemStack[stacks.length];

View File

@@ -5,6 +5,7 @@ import arc.util.io.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -33,6 +34,16 @@ public class BuildPayload implements Payload{
build.dropped();
}
@Override
public ItemStack[] requirements(){
return build.block.requirements;
}
@Override
public float buildTime(){
return build.block.buildCost;
}
@Override
public float x(){
return build.x;

View File

@@ -6,6 +6,7 @@ import arc.util.*;
import arc.util.io.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -25,6 +26,12 @@ public interface Payload extends Position{
float x();
float y();
/** @return the items needed to make this payload; may be empty. */
ItemStack[] requirements();
/** @return the time taken to build this payload. */
float buildTime();
/** @return whether this payload was dumped. */
default boolean dump(){
return false;

View File

@@ -0,0 +1,179 @@
package mindustry.world.blocks.payloads;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class PayloadDeconstructor extends PayloadBlock{
public float deconstructSpeed = 2f;
public PayloadDeconstructor(String name){
super(name);
outputsPayload = false;
acceptsPayload = true;
update = true;
rotate = false;
size = 5;
payloadSpeed = 1f;
//make sure to display large units.
clipSize = 120;
hasItems = true;
hasPower = true;
itemCapacity = 100;
}
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, topRegion};
}
public class PayloadDeconstructorBuild extends PayloadBlockBuild<Payload>{
public @Nullable Payload deconstructing;
public @Nullable float[] accum;
public float progress;
public float time, speedScl;
@Override
public void draw(){
Draw.rect(region, x, y);
//draw input
for(int i = 0; i < 4; i++){
if(blends(i)){
Draw.rect(inRegion, x, y, (i * 90) - 180);
}
}
Draw.z(Layer.blockOver);
drawPayload();
if(deconstructing != null){
deconstructing.set(x + payVector.x, y + payVector.y, payRotation);
Draw.z(Layer.blockOver);
//deconstructing.draw();
//TODO shadow
Draw.draw(Layer.blockOver, () -> {
Drawf.construct(x, y, deconstructing.icon(), Pal.remove, 0f, 1f - progress, speedScl, time);
Draw.color(Pal.remove);
Draw.alpha(speedScl);
Lines.lineAngleCenter(x + Mathf.sin(time, 20f, Vars.tilesize / 2f * block.size - 2f), y, 90, block.size * Vars.tilesize - 4f);
Draw.reset();
});
}
Draw.rect(topRegion, x, y);
}
@Override
public void handlePayload(Building source, Payload payload){
super.handlePayload(source, payload);
accum = null;
}
@Override
public boolean acceptPayload(Building source, Payload payload){
return deconstructing == null && super.acceptPayload(source, payload) && payload.requirements().length > 0;
}
@Override
public void updateTile(){
//always dump items
dumpAccumulate();
if(deconstructing != null){
var reqs = deconstructing.requirements();
if(accum == null || reqs.length != accum.length){
accum = new float[reqs.length];
}
//check if there is enough space to get the items for deconstruction
boolean canProgress = items.total() <= itemCapacity;
if(canProgress){
for(var ac : accum){
if(ac >= 1f){
canProgress = false;
break;
}
}
}
//move progress forward if possible
if(canProgress){
float shift = edelta() * deconstructSpeed / deconstructing.buildTime();
float realShift = Math.min(shift, 1f - progress);
progress += shift;
time += edelta();
for(int i = 0; i < reqs.length; i++){
accum[i] += reqs[i].amount * realShift;
}
}
speedScl = Mathf.lerpDelta(speedScl, canProgress ? 1f : 0f, 0.1f);
//transfer items from accumulation buffer into block inventory when they reach integers
for(int i = 0; i < reqs.length; i++){
int taken = Math.min((int)accum[i], itemCapacity - items.total());
if(taken > 0){
items.add(reqs[i].item, taken);
accum[i] -= taken;
}
}
//finish deconstruction, prepare for next payload.
if(progress >= 1f){
//TODO
deconstructing = null;
accum = null;
}
}else if(moveInPayload(false) && payload != null && cons.valid()){
accum = new float[payload.requirements().length];
deconstructing = payload;
payload = null;
progress = 0f;
}
}
@Override
public void write(Writes write){
super.write(write);
write.f(progress);
if(accum != null){
write.s(accum.length);
for(float v : accum){
write.f(v);
}
}else{
write.s(0);
}
Payload.write(deconstructing, write);
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
progress = read.f();
short accums = read.s();
if(accums > 0){
accum = new float[accums];
for(int i = 0; i < accums; i++){
accum[i] = read.f();
}
}
deconstructing = Payload.read(read);
}
}
}

View File

@@ -12,6 +12,7 @@ import mindustry.entities.EntityCollisions.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.type.*;
public class UnitPayload implements Payload{
public static final float deactiveDuration = 40f;
@@ -23,6 +24,16 @@ public class UnitPayload implements Payload{
this.unit = unit;
}
@Override
public ItemStack[] requirements(){
return unit.type.getTotalRequirements();
}
@Override
public float buildTime(){
return unit.type.getBuildTime();
}
@Override
public void write(Writes write){
write.b(payloadUnit);