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)); requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3; size = 3;
itemCapacity = 1000; itemCapacity = 1000;
group = BlockGroup.storage;
}}; }};
container = new StorageBlock("container"){{ container = new StorageBlock("container"){{
requirements(Category.effect, with(Items.titanium, 100)); requirements(Category.effect, with(Items.titanium, 100));
size = 2; size = 2;
itemCapacity = 300; itemCapacity = 300;
group = BlockGroup.storage;
}}; }};
unloader = new Unloader("unloader"){{ unloader = new Unloader("unloader"){{
requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30)); requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30));
speed = 6f; speed = 6f;
group = BlockGroup.transportation;
}}; }};
//endregion //endregion

View File

@@ -85,7 +85,7 @@ public abstract class BulletType extends Content{
public float fragAngle = 0f; public float fragAngle = 0f;
public int fragBullets = 9; public int fragBullets = 9;
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f, fragLifeMin = 1f, fragLifeMax = 1f; 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 hitColor = Color.white;
public Color trailColor = Pal.missileYellowBack; 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(){ public void onRemoved(){
} }

View File

@@ -198,6 +198,8 @@ public class Block extends UnlockableContent{
public boolean instantTransfer = false; public boolean instantTransfer = false;
/** Whether you can rotate this block with Keybind rotateplaced + Scroll Wheel. */ /** Whether you can rotate this block with Keybind rotateplaced + Scroll Wheel. */
public boolean quickRotate = true; public boolean quickRotate = true;
/** Main subclass. Non-anonymous. */
public @Nullable Class<?> subclass;
public Prov<Building> buildType = null; //initialized later public Prov<Building> buildType = null; //initialized later
public ObjectMap<Class<?>, Cons2> configurations = new ObjectMap<>(); public ObjectMap<Class<?>, Cons2> configurations = new ObjectMap<>();
@@ -371,7 +373,7 @@ public class Block extends UnlockableContent{
public boolean canReplace(Block other){ public boolean canReplace(Block other){
if(other.alwaysReplace) return true; 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. */ /** @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(); current = current.getSuperclass();
} }
subclass = current;
while(buildType == null && Block.class.isAssignableFrom(current)){ while(buildType == null && Block.class.isAssignableFrom(current)){
//first class that is subclass of Building //first class that is subclass of Building
Class<?> type = Structs.find(current.getDeclaredClasses(), t -> Building.class.isAssignableFrom(t) && !t.isInterface()); 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.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.gen.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.ConstructBlock.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Build{ public class Build{
private static final IntSet tmp = new IntSet();
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void beginBreak(Team team, int x, int y){ public static void beginBreak(Team team, int x, int y){
@@ -36,7 +39,8 @@ public class Build{
tile.setBlock(sub, team, rotation); tile.setBlock(sub, team, rotation);
tile.<ConstructBuild>bc().setDeconstruct(previous); 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))); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true)));
} }
@@ -55,11 +59,23 @@ public class Build{
Block previous = tile.block(); Block previous = tile.block();
Block sub = ConstructBlock.get(result.size); Block sub = ConstructBlock.get(result.size);
Seq<Building> prevBuild = new Seq<>(9);
result.beforePlaceBegan(tile, previous); 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.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); result.placeBegan(tile, previous);
@@ -110,7 +126,9 @@ public class Build{
for(int dy = 0; dy < type.size; dy++){ for(int dy = 0; dy < type.size; dy++){
int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y; int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y;
Tile check = world.tile(wx, wy); Tile check = world.tile(wx, wy);
if( if(
check == null || //nothing there check == null || //nothing there
(check.floor().isDeep() && !type.floating && !type.requiresWater && !type.placeableLiquid) || //deep water (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){ public Seq<Tile> getLinkedTilesAs(Block block, Seq<Tile> tmpArray){
tmpArray.clear(); 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()){ if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2; int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2; int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){ for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){ for(int dy = 0; dy < block.size; dy++){
Tile other = world.tile(x + dx + offsetx, y + dy + offsety); Tile other = world.tile(x + dx + offsetx, y + dy + offsety);
if(other != null) tmpArray.add(other); if(other != null) tmpArray.get(other);
} }
} }
}else{ }else{
tmpArray.add(this); tmpArray.get(this);
} }
return tmpArray;
} }
public Rect getHitbox(Rect rect){ public Rect getHitbox(Rect rect){

View File

@@ -5,6 +5,7 @@ import arc.Graphics.*;
import arc.Graphics.Cursor.*; import arc.Graphics.Cursor.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import arc.util.*; import arc.util.*;
import arc.util.io.*; import arc.util.io.*;
@@ -62,6 +63,7 @@ public class ConstructBlock extends Block{
if(tile == null) return; if(tile == null) return;
float healthf = tile.build == null ? 1f : tile.build.healthf(); 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); tile.setBlock(block, team, rotation);
@@ -71,6 +73,10 @@ public class ConstructBlock extends Block{
if(config != null){ if(config != null){
tile.build.configured(builder, config); tile.build.configured(builder, config);
} }
if(prev != null && prev.size > 0){
tile.build.overwrote(prev);
}
} }
//last builder was this local client player, call placed() //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. * If there is no recipe for this block, as is the case with rocks, 'previous' is used.
*/ */
public @Nullable Block cblock; public @Nullable Block cblock;
public @Nullable Seq<Building> prevBuild;
public float progress = 0; public float progress = 0;
public float buildCost; 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 @Override
public boolean shouldIdleSound(){ public boolean shouldIdleSound(){
return clogHeat <= 0.5f ; return clogHeat <= 0.5f ;
@@ -161,11 +175,9 @@ public class Conveyor extends Block implements Autotiler{
blendscly = bits[2]; blendscly = bits[2];
blending = bits[4]; blending = bits[4];
if(front() != null && front() != null){ next = front();
next = front(); nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null;
nextc = next instanceof ConveyorBuild && next.team == team ? (ConveyorBuild)next : null; aligned = nextc != null && rotation == next.rotation;
aligned = nextc != null && rotation == next.rotation;
}
} }
@Override @Override
@@ -220,7 +232,7 @@ public class Conveyor extends Block implements Autotiler{
if(ys[i] > 0.5 && i > 0) mid = i - 1; if(ys[i] > 0.5 && i > 0) mid = i - 1;
xs[i] = Mathf.approachDelta(xs[i], 0, speed*2); 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 //align X position if passing forwards
if(aligned){ if(aligned){
nextc.xs[nextc.lastInserted] = xs[i]; nextc.xs[nextc.lastInserted] = xs[i];
@@ -242,6 +254,14 @@ public class Conveyor extends Block implements Autotiler{
noSleep(); 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 @Override
public int removeStack(Item item, int amount){ public int removeStack(Item item, int amount){
noSleep(); noSleep();
@@ -346,6 +366,9 @@ public class Conveyor extends Block implements Autotiler{
ys[i] = y; 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.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.io.*; import arc.util.io.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
@@ -14,6 +15,7 @@ import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.blocks.distribution.Conveyor.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
import static mindustry.Vars.*; 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 @Override
public boolean shouldIdleSound(){ public boolean shouldIdleSound(){
return false; // has no moving parts; return false; // has no moving parts;

View File

@@ -2,6 +2,7 @@ package mindustry.world.blocks.power;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.gen.*; import mindustry.gen.*;
@@ -31,5 +32,15 @@ public class Battery extends PowerDistributor{
Draw.rect(topRegion, x, y); 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; package mindustry.world.blocks.storage;
import arc.struct.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; 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 @Override
public boolean canPickup(){ public boolean canPickup(){
return linkedCore == null; return linkedCore == null;

View File

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