New unstable mass driver code

This commit is contained in:
Anuken
2019-04-20 21:10:52 -04:00
parent 75dcceff43
commit 7785ca55c2
2 changed files with 144 additions and 120 deletions

View File

@@ -88,7 +88,6 @@ public class MassDriverBolt extends BulletType{
if(!(b.getData() instanceof DriverBulletData)) return;
DriverBulletData data = (DriverBulletData)b.getData();
data.to.isRecieving = false;
for(int i = 0; i < data.items.length; i++){
int amountDropped = Mathf.random(0, data.items[i]);

View File

@@ -3,8 +3,7 @@ package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.Core;
import io.anuke.arc.collection.ObjectSet;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.collection.OrderedSet;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf;
@@ -63,47 +62,6 @@ public class MassDriver extends Block{
entity.link = position;
}
@Remote(called = Loc.server)
public static void onMassDriverFire(Tile tile, Tile target){
//just in case the client has invalid data
if(!(tile.entity instanceof MassDriverEntity) || !(target.entity instanceof MassDriverEntity)) return;
MassDriver driver = (MassDriver)tile.block();
MassDriverEntity entity = tile.entity();
MassDriverEntity other = target.entity();
entity.reload = 1f;
entity.power.satisfaction -= Math.min(entity.power.satisfaction, driver.powerPercentageUsed);
DriverBulletData data = Pools.obtain(DriverBulletData.class, DriverBulletData::new);
data.from = entity;
data.to = other;
int totalUsed = 0;
for(int i = 0; i < content.items().size; i++){
int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed);
data.items[i] = maxTransfer;
totalUsed += maxTransfer;
}
entity.items.clear();
float angle = tile.angleTo(target);
other.isRecieving = true;
Bullet.create(Bullets.driverBolt, entity, entity.getTeam(),
tile.drawx() + Angles.trnsx(angle, driver.translation), tile.drawy() + Angles.trnsy(angle, driver.translation),
angle, 1f, 1f, data);
Effects.effect(driver.shootEffect, tile.drawx() + Angles.trnsx(angle, driver.translation),
tile.drawy() + Angles.trnsy(angle, driver.translation), angle);
Effects.effect(driver.smokeEffect, tile.drawx() + Angles.trnsx(angle, driver.translation),
tile.drawy() + Angles.trnsy(angle, driver.translation), angle);
Effects.shake(driver.shake, driver.shake, entity);
}
@Override
public TextureRegion[] generateIcons(){
return new TextureRegion[]{Core.atlas.find(name + "-base"), Core.atlas.find(name)};
@@ -126,51 +84,78 @@ public class MassDriver extends Block{
@Override
public void update(Tile tile){
MassDriverEntity entity = tile.entity();
Tile link = world.tile(entity.link);
boolean hasLink = linkValid(tile);
if(entity.isUnloading){
tryDump(tile);
if(entity.items.total() <= 0){
entity.isUnloading = false;
}
}
//reload regardless of state
if(entity.reload > 0f){
entity.reload = Mathf.clamp(entity.reload - entity.delta() / reloadTime);
}
//unload when dest is full
if(!linkValid(tile) || (link.entity.items.total() >= itemCapacity) && entity.items.total() > 0){
entity.isUnloading = true;
//cleanup waiting shooters that are not valid
if(!shooterValid(tile, entity.currentShooter())){
entity.waitingShooters.remove(entity.currentShooter());
}
if(!entity.isRecieving){
if(entity.waiting.size > 0){ //accepting takes priority over shooting
Tile waiter = entity.waiting.first();
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(waiter), rotateSpeed);
}else if(tile.entity.items.total() >= minDistribute &&
linkValid(tile) &&
tile.entity.power.satisfaction >= powerPercentageUsed &&
link.block().itemCapacity - link.entity.items.total() >= minDistribute && entity.reload <= 0.0001f){
MassDriverEntity other = link.entity();
other.waiting.add(tile);
float target = tile.angleTo(link);
entity.rotation = Mathf.slerpDelta(entity.rotation, target, rotateSpeed);
if(Angles.near(entity.rotation, target, 1f) &&
Angles.near(other.rotation, target + 180f, 1f)){
Call.onMassDriverFire(tile, link);
}
//switch states
if(entity.state == DriverState.idle){
//start accepting when idle
if(!entity.waitingShooters.isEmpty()){
entity.state = DriverState.accepting;
}else if(hasLink){ //switch to shooting if there's a valid link.
entity.state = DriverState.shooting;
}
}
entity.waiting.clear();
//dump when idle or accepting
if(entity.state == DriverState.idle || entity.state == DriverState.accepting){
tryDump(tile);
}
if(entity.state == DriverState.accepting){
//if there's nothing shooting at this, bail
if(entity.currentShooter() == null){
entity.state = DriverState.idle;
return;
}
//align to shooter rotation
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed);
}else if(entity.state == DriverState.shooting){
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
if(!hasLink || !entity.waitingShooters.isEmpty()){
entity.state = DriverState.idle;
return;
}
float targetRotation = tile.angleTo(link);
if(
tile.entity.items.total() >= minDistribute && //must shoot minimum amount of items
tile.entity.power.satisfaction >= powerPercentageUsed && //must have power
link.block().itemCapacity - link.entity.items.total() >= minDistribute && //must have minimum amount of space
entity.reload <= 0.0001f //must have reloaded
){
MassDriverEntity other = link.entity();
other.waitingShooters.add(tile);
//align to target location
entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed);
//fire when it's the first in the queue and angles are ready.
if(other.currentShooter() == tile &&
other.state == DriverState.accepting &&
Angles.near(entity.rotation, targetRotation, 2f) && Angles.near(other.rotation, targetRotation + 180f, 2f)){
//actually fire
fire(tile, link);
//remove waiting shooters, it's done firing
other.waitingShooters.remove(tile);
//set both states to idle
entity.state = DriverState.idle;
other.state = DriverState.idle;
}
}
}
}
@Override
@@ -244,7 +229,71 @@ public class MassDriver extends Block{
return new MassDriverEntity();
}
protected void fire(Tile tile, Tile target){
MassDriverEntity entity = tile.entity();
MassDriverEntity other = target.entity();
//reset reload, use power.
entity.reload = 1f;
entity.power.satisfaction -= Math.min(entity.power.satisfaction, powerPercentageUsed);
DriverBulletData data = Pools.obtain(DriverBulletData.class, DriverBulletData::new);
data.from = entity;
data.to = other;
int totalUsed = 0;
for(int i = 0; i < content.items().size; i++){
int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed);
data.items[i] = maxTransfer;
totalUsed += maxTransfer;
}
entity.items.clear();
float angle = tile.angleTo(target);
Bullet.create(Bullets.driverBolt, entity, entity.getTeam(),
tile.drawx() + Angles.trnsx(angle, translation), tile.drawy() + Angles.trnsy(angle, translation),
angle, 1f, 1f, data);
Effects.effect(shootEffect, tile.drawx() + Angles.trnsx(angle, translation),
tile.drawy() + Angles.trnsy(angle, translation), angle);
Effects.effect(smokeEffect, tile.drawx() + Angles.trnsx(angle, translation),
tile.drawy() + Angles.trnsy(angle, translation), angle);
Effects.shake(shake, shake, entity);
}
protected void handlePayload(MassDriverEntity entity, Bullet bullet, DriverBulletData data){
int totalItems = entity.items.total();
//add all the items possible
for(int i = 0; i < data.items.length; i++){
int maxAdd = Math.min(data.items[i], itemCapacity * 2 - totalItems);
entity.items.add(content.item(i), maxAdd);
data.items[i] -= maxAdd;
totalItems += maxAdd;
if(totalItems >= itemCapacity * 2){
break;
}
}
Effects.shake(shake, shake, entity);
Effects.effect(recieveEffect, bullet);
entity.reload = 1f;
bullet.remove();
}
protected boolean shooterValid(Tile tile, Tile other){
if(other == null) return true;
if(!(other.block() instanceof MassDriver)) return false;
MassDriverEntity entity = other.entity();
return entity.link == tile.pos() && tile.dst(other) <= range;
}
protected boolean linkValid(Tile tile){
if(tile == null) return false;
MassDriverEntity entity = tile.entity();
if(entity == null || entity.link == -1) return false;
Tile link = world.tile(entity.link);
@@ -264,63 +313,39 @@ public class MassDriver extends Block{
}
public class MassDriverEntity extends TileEntity{
public int link = -1;
public float rotation = 90;
//set of tiles that currently want to distribute to this tile
public ObjectSet<Tile> waiting = new ObjectSet<>();
//whether this mass driver is waiting for a bullet to hit it and deliver items
public boolean isRecieving;
//whether this driver just recieved some items and is now unloading
public boolean isUnloading = true;
int link = -1;
float rotation = 90;
float reload = 0f;
DriverState state = DriverState.idle;
OrderedSet<Tile> waitingShooters = new OrderedSet<>();
public float reload = 0f;
Tile currentShooter(){
return waitingShooters.isEmpty() ? null : waitingShooters.first();
}
public void handlePayload(Bullet bullet, DriverBulletData data){
int totalItems = items.total();
//add all the items possible
for(int i = 0; i < data.items.length; i++){
int maxAdd = Math.min(data.items[i], itemCapacity * 2 - totalItems);
items.add(content.item(i), maxAdd);
data.items[i] -= maxAdd;
totalItems += maxAdd;
if(totalItems >= itemCapacity * 2){
break;
}
}
//drop all items remaining on the ground
for(int i = 0; i < data.items.length; i++){
int amountDropped = Mathf.random(0, data.items[i]);
if(amountDropped > 0){
float angle = Mathf.range(180f);
Effects.effect(Fx.dropItem, Color.WHITE, bullet.x, bullet.y, angle, content.item(i));
}
}
reload = 1f;
Effects.shake(shake, shake, this);
Effects.effect(recieveEffect, bullet);
isRecieving = false;
bullet.remove();
if(!linkValid(tile)){
isUnloading = true;
}
((MassDriver)block).handlePayload(this, bullet, data);
}
@Override
public void write(DataOutput stream) throws IOException{
stream.writeInt(link);
stream.writeFloat(rotation);
stream.writeByte((byte)state.ordinal());
}
@Override
public void read(DataInput stream) throws IOException{
link = stream.readInt();
rotation = stream.readFloat();
state = DriverState.values()[stream.readByte()];
}
}
enum DriverState{
idle, //nothing is shooting at this mass driver and it does not have any target
accepting, //currently getting shot at, unload items
shooting,
unloading
}
}