Improved replacement system

This commit is contained in:
Anuken 2020-10-02 11:14:18 -04:00
parent 138434d029
commit a3224b7082
13 changed files with 123 additions and 14 deletions

View File

@ -1350,17 +1350,20 @@ public class Blocks implements ContentList{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3;
itemCapacity = 1000;
group = BlockGroup.storage;
}};
container = new StorageBlock("container"){{
requirements(Category.effect, with(Items.titanium, 100));
size = 2;
itemCapacity = 300;
group = BlockGroup.storage;
}};
unloader = new Unloader("unloader"){{
requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30));
speed = 6f;
group = BlockGroup.transportation;
}};
//endregion

View File

@ -85,7 +85,7 @@ public abstract class BulletType extends Content{
public float fragAngle = 0f;
public int fragBullets = 9;
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f, fragLifeMin = 1f, fragLifeMax = 1f;
public BulletType fragBullet = null;
public @Nullable BulletType fragBullet = null;
public Color hitColor = Color.white;
public Color trailColor = Pal.missileYellowBack;

View File

@ -849,6 +849,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
}
/**
* Called when a block is placed over some other blocks. This seq will always have at least one item.
* Should load some previous state, if necessary. */
public void overwrote(Seq<Building> previous){
}
public void onRemoved(){
}

View File

@ -198,6 +198,8 @@ public class Block extends UnlockableContent{
public boolean instantTransfer = false;
/** Whether you can rotate this block with Keybind rotateplaced + Scroll Wheel. */
public boolean quickRotate = true;
/** Main subclass. Non-anonymous. */
public @Nullable Class<?> subclass;
public Prov<Building> buildType = null; //initialized later
public ObjectMap<Class<?>, Cons2> configurations = new ObjectMap<>();
@ -371,7 +373,7 @@ public class Block extends UnlockableContent{
public boolean canReplace(Block other){
if(other.alwaysReplace) return true;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && size == other.size;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && (size == other.size || (size >= other.size && subclass != null && subclass == other.subclass));
}
/** @return a possible replacement for this block when placed in a line by the player. */
@ -590,6 +592,8 @@ public class Block extends UnlockableContent{
current = current.getSuperclass();
}
subclass = current;
while(buildType == null && Block.class.isAssignableFrom(current)){
//first class that is subclass of Building
Class<?> type = Structs.find(current.getDeclaredClasses(), t -> Building.class.isAssignableFrom(t) && !t.isInterface());

View File

@ -3,18 +3,21 @@ package mindustry.world;
import arc.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.ConstructBlock.*;
import static mindustry.Vars.*;
public class Build{
private static final IntSet tmp = new IntSet();
@Remote(called = Loc.server)
public static void beginBreak(Team team, int x, int y){
@ -36,7 +39,8 @@ public class Build{
tile.setBlock(sub, team, rotation);
tile.<ConstructBuild>bc().setDeconstruct(previous);
tile.build.health(tile.build.maxHealth() * prevPercent);
tile.build.health = tile.build.maxHealth * prevPercent;
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true)));
}
@ -55,11 +59,23 @@ public class Build{
Block previous = tile.block();
Block sub = ConstructBlock.get(result.size);
Seq<Building> prevBuild = new Seq<>(9);
result.beforePlaceBegan(tile, previous);
tmp.clear();
tile.getLinkedTilesAs(result, t -> {
if(t.build != null && t.build.team == team && tmp.add(t.build.id)){
prevBuild.add(t.build);
}
});
tile.setBlock(sub, team, rotation);
tile.<ConstructBuild>bc().setConstruct(previous.size == sub.size ? previous : Blocks.air, result);
ConstructBuild build = tile.bc();
build.setConstruct(previous.size == sub.size ? previous : Blocks.air, result);
build.prevBuild = prevBuild;
result.placeBegan(tile, previous);
@ -110,7 +126,9 @@ public class Build{
for(int dy = 0; dy < type.size; dy++){
int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y;
Tile check = world.tile(wx, wy);
if(
check == null || //nothing there
(check.floor().isDeep() && !type.floating && !type.requiresWater && !type.placeableLiquid) || //deep water

View File

@ -389,19 +389,27 @@ public class Tile implements Position, QuadTreeObject, Displayable{
*/
public Seq<Tile> getLinkedTilesAs(Block block, Seq<Tile> tmpArray){
tmpArray.clear();
getLinkedTilesAs(block, tmpArray::add);
return tmpArray;
}
/**
* Returns the list of all tiles linked to this multiblock if it were this block.
* The result contains all linked tiles, including this tile itself.
*/
public void getLinkedTilesAs(Block block, Cons<Tile> tmpArray){
if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
Tile other = world.tile(x + dx + offsetx, y + dy + offsety);
if(other != null) tmpArray.add(other);
if(other != null) tmpArray.get(other);
}
}
}else{
tmpArray.add(this);
tmpArray.get(this);
}
return tmpArray;
}
public Rect getHitbox(Rect rect){

View File

@ -5,6 +5,7 @@ import arc.Graphics.*;
import arc.Graphics.Cursor.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import arc.util.io.*;
@ -62,6 +63,7 @@ public class ConstructBlock extends Block{
if(tile == null) return;
float healthf = tile.build == null ? 1f : tile.build.healthf();
Seq<Building> prev = tile.build instanceof ConstructBuild ? ((ConstructBuild)tile.build).prevBuild : null;
tile.setBlock(block, team, rotation);
@ -71,6 +73,10 @@ public class ConstructBlock extends Block{
if(config != null){
tile.build.configured(builder, config);
}
if(prev != null && prev.size > 0){
tile.build.overwrote(prev);
}
}
//last builder was this local client player, call placed()
@ -126,6 +132,7 @@ public class ConstructBlock extends Block{
* If there is no recipe for this block, as is the case with rocks, 'previous' is used.
*/
public @Nullable Block cblock;
public @Nullable Seq<Building> prevBuild;
public float progress = 0;
public float buildCost;

View File

@ -146,6 +146,20 @@ public class Conveyor extends Block implements Autotiler{
}
}
@Override
public void overwrote(Seq<Building> builds){
if(builds.first() instanceof ConveyorBuild build){
ids = build.ids.clone();
xs = build.xs.clone();
ys = build.ys.clone();
len = build.len;
clogHeat = build.clogHeat;
lastInserted = build.lastInserted;
mid = build.mid;
minitem = build.minitem;
}
}
@Override
public boolean shouldIdleSound(){
return clogHeat <= 0.5f ;
@ -161,11 +175,9 @@ public class Conveyor extends Block implements Autotiler{
blendscly = bits[2];
blending = bits[4];
if(front() != null && front() != null){
next = front();
nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null;
aligned = nextc != null && rotation == next.rotation;
}
next = front();
nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null;
aligned = nextc != null && rotation == next.rotation;
}
@Override
@ -220,7 +232,7 @@ public class Conveyor extends Block implements Autotiler{
if(ys[i] > 0.5 && i > 0) mid = i - 1;
xs[i] = Mathf.approachDelta(xs[i], 0, speed*2);
if(ys[i] >= 1f && moveForward(ids[i])){
if(ys[i] >= 1f && pass(ids[i])){
//align X position if passing forwards
if(aligned){
nextc.xs[nextc.lastInserted] = xs[i];
@ -242,6 +254,14 @@ public class Conveyor extends Block implements Autotiler{
noSleep();
}
public boolean pass(Item item) {
if(next != null && next.team == team && next.acceptItem(this, item)){
next.handleItem(this, item);
return true;
}
return false;
}
@Override
public int removeStack(Item item, int amount){
noSleep();
@ -346,6 +366,9 @@ public class Conveyor extends Block implements Autotiler{
ys[i] = y;
}
}
//this updates some state
updateTile();
}

View File

@ -2,6 +2,7 @@ package mindustry.world.blocks.distribution;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
@ -14,6 +15,7 @@ import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.distribution.Conveyor.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@ -220,6 +222,16 @@ public class StackConveyor extends Block implements Autotiler{
}
}
@Override
public void overwrote(Seq<Building> builds){
if(builds.first() instanceof ConveyorBuild build){
Item item = build.items.first();
if(item != null){
handleStack(item, build.items.get(itemCapacity), null);
}
}
}
@Override
public boolean shouldIdleSound(){
return false; // has no moving parts;

View File

@ -2,6 +2,7 @@ package mindustry.world.blocks.power;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import mindustry.annotations.Annotations.*;
import mindustry.gen.*;
@ -31,5 +32,15 @@ public class Battery extends PowerDistributor{
Draw.rect(topRegion, x, y);
}
@Override
public void overwrote(Seq<Building> previous){
for(Building other : previous){
if(other.power != null && other.block.consumes.hasPower() && other.block.consumes.getPower().buffered){
float amount = other.block.consumes.getPower().capacity * other.power.status;
power.status = Mathf.clamp(power.status + amount / block.consumes.getPower().capacity);
}
}
}
}
}

View File

@ -1,5 +1,6 @@
package mindustry.world.blocks.storage;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import mindustry.gen.*;
import mindustry.type.*;
@ -40,6 +41,18 @@ public abstract class StorageBlock extends Block{
}
}
@Override
public void overwrote(Seq<Building> previous){
for(Building other : previous){
if(other.items != null){
items.addAll(other.items);
}
}
//ensure item counts are not too high
items.each((i, a) -> items.set(i, Math.min(a, itemCapacity)));
}
@Override
public boolean canPickup(){
return linkedCore == null;

View File

@ -1,5 +1,5 @@
package mindustry.world.meta;
public enum BlockGroup{
none, walls, turrets, transportation, power, liquids, drills
none, walls, turrets, transportation, power, liquids, drills, storage
}

View File

@ -180,6 +180,7 @@ public class ItemModule extends BlockModule{
return total > 0;
}
@Nullable
public Item first(){
for(int i = 0; i < items.length; i++){
if(items[i] > 0){
@ -189,6 +190,7 @@ public class ItemModule extends BlockModule{
return null;
}
@Nullable
public Item take(){
for(int i = 0; i < items.length; i++){
int index = (i + takeRotation);
@ -204,6 +206,7 @@ public class ItemModule extends BlockModule{
}
/** Begins a speculative take operation. This returns the item that would be returned by #take(), but does not change state. */
@Nullable
public Item beginTake(){
for(int i = 0; i < items.length; i++){
int index = (i + takeRotation);