mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-11 07:39:39 +07:00
Improved replacement system
This commit is contained in:
parent
138434d029
commit
a3224b7082
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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(){
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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){
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user