Files
Mindustry/core/src/mindustry/entities/comp/PayloadComp.java
2021-11-01 09:41:33 -04:00

199 lines
5.5 KiB
Java

package mindustry.entities.comp;
import arc.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.core.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.payloads.*;
/** An entity that holds a payload. */
@Component
abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
@Import float x, y, rotation;
@Import UnitType type;
Seq<Payload> payloads = new Seq<>();
//uncomment for insanity
/*
private transient @Nullable PowerGraph payloadPower;
@Override
public void update(){
if(payloadPower != null){
payloadPower.clear();
}
//update power graph first, resolve everything
for(Payload pay : payloads){
if(pay instanceof BuildPayload pb && pb.build.power != null){
if(payloadPower == null) payloadPower = new PowerGraph();
pb.build.power.graph = null;
payloadPower.add(pb.build);
}
}
if(payloadPower != null){
payloadPower.update();
}
for(Payload pay : payloads){
pay.set(x, y, rotation);
pay.update(true);
}
}*/
float payloadUsed(){
return payloads.sumf(p -> p.size() * p.size());
}
boolean canPickup(Unit unit){
return payloadUsed() + unit.hitSize * unit.hitSize <= type.payloadCapacity + 0.001f && unit.team == team() && unit.isAI();
}
boolean canPickup(Building build){
return payloadUsed() + build.block.size * build.block.size * Vars.tilesize * Vars.tilesize <= type.payloadCapacity + 0.001f && build.canPickup();
}
boolean canPickupPayload(Payload pay){
return payloadUsed() + pay.size()*pay.size() <= type.payloadCapacity + 0.001f;
}
boolean hasPayload(){
return payloads.size > 0;
}
void addPayload(Payload load){
payloads.add(load);
}
void pickup(Unit unit){
unit.remove();
addPayload(new UnitPayload(unit));
Fx.unitPickup.at(unit);
if(Vars.net.client()){
Vars.netClient.clearRemovedEntity(unit.id);
}
Events.fire(new PickupEvent(self(), unit));
}
void pickup(Building tile){
tile.pickedUp();
tile.tile.remove();
tile.afterPickedUp();
addPayload(new BuildPayload(tile));
Fx.unitPickup.at(tile);
Events.fire(new PickupEvent(self(), tile));
}
boolean dropLastPayload(){
if(payloads.isEmpty()) return false;
Payload load = payloads.peek();
if(tryDropPayload(load)){
payloads.pop();
return true;
}
return false;
}
boolean tryDropPayload(Payload payload){
Tile on = tileOn();
//clear removed state of unit so it can be synced
if(Vars.net.client() && payload instanceof UnitPayload u){
Vars.netClient.clearRemovedEntity(u.unit.id);
}
//drop off payload on an acceptor if possible
if(on != null && on.build != null && on.build.acceptPayload(on.build, payload)){
Fx.unitDrop.at(on.build);
on.build.handlePayload(on.build, payload);
return true;
}
if(payload instanceof BuildPayload b){
return dropBlock(b);
}else if(payload instanceof UnitPayload p){
return dropUnit(p);
}
return false;
}
boolean dropUnit(UnitPayload payload){
Unit u = payload.unit;
//can't drop ground units
if(!u.canPass(tileX(), tileY()) || Units.count(x, y, u.physicSize(), o -> o.isGrounded()) > 1){
return false;
}
Fx.unitDrop.at(this);
//clients do not drop payloads
if(Vars.net.client()) return true;
u.set(this);
u.trns(Tmp.v1.rnd(Mathf.random(2f)));
u.rotation(rotation);
//reset the ID to a new value to make sure it's synced
u.id = EntityGroup.nextId();
//decrement count to prevent double increment
if(!u.isAdded()) u.team.data().updateCount(u.type, -1);
u.add();
u.unloaded();
return true;
}
/** @return whether the tile has been successfully placed. */
boolean dropBlock(BuildPayload payload){
Building tile = payload.build;
int tx = World.toTile(x - tile.block.offset), ty = World.toTile(y - tile.block.offset);
Tile on = Vars.world.tile(tx, ty);
if(on != null && Build.validPlace(tile.block, tile.team, tx, ty, tile.rotation, false)){
int rot = (int)((rotation + 45f) / 90f) % 4;
payload.place(on, rot);
if(getControllerName() != null){
payload.build.lastAccessed = getControllerName();
}
Fx.unitDrop.at(tile);
Fx.placeBlock.at(on.drawx(), on.drawy(), on.block().size);
return true;
}
return false;
}
void contentInfo(Table table, float itemSize, float width){
table.clear();
table.top().left();
float pad = 0;
float items = payloads.size;
if(itemSize * items + pad * items > width){
pad = (width - (itemSize) * items) / items;
}
for(Payload p : payloads){
table.image(p.icon()).size(itemSize).padRight(pad);
}
}
}