Unit assembler progress

This commit is contained in:
Anuken
2021-12-13 23:14:26 -05:00
parent 121b992d56
commit bdc3b85346
18 changed files with 264 additions and 12 deletions

View File

@@ -29,6 +29,8 @@ public class CargoAI extends AIController{
var build = tether.building();
if(build.items == null) return;
//empty, approach the loader, even if there's nothing to pick up (units hanging around doing nothing looks bad)
if(!unit.hasItem()){
moveTo(build, moveRange, moveSmoothing);

View File

@@ -3312,10 +3312,13 @@ public class Blocks{
//endregion
//region units - erekir
//TODO completely unfinished
tankAssembler = new UnitAssembler("tank-assembler"){{
requirements(Category.units, with(Items.graphite, 10));
size = 3;
output = UnitTypes.vanquish;
requirements = BlockStack.list(Blocks.thoriumWallLarge, 4);
droneType = UnitTypes.manifold;
requirements = BlockStack.list(Blocks.thoriumWallLarge, 4, Blocks.duct, 2);
}};
//endregion

View File

@@ -2691,6 +2691,7 @@ public class UnitTypes{
itemCapacity = 0;
commandLimit = 0;
hidden = true;
internal = true;
}};
manifold = new UnitType("manifold"){{

View File

@@ -0,0 +1,65 @@
package mindustry.type;
import arc.struct.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.world.*;
public class BlockSeq{
private ObjectIntMap<Block> blocks = new ObjectIntMap<>();
public void add(Block block){
blocks.increment(block);
}
public void add(Block block, int amount){
blocks.increment(block, amount);
}
public void remove(Block block){
add(block, -1);
}
public void remove(Block block, int amount){
add(block, -amount);
}
public void remove(Seq<BlockStack> stacks){
stacks.each(b -> remove(b.block, b.amount));
}
public void clear(){
blocks.clear();
}
public int get(Block block){
return blocks.get(block);
}
public boolean contains(Seq<BlockStack> stacks){
return !stacks.contains(b -> get(b.block) < b.amount);
}
public boolean contains(Block block, int amount){
return get(block) >= amount;
}
public boolean contains(BlockStack stack){
return get(stack.block) >= stack.amount;
}
public void write(Writes write){
write.s(blocks.size);
for(var entry : blocks.entries()){
write.s(entry.key.id);
write.i(entry.value);
}
}
public void read(Reads read){
short amount = read.s();
for(int i = 0; i < amount; i++){
blocks.put(Vars.content.block(read.s()), read.i());
}
}
}

View File

@@ -156,6 +156,7 @@ public class UnitType extends UnlockableContent{
public boolean singleTarget = false;
public boolean forceMultiTarget = false;
public boolean hidden = false;
public boolean internal = false;
//for crawlers
public int segments = 0;

View File

@@ -44,4 +44,8 @@ public class ItemImage extends Stack{
}));
}
}
public ItemImage(BlockStack stack){
this(stack.block.uiIcon, stack.amount);
}
}

View File

@@ -47,6 +47,7 @@ public class BuildTurret extends BaseTurret{
//this is super hacky, but since blocks are initialized before units it does not run into init/concurrent modification issues
unitType = new UnitType("turret-unit-" + name){{
hidden = true;
internal = true;
speed = 0f;
hitSize = 0f;
health = 1;

View File

@@ -124,6 +124,11 @@ public class Duct extends Block implements Autotiler{
Draw.reset();
}
@Override
public void payloadDraw(){
Draw.rect(fullIcon, x, y);
}
protected void drawAt(float x, float y, int bits, float rotation, SliceMode slice){
Draw.z(Layer.blockUnder);
Draw.rect(sliced(botRegions[bits], slice), x, y, rotation);

View File

@@ -1,14 +1,21 @@
package mindustry.world.blocks.units;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.blocks.payloads.*;
import mindustry.world.consumers.*;
import static mindustry.Vars.*;
@@ -20,13 +27,13 @@ import static mindustry.Vars.*;
* 3.
* */
public class UnitAssembler extends PayloadBlock{
public int areaSize = 10;
public int areaSize = 11;
public UnitType droneType;
public int dronesCreated = 4;
//TODO should be different for every tier.
public Seq<BlockStack> requirements = new Seq<>();
public UnitType output = UnitTypes.vanquish;
public UnitType output;
public UnitAssembler(String name){
super(name);
@@ -48,21 +55,62 @@ public class UnitAssembler extends PayloadBlock{
Tmp.r1.x += Geometry.d4x(rotation) * len;
Tmp.r1.y += Geometry.d4y(rotation) * len;
//TODO better visuals here?
//TODO better visuals here? dashLine looks bad
Drawf.dashRect(valid ? Pal.accent : Pal.remove, Tmp.r1);
}
@Override
public void setBars(){
super.setBars();
//TODO progress bar
//bars.add("progress", (UnitAssemblerBuild e) -> new Bar("bar.progress", Pal.ammo, e::fraction));
bars.add("units", (UnitAssemblerBuild e) ->
new Bar(() ->
Core.bundle.format("bar.unitcap",
Fonts.getUnicodeStr(output.name),
e.team.data().countType(output),
Units.getStringCap(e.team)
),
() -> Pal.power,
() -> (float)e.team.data().countType(output) / Units.getCap(e.team)
));
}
@Override
public void drawRequestRegion(BuildPlan plan, Eachable<BuildPlan> list){
Draw.rect(region, plan.drawx(), plan.drawy());
//Draw.rect(outRegion, plan.drawx(), plan.drawy(), plan.rotation * 90);
Draw.rect(topRegion, plan.drawx(), plan.drawy());
}
@Override
public void init(){
consumes.add(new ConsumePayloads(requirements, (UnitAssemblerBuild build) -> build.blocks));
super.init();
}
public class UnitAssemblerBuild extends PayloadBlockBuild<BuildPayload>{
public Seq<Unit> units = new Seq<>();
public BlockSeq blocks = new BlockSeq();
//TODO how should payloads be stored? counts of blocks? intmap? references?
//public Seq<BuildPayload> payloads = new Seq<>();
//TODO progress
//TODO how should payloads be stored exactly? counts of blocks? intmap? references?
public Vec2 getUnitSpawn(){
float len = tilesize * (areaSize + size)/2f;
float unitX = x + Geometry.d4x(rotation) * len, unitY = y + Geometry.d4y(rotation) * len;
return Tmp.v4.set(unitX, unitY);
}
@Override
public void updateTile(){
units.removeAll(u -> !u.isAdded() || u.dead);
if(consValid() && units.size < dronesCreated){
//units annoying, disabled for now
if(false && efficiency() > 0 && units.size < dronesCreated){
//TODO build animation? distribute spawning?
var unit = droneType.create(team);
if(unit instanceof BuildingTetherc bt){
@@ -76,29 +124,88 @@ public class UnitAssembler extends PayloadBlock{
units.add(unit);
}
//TODO units should move stuff into position
//TODO check if area is occupied
Vec2 spawn = getUnitSpawn();
//check if all requirements are met
if(consValid() & Units.canCreate(team, output)){
//TODO ???? should this even be part of a trigger
consume();
//TODO actually just goes poof
var unit = output.create(team);
unit.set(spawn.x + Mathf.range(0.001f), spawn.y + Mathf.range(0.001f));
unit.rotation = 90f;
unit.add();
Fx.spawn.at(unit);
blocks.clear();
}
//TODO drones need to indicate that they are in position and actually play an animation
}
@Override
public void draw(){
Draw.rect(region, x, y);
//Draw.rect(outRegion, x, y, rotdeg());
Draw.z(Layer.blockOver);
//payRotation = rotdeg();
//drawPayload();
Draw.z(Layer.blockOver + 0.1f);
Draw.rect(topRegion, x, y);
Vec2 spawn = getUnitSpawn();
//TODO which layer?
Draw.z(Layer.power - 1f);
Draw.mixcol(Pal.accent, 1f);
Draw.alpha(0.4f + Mathf.absin(10f, 0.2f));
Draw.rect(output.fullIcon, spawn.x, spawn.y);
Draw.reset();
}
@Override
public void handlePayload(Building source, Payload payload){
//super.handlePayload(source, payload);
blocks.add(((BuildPayload)payload).block());
//payloads.add((BuildPayload)payload);
}
@Override
public boolean acceptPayload(Building source, Payload payload){
return payload instanceof BuildPayload bp && requirements.contains(b -> b.block == bp.block());
return payload instanceof BuildPayload bp && requirements.contains(b -> b.block == bp.block() && blocks.get(bp.block()) < b.amount);
}
@Override
public void write(Writes write){
super.write(write);
//blocks.write(write);
//TODO save:
//- unit IDs
//- progress
//- payloads in position (should they have positions?)
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
//blocks.read(read);
}
}
}

View File

@@ -37,7 +37,7 @@ public class ConsumeItems extends Consume{
int i = 0;
for(var stack : items){
c.add(new ReqImage(new ItemImage(stack.item.uiIcon, stack.amount),
() -> build.items != null && build.items.has(stack.item, stack.amount))).padRight(8);
() -> build.items.has(stack.item, stack.amount))).padRight(8);
if(++i % 4 == 0) c.row();
}
}).left();

View File

@@ -0,0 +1,62 @@
package mindustry.world.consumers;
import arc.func.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.meta.*;
public class ConsumePayloads extends Consume{
//TODO bad, should be part of Building + dynamic
protected Func<Building, BlockSeq> inventory;
public Seq<BlockStack> payloads;
public <T extends Building> ConsumePayloads(Seq<BlockStack> payloads, Func<T, BlockSeq> inventory){
this.payloads = payloads;
this.inventory = (Func<Building, BlockSeq>)inventory;
}
@Override
public boolean valid(Building build){
return inventory.get(build).contains(payloads);
}
@Override
public void trigger(Building build){
inventory.get(build).remove(payloads);
}
@Override
public void display(Stats stats){
//TODO
for(var stack : payloads){
stats.add(Stat.input, t -> {
t.add(new ItemImage(stack));
t.add(stack.block.localizedName).padLeft(4).padRight(4);
});
}
}
@Override
public void build(Building build, Table table){
var inv = inventory.get(build);
table.table(c -> {
int i = 0;
for(var stack : payloads){
c.add(new ReqImage(new ItemImage(stack.block.uiIcon, stack.amount),
() -> inv.contains(stack.block, stack.amount))).padRight(8);
if(++i % 4 == 0) c.row();
}
}).left();
}
@Override
public ConsumeType type(){
return ConsumeType.payload;
}
}

View File

@@ -3,5 +3,6 @@ package mindustry.world.consumers;
public enum ConsumeType{
item,
power,
liquid
liquid,
payload
}