This commit is contained in:
Anuken
2020-03-05 18:05:59 -05:00
parent 2dfbbdfd5b
commit 5a0d079a78
62 changed files with 1296 additions and 1352 deletions

View File

@@ -1,8 +1,6 @@
package mindustry.world;
import arc.*;
import arc.Graphics.*;
import arc.Graphics.Cursor.*;
import arc.audio.*;
import arc.func.*;
import arc.graphics.*;
@@ -11,11 +9,11 @@ import arc.graphics.g2d.TextureAtlas.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.Array;
import arc.struct.EnumSet;
import arc.struct.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import arc.util.pooling.*;
import mindustry.annotations.Annotations.*;
import mindustry.ctype.*;
import mindustry.entities.*;
@@ -26,18 +24,34 @@ import mindustry.graphics.MultiPacker.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.power.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
import mindustry.world.meta.values.*;
import java.lang.reflect.*;
import java.util.*;
import static mindustry.Vars.*;
import static mindustry.Vars.tilesize;
public class Block extends BlockStorage{
public class Block extends UnlockableContent{
public static final int crackRegions = 8, maxCrackSize = 5;
public boolean hasItems;
public boolean hasLiquids;
public boolean hasPower;
public boolean outputsLiquid = false;
public boolean consumesPower = true;
public boolean outputsPower = false;
public int itemCapacity = 10;
public float liquidCapacity = 10f;
public float liquidPressure = 1f;
public final BlockStats stats = new BlockStats();
public final BlockBars bars = new BlockBars();
public final Consumers consumes = new Consumers();
/** whether this block has a tile entity that updates */
public boolean update;
/** whether this block has health and can be destroyed */
@@ -140,12 +154,13 @@ public class Block extends BlockStorage{
public boolean instantTransfer = false;
public boolean alwaysUnlocked = false;
protected Prov<Tilec> entityType = null; //initialized later
protected TextureRegion[] cacheRegions = {};
protected Array<String> cacheRegionStrings = new Array<>();
protected Prov<Tilec> entityType = TileEntity::create;
protected ObjectMap<Class<?>, ConfigHandler> configurations = new ObjectMap<>();
protected ObjectMap<Class<?>, Cons2> configurations = new ObjectMap<>();
protected Array<Tile> tempTiles = new Array<>();
protected Array<Tilec> tempTileEnts = new Array<>();
protected TextureRegion[] generatedIcons;
protected TextureRegion[] variantRegions, editorVariantRegions;
protected TextureRegion region, editorIcon;
@@ -162,302 +177,6 @@ public class Block extends BlockStorage{
this.solid = false;
}
public boolean isAir(){
return id == 0;
}
public boolean canBreak(Tile tile){
return true;
}
public boolean isBuildable(){
return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly;
}
public boolean isStatic(){
return cacheLayer == CacheLayer.walls;
}
public void onProximityRemoved(Tile tile){
if(tile.entity.power() != null){
tile.block().powerGraphRemoved(tile);
}
}
public void onProximityAdded(Tile tile){
if(tile.block().hasPower) tile.block().updatePowerGraph(tile);
}
protected void updatePowerGraph(Tile tile){
Tilec entity = tile.ent();
for(Tile other : getPowerConnections(tile, tempTiles)){
if(other.entity.power() != null){
other.entity.power().graph.add(entity.power().graph);
}
}
}
protected void powerGraphRemoved(Tile tile){
if(tile.entity == null || tile.entity.power() == null){
return;
}
tile.entity.power().graph.remove(tile);
for(int i = 0; i < tile.entity.power().links.size; i++){
Tile other = world.tile(tile.entity.power().links.get(i));
if(other != null && other.entity != null && other.entity.power() != null){
other.entity.power().links.removeValue(tile.pos());
}
}
}
public Array<Tile> getPowerConnections(Tile tile, Array<Tile> out){
out.clear();
if(tile == null || tile.entity == null || tile.entity.power() == null) return out;
for(Tile other : tile.entity.proximity()){
if(other != null && other.entity != null && other.entity.power() != null
&& !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower)
&& !tile.entity.power().links.contains(other.pos())){
out.add(other);
}
}
for(int i = 0; i < tile.entity.power().links.size; i++){
Tile link = world.tile(tile.entity.power().links.get(i));
if(link != null && link.entity != null && link.entity.power() != null) out.add(link);
}
return out;
}
protected float getProgressIncrease(Tilec entity, float baseTime){
return 1f / baseTime * entity.delta() * entity.efficiency();
}
/** @return whether this block should play its active sound.*/
public boolean shouldActiveSound(Tile tile){
return false;
}
/** @return whether this block should play its idle sound.*/
public boolean shouldIdleSound(Tile tile){
return shouldConsume(tile);
}
public void drawLayer(Tile tile){
}
public void drawLayer2(Tile tile){
}
public void drawCracks(Tile tile){
if(!tile.entity.damaged() || size > maxCrackSize) return;
int id = tile.pos();
TextureRegion region = cracks[size - 1][Mathf.clamp((int)((1f - tile.entity.healthf()) * crackRegions), 0, crackRegions-1)];
Draw.colorl(0.2f, 0.1f + (1f - tile.entity.healthf())* 0.6f);
Draw.rect(region, tile.drawx(), tile.drawy(), (id%4)*90);
Draw.color();
}
/** Draw the block overlay that is shown when a cursor is over the block. */
public void drawSelect(Tile tile){
}
/** Drawn when you are placing a block. */
public void drawPlace(int x, int y, int rotation, boolean valid){
}
public float drawPlaceText(String text, int x, int y, boolean valid){
if(renderer.pixelator.enabled()) return 0;
Color color = valid ? Pal.accent : Pal.remove;
BitmapFont font = Fonts.outline;
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
boolean ints = font.usesIntegerPositions();
font.setUseIntegerPositions(false);
font.getData().setScale(1f / 4f / Scl.scl(1f));
layout.setText(font, text);
float width = layout.width;
font.setColor(color);
float dx = x * tilesize + offset(), dy = y * tilesize + offset() + size * tilesize / 2f + 3;
font.draw(text, dx, dy + layout.height + 1, Align.center);
dy -= 1f;
Lines.stroke(2f, Color.darkGray);
Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy);
Lines.stroke(1f, color);
Lines.line(dx - layout.width / 2f - 2f, dy, dx + layout.width / 2f + 1.5f, dy);
font.setUseIntegerPositions(ints);
font.setColor(Color.white);
font.getData().setScale(1f);
Draw.reset();
Pools.free(layout);
return width;
}
public void draw(Tile tile){
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.rotation() * 90 : 0);
}
public void drawLight(Tile tile){
if(tile.entity != null && hasLiquids && drawLiquidLight && tile.entity.liquids().current().lightColor.a > 0.001f){
drawLiquidLight(tile, tile.entity.liquids().current(), tile.entity.liquids().smoothAmount());
}
}
public void drawLiquidLight(Tile tile, Liquid liquid, float amount){
if(amount > 0.01f){
Color color = liquid.lightColor;
float fract = 1f;
float opacity = color.a * fract;
if(opacity > 0.001f){
renderer.lights.add(tile.drawx(), tile.drawy(), size * 30f * fract, color, opacity);
}
}
}
public void drawTeam(Tile tile){
Draw.color(tile.team().color);
Draw.rect("block-border", tile.drawx() - size * tilesize / 2f + 4, tile.drawy() - size * tilesize / 2f + 4);
Draw.color();
}
/** Called after the block is placed by this client. */
@CallSuper
public void playerPlaced(Tile tile){
}
/** Called after the block is placed by anyone. */
@CallSuper
public void placed(Tile tile){
if(net.client()) return;
if((consumesPower && !outputsPower) || (!consumesPower && outputsPower)){
int range = 10;
tempTiles.clear();
Geometry.circle(tile.x, tile.y, range, (x, y) -> {
Tile other = world.ltile(x, y);
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, tile) && !PowerNode.insulated(other, tile) && !other.entity.proximity().contains(tile) &&
!(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power() != null && p.entity.power().graph == other.entity.power().graph))){
tempTiles.add(other);
}
});
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
if(!tempTiles.isEmpty()){
Tile toLink = tempTiles.first();
if(!toLink.entity.power().links.contains(tile.pos())){
toLink.configureAny(tile.pos());
}
}
}
}
public void removed(Tile tile){
}
/** Called every frame a unit is on this tile. */
public void unitOn(Tile tile, Unitc unit){
}
/** Called when a unit that spawned at this tile is removed. */
public void unitRemoved(Tile tile, Unitc unit){
}
/** Returns whether ot not this block can be place on the specified tile. */
public boolean canPlaceOn(Tile tile){
return true;
}
/** Call when some content is produced. This unlocks the content if it is applicable. */
public void useContent(Tile tile, UnlockableContent content){
//only unlocks content in zones
if(!headless && tile.team() == player.team() && state.isCampaign()){
logic.handleContent(content);
}
}
public float sumAttribute(Attribute attr, int x, int y){
Tile tile = world.tile(x, y);
if(tile == null) return 0;
float sum = 0;
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
sum += other.floor().attributes.get(attr);
}
return sum;
}
public float percentSolid(int x, int y){
Tile tile = world.tile(x, y);
if(tile == null) return 0;
float sum = 0;
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
sum += !other.floor.isLiquid ? 1f : 0f;
}
return sum / size / size;
}
@Override
public void displayInfo(Table table){
ContentDisplay.displayBlock(table, this);
}
@Override
public ContentType getContentType(){
return ContentType.block;
}
/** Called after all blocks are created. */
@Override
@CallSuper
public void init(){
//initialize default health based on size
if(health == -1){
health = size * size * 40;
}
buildCost = 0f;
for(ItemStack stack : requirements){
buildCost += stack.amount * stack.item.cost;
}
buildCost *= buildCostMultiplier;
if(consumes.has(ConsumeType.power)) hasPower = true;
if(consumes.has(ConsumeType.item)) hasItems = true;
if(consumes.has(ConsumeType.liquid)) hasLiquids = true;
setStats();
setBars();
consumes.init();
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
throw new IllegalArgumentException("Consumer using buffered power: " + name);
}
}
@Override
public void load(){
region = Core.atlas.find(name);
cacheRegions = new TextureRegion[cacheRegionStrings.size];
for(int i = 0; i < cacheRegions.length; i++){
cacheRegions[i] = Core.atlas.find(cacheRegionStrings.get(i));
}
if(cracks == null || (cracks[0][0].getTexture() != null && cracks[0][0].getTexture().isDisposed())){
cracks = new TextureRegion[maxCrackSize][crackRegions];
for(int size = 1; size <= maxCrackSize; size++){
for(int i = 0; i < crackRegions; i++){
cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i);
}
}
}
}
/** Adds a region by name to be loaded, with the final name "{name}-suffix". Returns an ID to looks this region up by in {@link #reg(int)}. */
protected int reg(String suffix){
cacheRegionStrings.add(name + suffix);
@@ -469,78 +188,10 @@ public class Block extends BlockStorage{
return cacheRegions[id];
}
/** Called when the block is tapped. This is equivalent to being configured with null. */
public void tapped(Tile tile, Playerc player){
}
/** Called when arbitrary configuration is applied to a tile. */
public void configured(Tile tile, @Nullable Playerc player, @Nullable Object value){
//null is of type Void.class; anonymous classes use their superclass.
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
if(configurations.containsKey(type)){
configurations.get(type).configured(tile, value);
}
}
/** Configure when a null value is passed.*/
public void configClear(Cons<Tile> cons){
configurations.put(void.class, (tile, value) -> cons.get(tile));
}
/** Listen for a config by class type. */
public <T> void config(Class<T> type, ConfigHandler<T> config){
configurations.put(type, config);
}
/** Returns whether or not a hand cursor should be shown over this block. */
public Cursor getCursor(Tile tile){
return configurable ? SystemCursor.hand : SystemCursor.arrow;
}
/**
* Called when this block is tapped to build a UI on the table.
* {@link #configurable} must return true for this to be called.
*/
public void buildConfiguration(Tile tile, Table table){
}
/** Update table alignment after configuring.*/
public void updateTableAlign(Tile tile, Table table){
Vec2 pos = Core.input.mouseScreen(tile.drawx(), tile.drawy() - tile.block().size * tilesize / 2f - 1);
table.setPosition(pos.x, pos.y, Align.top);
}
/**
* Called when another tile is tapped while this block is selected.
* Returns whether or not this block should be deselected.
*/
public boolean onConfigureTileTapped(Tile tile, Tile other){
return tile != other;
}
/** Returns whether this config menu should show when the specified player taps it. */
public boolean shouldShowConfigure(Tile tile, Playerc player){
return true;
}
/** Whether this configuration should be hidden now. Called every frame the config is open. */
public boolean shouldHideConfigure(Tile tile, Playerc player){
return false;
}
public boolean synthetic(){
return update || destructible;
}
public void drawConfigure(Tile tile){
Draw.color(Pal.accent);
Lines.stroke(1f);
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1f);
Draw.reset();
}
public void setStats(){
stats.add(BlockStat.size, "{0}x{0}", size);
stats.add(BlockStat.health, health, StatUnit.none);
@@ -568,7 +219,7 @@ public class Block extends BlockStorage{
current = entity -> entity.liquids().current();
}
bars.add("liquid", entity -> new Bar(() -> entity.liquids().get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName,
() -> current.get(entity).barColor(), () -> entity.liquids().get(current.get(entity)) / liquidCapacity));
() -> current.get(entity).barColor(), () -> entity.liquids().get(current.get(entity)) / liquidCapacity));
}
if(hasPower && consumes.hasPower()){
@@ -577,7 +228,7 @@ public class Block extends BlockStorage{
float capacity = cons.capacity;
bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power().status * capacity) ? "<ERROR>" : (int)(entity.power().status * capacity)) :
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power().graph.getPowerProduced() + entity.power().graph.getBatteryStored() > 0f ? 1f : entity.power().status));
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power().graph.getPowerProduced() + entity.power().graph.getBatteryStored() > 0f ? 1f : entity.power().status));
}
if(hasItems && configurable){
@@ -585,14 +236,6 @@ public class Block extends BlockStorage{
}
}
public Tile linked(Tile tile){
return tile;
}
public boolean isSolidFor(Tile tile){
return false;
}
public boolean canReplace(Block other){
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group;
}
@@ -602,129 +245,6 @@ public class Block extends BlockStorage{
return this;
}
public float handleDamage(Tile tile, float amount){
return amount;
}
public void handleBulletHit(Tilec entity, Bulletc bullet){
entity.damage(bullet.damage());
}
public void update(Tile tile){
}
public boolean isAccessible(){
return (hasItems && itemCapacity > 0);
}
/** Called when the block is destroyed. */
public void onDestroyed(Tile tile){
float x = tile.worldx(), y = tile.worldy();
float explosiveness = baseExplosiveness;
float flammability = 0f;
float power = 0f;
if(hasItems){
for(Item item : content.items()){
int amount = tile.entity.items().get(item);
explosiveness += item.explosiveness * amount;
flammability += item.flammability * amount;
}
}
if(hasLiquids){
flammability += tile.entity.liquids().sum((liquid, amount) -> liquid.explosiveness * amount / 2f);
explosiveness += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 2f);
}
if(consumes.hasPower() && consumes.getPower().buffered){
power += tile.entity.power().status * consumes.getPower().capacity;
}
if(hasLiquids){
tile.entity.liquids().each((liquid, amount) -> {
float splash = Mathf.clamp(amount / 4f, 0f, 10f);
for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){
Time.run(i / 2f, () -> {
Tile other = world.tile(tile.x + Mathf.range(size / 2), tile.y + Mathf.range(size / 2));
if(other != null){
Puddles.deposit(other, liquid, splash);
}
});
}
});
}
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame);
if(!tile.floor().solid && !tile.floor().isLiquid){
Effects.rubble(tile.drawx(), tile.drawy(), size);
}
}
/**
* Returns the flammability of the tile. Used for fire calculations.
* Takes flammability of floor liquid into account.
*/
public float getFlammability(Tile tile){
if(!hasItems || tile.entity == null){
if(tile.floor().isLiquid && !solid){
return tile.floor().liquidDrop.flammability;
}
return 0;
}else{
float result = tile.entity.items().sum((item, amount) -> item.flammability * amount);
if(hasLiquids){
result += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 3f);
}
return result;
}
}
public String getDisplayName(Tile tile){
return localizedName;
}
public TextureRegion getDisplayIcon(Tile tile){
return icon(Cicon.medium);
}
public void display(Tile tile, Table table){
Tilec entity = tile.entity;
if(entity != null){
table.table(bars -> {
bars.defaults().growX().height(18f).pad(4);
displayBars(tile, bars);
}).growX();
table.row();
table.table(ctable -> {
displayConsumption(tile, ctable);
}).growX();
table.marginBottom(-5);
}
}
public void displayConsumption(Tile tile, Table table){
table.left();
for(Consume cons : consumes.all()){
if(cons.isOptional() && cons.isBoost()) continue;
cons.build(tile, table);
}
}
public void displayBars(Tile tile, Table table){
for(Func<Tilec, Bar> bar : bars.list()){
table.add(bar.get(tile.entity)).growX();
table.row();
}
}
public void drawRequest(BuildRequest req, Eachable<BuildRequest> list, boolean valid){
Draw.reset();
Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f));
@@ -736,9 +256,9 @@ public class Block extends BlockStorage{
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
TextureRegion reg = getRequestRegion(req, list);
Draw.rect(reg, req.drawx(), req.drawy(),
reg.getWidth() * req.animScale * Draw.scl,
reg.getHeight() * req.animScale * Draw.scl,
!rotate ? 0 : req.rotation * 90);
reg.getWidth() * req.animScale * Draw.scl,
reg.getHeight() * req.animScale * Draw.scl,
!rotate ? 0 : req.rotation * 90);
if(req.hasConfig){
drawRequestConfig(req, list);
@@ -766,75 +286,32 @@ public class Block extends BlockStorage{
Draw.color();
}
/** @return a custom minimap color for this tile, or 0 to use default colors. */
public int minimapColor(Tile tile){
return 0;
}
public void drawRequestConfigTop(BuildRequest req, Eachable<BuildRequest> list){
}
@Override
public void createIcons(MultiPacker packer){
super.createIcons(packer);
/** Called when arbitrary configuration is applied to a tile. */
public void configured(Tilec tile, @Nullable Playerc player, @Nullable Object value){
//null is of type Void.class; anonymous classes use their superclass.
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
packer.add(PageType.editor, name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)));
if(!synthetic()){
PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full));
mapColor.set(image.getPixel(image.width/2, image.height/2));
if(configurations.containsKey(type)){
configurations.get(type).get(tile, value);
}
}
getGeneratedIcons();
/** Configure when a null value is passed.*/
public void configClear(Cons<Tilec> cons){
configurations.put(void.class, (tile, value) -> cons.get((Tilec)tile));
}
Pixmap last = null;
/** Listen for a config by class type. */
public <T> void config(Class<T> type, Cons2<Tile, T> config){
configurations.put(type, config);
}
if(outlineIcon){
final int radius = 4;
PixmapRegion region = Core.atlas.getPixmap(getGeneratedIcons()[getGeneratedIcons().length-1]);
Pixmap out = new Pixmap(region.width, region.height);
Color color = new Color();
for(int x = 0; x < region.width; x++){
for(int y = 0; y < region.height; y++){
region.getPixel(x, y, color);
out.draw(x, y, color);
if(color.a < 1f){
boolean found = false;
outer:
for(int rx = -radius; rx <= radius; rx++){
for(int ry = -radius; ry <= radius; ry++){
if(Structs.inBounds(rx + x, ry + y, region.width, region.height) && Mathf.dst2(rx, ry) <= radius*radius && color.set(region.getPixel(rx + x, ry + y)).a > 0.01f){
found = true;
break outer;
}
}
}
if(found){
out.draw(x, y, outlineColor);
}
}
}
}
last = out;
packer.add(PageType.main, name, out);
}
if(generatedIcons.length > 1){
Pixmap base = Core.atlas.getPixmap(generatedIcons[0]).crop();
for(int i = 1; i < generatedIcons.length; i++){
if(i == generatedIcons.length - 1 && last != null){
base.drawPixmap(last);
}else{
base.draw(Core.atlas.getPixmap(generatedIcons[i]));
}
}
packer.add(PageType.main, "block-" + name + "-full", base);
generatedIcons = null;
Arrays.fill(cicons, null);
}
public boolean isAccessible(){
return (hasItems && itemCapacity > 0);
}
/** Never use outside of the editor! */
@@ -911,14 +388,16 @@ public class Block extends BlockStorage{
return (Floor)this;
}
@Override
public boolean isHidden(){
return !buildVisibility.visible();
public boolean isAir(){
return id == 0;
}
@Override
public boolean alwaysUnlocked(){
return alwaysUnlocked;
public boolean isBuildable(){
return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly;
}
public boolean isStatic(){
return cacheLayer == CacheLayer.walls;
}
protected void requirements(Category cat, ItemStack[] stacks, boolean unlocked){
@@ -939,8 +418,157 @@ public class Block extends BlockStorage{
Arrays.sort(requirements, Structs.comparingInt(i -> i.item.id));
}
public interface ConfigHandler<T>{
void configured(Tile tile, T value);
@Override
public void displayInfo(Table table){
ContentDisplay.displayBlock(table, this);
}
@Override
public ContentType getContentType(){
return ContentType.block;
}
/** Called after all blocks are created. */
@Override
@CallSuper
public void init(){
//initialize default health based on size
if(health == -1){
health = size * size * 40;
}
if(entityType == null){
//assign default value for now
entityType = TileEntity::create;
//attempt to find the first declared class and use it as the entity type
try{
Class<?>[] classes = getClass().getDeclaredClasses();
//first class that is subclass of Tilec
Class<?> type = Structs.find(classes, Tilec.class::isAssignableFrom);
if(type != null){
Constructor<? extends Tilec> cons = (Constructor<? extends Tilec>)type.getConstructor();
entityType = () -> {
try{
return cons.newInstance();
}catch(Exception e){
throw new RuntimeException(e);
}
};
}
}catch(Throwable ignored){
}
}
buildCost = 0f;
for(ItemStack stack : requirements){
buildCost += stack.amount * stack.item.cost;
}
buildCost *= buildCostMultiplier;
if(consumes.has(ConsumeType.power)) hasPower = true;
if(consumes.has(ConsumeType.item)) hasItems = true;
if(consumes.has(ConsumeType.liquid)) hasLiquids = true;
setStats();
setBars();
consumes.init();
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
throw new IllegalArgumentException("Consumer using buffered power: " + name);
}
}
@Override
public void load(){
region = Core.atlas.find(name);
cacheRegions = new TextureRegion[cacheRegionStrings.size];
for(int i = 0; i < cacheRegions.length; i++){
cacheRegions[i] = Core.atlas.find(cacheRegionStrings.get(i));
}
if(cracks == null || (cracks[0][0].getTexture() != null && cracks[0][0].getTexture().isDisposed())){
cracks = new TextureRegion[maxCrackSize][crackRegions];
for(int size = 1; size <= maxCrackSize; size++){
for(int i = 0; i < crackRegions; i++){
cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i);
}
}
}
}
@Override
public boolean isHidden(){
return !buildVisibility.visible();
}
@Override
public boolean alwaysUnlocked(){
return alwaysUnlocked;
}
@Override
public void createIcons(MultiPacker packer){
super.createIcons(packer);
packer.add(PageType.editor, name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)));
if(!synthetic()){
PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full));
mapColor.set(image.getPixel(image.width/2, image.height/2));
}
getGeneratedIcons();
Pixmap last = null;
if(outlineIcon){
final int radius = 4;
PixmapRegion region = Core.atlas.getPixmap(getGeneratedIcons()[getGeneratedIcons().length-1]);
Pixmap out = new Pixmap(region.width, region.height);
Color color = new Color();
for(int x = 0; x < region.width; x++){
for(int y = 0; y < region.height; y++){
region.getPixel(x, y, color);
out.draw(x, y, color);
if(color.a < 1f){
boolean found = false;
outer:
for(int rx = -radius; rx <= radius; rx++){
for(int ry = -radius; ry <= radius; ry++){
if(Structs.inBounds(rx + x, ry + y, region.width, region.height) && Mathf.dst2(rx, ry) <= radius*radius && color.set(region.getPixel(rx + x, ry + y)).a > 0.01f){
found = true;
break outer;
}
}
}
if(found){
out.draw(x, y, outlineColor);
}
}
}
}
last = out;
packer.add(PageType.main, name, out);
}
if(generatedIcons.length > 1){
Pixmap base = Core.atlas.getPixmap(generatedIcons[0]).crop();
for(int i = 1; i < generatedIcons.length; i++){
if(i == generatedIcons.length - 1 && last != null){
base.drawPixmap(last);
}else{
base.draw(Core.atlas.getPixmap(generatedIcons[i]));
}
}
packer.add(PageType.main, "block-" + name + "-full", base);
generatedIcons = null;
Arrays.fill(cicons, null);
}
}
}

View File

@@ -1,280 +0,0 @@
package mindustry.world;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
public abstract class BlockStorage extends UnlockableContent{
public boolean hasItems;
public boolean hasLiquids;
public boolean hasPower;
public boolean outputsLiquid = false;
public boolean consumesPower = true;
public boolean outputsPower = false;
public int itemCapacity = 10;
public float liquidCapacity = 10f;
public float liquidPressure = 1f;
public final BlockStats stats = new BlockStats();
public final BlockBars bars = new BlockBars();
public final Consumers consumes = new Consumers();
public BlockStorage(String name){
super(name);
}
public boolean shouldConsume(Tile tile){
return true;
}
public boolean productionValid(Tile tile){
return true;
}
public float getPowerProduction(Tile tile){
return 0f;
}
/** Returns the amount of items this block can accept. */
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.team() == tile.team())){
return Math.min(getMaximumAccepted(tile, item) - tile.entity.items().get(item), amount);
}else{
return 0;
}
}
public int getMaximumAccepted(Tile tile, Item item){
return itemCapacity;
}
/** Remove a stack from this inventory, and return the amount removed. */
public int removeStack(Tile tile, Item item, int amount){
if(tile.entity == null || tile.entity.items() == null) return 0;
amount = Math.min(amount, tile.entity.items().get(item));
tile.entity.noSleep();
tile.entity.items().remove(item, amount);
return amount;
}
/** Handle a stack input. */
public void handleStack(Item item, int amount, Tile tile, Teamc source){
tile.entity.noSleep();
tile.entity.items().add(item, amount);
}
public boolean outputsItems(){
return hasItems;
}
/** Returns offset for stack placement. */
public void getStackOffset(Item item, Tile tile, Vec2 trns){
}
public void onProximityUpdate(Tile tile){
if(tile.entity != null) tile.entity.noSleep();
}
public void handleItem(Item item, Tile tile, Tile source){
tile.entity.items().add(item, 1);
}
public boolean acceptItem(Item item, Tile tile, Tile source){
return consumes.itemFilters.get(item.id) && tile.entity.items().get(item) < getMaximumAccepted(tile, item);
}
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
return hasLiquids && tile.entity.liquids().get(liquid) + amount < liquidCapacity && consumes.liquidfilters.get(liquid.id);
}
public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){
tile.entity.liquids().add(liquid, amount);
}
public void tryDumpLiquid(Tile tile, Liquid liquid){
Array<Tile> proximity = tile.entity.proximity();
int dump = tile.rotation();
for(int i = 0; i < proximity.size; i++){
incrementDump(tile, proximity.size);
Tile other = proximity.get((i + dump) % proximity.size);
Tile in = Edges.getFacingEdge(tile, other);
other = other.block().getLiquidDestination(other, in, liquid);
if(other != null && other.team() == tile.team() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids() != null){
float ofract = other.entity.liquids().get(liquid) / other.block().liquidCapacity;
float fract = tile.entity.liquids().get(liquid) / liquidCapacity;
if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f, liquid);
}
}
}
public boolean canDumpLiquid(Tile tile, Tile to, Liquid liquid){
return true;
}
public void tryMoveLiquid(Tile tile, Tile tileSource, Tile next, float amount, Liquid liquid){
float flow = Math.min(next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f, amount);
if(next.block().acceptLiquid(next, tileSource, liquid, flow)){
next.block().handleLiquid(next, tileSource, liquid, flow);
tile.entity.liquids().remove(liquid, flow);
}
}
public float tryMoveLiquid(Tile tile, Tile next, boolean leak, Liquid liquid){
return tryMoveLiquid(tile, next, leak ? 1.5f : 100, liquid);
}
public float tryMoveLiquid(Tile tile, Tile next, float leakResistance, Liquid liquid){
if(next == null) return 0;
next = next.link();
next = next.block().getLiquidDestination(next, tile, liquid);
if(next.team() == tile.team() && next.block().hasLiquids && tile.entity.liquids().get(liquid) > 0f){
if(next.block().acceptLiquid(next, tile, liquid, 0f)){
float ofract = next.entity.liquids().get(liquid) / next.block().liquidCapacity;
float fract = tile.entity.liquids().get(liquid) / liquidCapacity * liquidPressure;
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids().get(liquid));
flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f);
if(flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, liquid, flow)){
next.block().handleLiquid(next, tile, liquid, flow);
tile.entity.liquids().remove(liquid, flow);
return flow;
}else if(ofract > 0.1f && fract > 0.1f){
Liquid other = next.entity.liquids().current();
if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){
tile.entity.damage(1 * Time.delta());
next.entity.damage(1 * Time.delta());
if(Mathf.chance(0.1 * Time.delta())){
Fx.fire.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f);
}
}else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){
tile.entity.liquids().remove(liquid, Math.min(tile.entity.liquids().get(liquid), 0.7f * Time.delta()));
if(Mathf.chance(0.2f * Time.delta())){
Fx.steam.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f);
}
}
}
}
}else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){
float leakAmount = tile.entity.liquids().get(liquid) / leakResistance;
Puddles.deposit(next, tile, liquid, leakAmount);
tile.entity.liquids().remove(liquid, leakAmount);
}
return 0;
}
public Tile getLiquidDestination(Tile tile, Tile from, Liquid liquid){
return tile;
}
/**
* Tries to put this item into a nearby container, if there are no available
* containers, it gets added to the block's inventory.
*/
public void offloadNear(Tile tile, Item item){
Array<Tile> proximity = tile.entity.proximity();
int dump = tile.rotation();
for(int i = 0; i < proximity.size; i++){
incrementDump(tile, proximity.size);
Tile other = proximity.get((i + dump) % proximity.size);
Tile in = Edges.getFacingEdge(tile, other);
if(other.team() == tile.team() && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){
other.block().handleItem(item, other, in);
return;
}
}
handleItem(item, tile, tile);
}
/** Try dumping any item near the tile. */
public boolean tryDump(Tile tile){
return tryDump(tile, null);
}
/**
* Try dumping a specific item near the tile.
* @param todump Item to dump. Can be null to dump anything.
*/
public boolean tryDump(Tile tile, Item todump){
Tilec entity = tile.entity;
if(entity == null || !hasItems || tile.entity.items().total() == 0 || (todump != null && !entity.items().has(todump)))
return false;
Array<Tile> proximity = entity.proximity();
int dump = tile.rotation();
if(proximity.size == 0) return false;
for(int i = 0; i < proximity.size; i++){
Tile other = proximity.get((i + dump) % proximity.size);
Tile in = Edges.getFacingEdge(tile, other);
if(todump == null){
for(int ii = 0; ii < Vars.content.items().size; ii++){
Item item = Vars.content.item(ii);
if(other.team() == tile.team() && entity.items().has(item) && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){
other.block().handleItem(item, other, in);
tile.entity.items().remove(item, 1);
incrementDump(tile, proximity.size);
return true;
}
}
}else{
if(other.team() == tile.team() && other.block().acceptItem(todump, other, in) && canDump(tile, other, todump)){
other.block().handleItem(todump, other, in);
tile.entity.items().remove(todump, 1);
incrementDump(tile, proximity.size);
return true;
}
}
incrementDump(tile, proximity.size);
}
return false;
}
protected void incrementDump(Tile tile, int prox){
tile.rotation((byte)((tile.rotation() + 1) % prox));
}
/** Used for dumping items. */
public boolean canDump(Tile tile, Tile to, Item item){
return true;
}
/** Try offloading an item to a nearby container in its facing direction. Returns true if success. */
public boolean offloadDir(Tile tile, Item item){
Tile other = tile.front();
if(other != null && other.team() == tile.team() && other.block().acceptItem(item, other, tile)){
other.block().handleItem(item, other, tile);
return true;
}
return false;
}
}

View File

@@ -15,19 +15,16 @@ import static mindustry.Vars.*;
public class Build{
/** Returns block type that was broken, or null if unsuccesful. */
@Remote(called = Loc.server)
public static void beginBreak(Team team, int x, int y){
if(!validBreak(team, x, y)){
return;
}
Tile tile = world.ltile(x, y);
Tile tile = world.tilec(x, y);
//this should never happen, but it doesn't hurt to check for links
float prevPercent = 1f;
//just in case
if(tile == null) return;
if(tile.entity != null){
prevPercent = tile.entity.healthf();
}
@@ -36,7 +33,7 @@ public class Build{
Block previous = tile.block();
Block sub = BuildBlock.get(previous.size);
tile.set(sub, team, rotation);
tile.setBlock(sub, team, rotation);
tile.<BuildEntity>ent().setDeconstruct(previous);
tile.entity.health(tile.entity.maxHealth() * prevPercent);
@@ -58,7 +55,7 @@ public class Build{
Block previous = tile.block();
Block sub = BuildBlock.get(result.size);
tile.set(sub, team, rotation);
tile.setBlock(sub, team, rotation);
tile.<BuildEntity>ent().setConstruct(previous, result);
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false)));
@@ -152,7 +149,7 @@ public class Build{
/** Returns whether the tile at this position is breakable by this team */
public static boolean validBreak(Team team, int x, int y){
Tile tile = world.ltile(x, y);
Tile tile = world.tile(x, y);
return tile != null && tile.block().canBreak(tile) && tile.breakable() && tile.interactable(team);
}
}

View File

@@ -19,15 +19,13 @@ public class Tile implements Position{
/** Tile traversal cost. */
public byte cost = 1;
/** Tile entity, usually null. */
public Tilec entity;
public @Nullable Tilec entity;
public short x, y;
protected @NonNull Block block;
protected @NonNull Floor floor;
protected @NonNull Floor overlay;
/** Rotation, 0-3. Also used to store offload location, in which case it can be any number.*/
protected byte rotation;
/** Team ordinal. */
protected byte team;
public Tile(int x, int y){
this.x = (short)x;
@@ -144,23 +142,63 @@ public class Tile implements Position{
}
public Team team(){
return Team.get(link().team);
return entity == null ? Team.derelict : entity.team();
}
public void setTeam(Team team){
this.team = (byte) team.id;
if(entity != null){
entity.team(team);
}
}
public boolean isCenter(){
return entity == null || entity.tile() == this;
}
public byte getTeamID(){
return team;
return team().id;
}
public void setBlock(@NonNull Block type, Team team, int rotation){
preChanged();
this.block = type;
this.team = (byte) team.id;
this.rotation = (byte)Mathf.mod(rotation, 4);
this.rotation = rotation == 0 ? 0 : (byte)Mathf.mod(rotation, 4);
changed();
if(entity != null){
entity.team(team);
}
//set up multiblock
if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
//two passes: first one clears, second one sets
for(int pass = 0; pass < 2; pass++){
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!(worldx == x && worldy == y)){
Tile other = world.tile(worldx, worldy);
if(other != null){
if(pass == 0){
//first pass: delete existing blocks - this should automatically trigger removal if overlap exists
other.setBlock(Blocks.air);
}else{
//second pass: assign changed data
//assign entity and type to blocks, so they act as proxies for this one
other.entity = entity;
other.block = block;
}
}
}
}
}
}
}
}
public void setBlock(@NonNull Block type, Team team){
@@ -168,11 +206,7 @@ public class Tile implements Position{
}
public void setBlock(@NonNull Block type){
if(type == null) throw new IllegalArgumentException("Block cannot be null.");
preChanged();
this.block = type;
this.rotation = 0;
changed();
setBlock(type, Team.derelict, 0);
}
/** This resets the overlay! */
@@ -181,7 +215,9 @@ public class Tile implements Position{
this.overlay = (Floor)Blocks.air;
recache();
block.onProximityUpdate(this);
if(entity != null){
block.onProximityUpdate(entity);
}
}
/** Sets the floor, preserving overlay.*/
@@ -205,32 +241,8 @@ public class Tile implements Position{
}
public void remove(){
link().getLinkedTiles(other -> other.setBlock(Blocks.air));
}
public void set(Block block, Team team){
set(block, team, 0);
}
public void set(Block block, Team team, int rotation){
setBlock(block, team, rotation);
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++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(!(worldx == x && worldy == y)){
Tile toplace = world.tile(worldx, worldy);
if(toplace != null){
toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team);
}
}
}
}
}
//this automatically removes multiblock references to this block
setBlock(Blocks.air);
}
/** remove()-s this tile, except it's synced across the network */
@@ -274,11 +286,13 @@ public class Tile implements Position{
}
public void setOverlayID(short ore){
this.overlay = (Floor)content.block(ore);
setOverlay(content.block(ore));
}
public void setOverlay(Block block){
this.overlay = (Floor)block;
recache();
}
public void clearOverlay(){
@@ -286,7 +300,7 @@ public class Tile implements Position{
}
public boolean passable(){
return isLinked() || !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update)));
return !((floor.solid && (block == Blocks.air || block.solidifes)) || (block.solid && (!block.destructible && !block.update)));
}
/** Whether this block was placed by a player/unit. */
@@ -295,27 +309,19 @@ public class Tile implements Position{
}
public boolean solid(){
return block.solid || block.isSolidFor(this) || (isLinked() && link() != this && link().solid());
return block.solid || (entity != null && block.isSolidFor(entity));
}
public boolean breakable(){
return !isLinked() ? (block.destructible || block.breakable || block.update) : link().breakable();
}
public Tile link(){
return block.linked(this);
return block.destructible || block.breakable || block.update;
}
public boolean isEnemyCheat(){
return team() == state.rules.waveTeam && state.rules.enemyCheat;
}
public boolean isLinked(){
return block instanceof BlockPart;
}
/**
* Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock.
* Returns the list of all tiles linked to this multiblock, or just itself if it's not a multiblock.
* This array contains all linked tiles, including this tile itself.
*/
public void getLinkedTiles(Cons<Tile> cons){
@@ -385,29 +391,29 @@ public class Tile implements Position{
return null;
}
public Tile getNearbyLink(int rotation){
if(rotation == 0) return world.ltile(x + 1, y);
if(rotation == 1) return world.ltile(x, y + 1);
if(rotation == 2) return world.ltile(x - 1, y);
if(rotation == 3) return world.ltile(x, y - 1);
public Tilec getNearbyEntity(int rotation){
if(rotation == 0) return world.ent(x + 1, y);
if(rotation == 1) return world.ent(x, y + 1);
if(rotation == 2) return world.ent(x - 1, y);
if(rotation == 3) return world.ent(x, y - 1);
return null;
}
// ▲ ▲ ▼ ▼ ◀ ▶ ◀ ▶ B A
public @Nullable Tile front(){
return getNearbyLink((rotation + 4) % 4);
public @Nullable Tilec front(){
return getNearbyEntity((rotation + 4) % 4);
}
public @Nullable Tile right(){
return getNearbyLink((rotation + 3) % 4);
public @Nullable Tilec right(){
return getNearbyEntity((rotation + 3) % 4);
}
public @Nullable Tile back(){
return getNearbyLink((rotation + 2) % 4);
public @Nullable Tilec back(){
return getNearbyEntity((rotation + 2) % 4);
}
public @Nullable Tile left(){
return getNearbyLink((rotation + 1) % 4);
public @Nullable Tilec left(){
return getNearbyEntity((rotation + 1) % 4);
}
public boolean interactable(Team team){
@@ -443,8 +449,8 @@ public class Tile implements Position{
//+26
if(link().synthetic() && link().solid()){
cost += Mathf.clamp(link().block.health / 10f, 0, 20);
if(block.synthetic() && solid()){
cost += Mathf.clamp(block.health / 10f, 0, 20);
}
//+46
@@ -467,15 +473,34 @@ public class Tile implements Position{
}
protected void preChanged(){
block.removed(this);
if(entity != null){
//only call removed() for the center block - this only gets called once.
block.removed(entity);
entity.removeFromProximity();
//remove this tile's dangling entities
if(entity.block().isMultiblock()){
int size = entity.block().size;
int offsetx = -(size - 1) / 2;
int offsety = -(size - 1) / 2;
for(int dx = 0; dx < size; dx++){
for(int dy = 0; dy < size; dy++){
Tile other = world.tile(entity.tileX() + dx + offsetx, entity.tileY() + dy + offsety);
if(other != null){
//reset entity and block *manually* - thus, preChanged() will not be called anywhere else, for multiblocks
other.entity = null;
other.block = Blocks.air;
}
}
}
}
}
//recache when static blocks get changed
if(block.isStatic()){
recache();
}
team = 0;
}
protected void changed(){
@@ -493,18 +518,18 @@ public class Tile implements Position{
if(block.hasLiquids) entity.liquids(new LiquidModule());
if(block.hasPower){
entity.power(new PowerModule());
entity.power().graph.add(this);
entity.power().graph.add(entity);
}
if(!world.isGenerating()){
entity.updateProximity();
}
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
}else if(!world.isGenerating()){
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
for(Point2 p : Geometry.d4){
Tile tile = world.ltile(x + p.x, y + p.y);
Tile tile = world.tile(x + p.x, y + p.y);
if(tile != null){
tile.block().onProximityUpdate(tile);
tile.block().onProximityUpdate(entity);
}
}
}
@@ -549,7 +574,7 @@ public class Tile implements Position{
@Remote(called = Loc.server)
public static void setTile(Tile tile, Block block, Team team, int rotation){
tile.set(block, team, rotation);
tile.setBlock(block, team, rotation);
}
@Remote(called = Loc.server, unreliable = true)

View File

@@ -1,83 +0,0 @@
package mindustry.world.blocks;
import mindustry.type.Item;
import mindustry.type.Liquid;
import mindustry.world.Block;
import mindustry.world.Tile;
/**
* Used for multiblocks. Each block that is not the center of the multiblock is a part.
* Think of these as delegates to the actual block; all events are passed to the target block.
* They are made to share all properties from the linked tile/block.
*/
public class BlockPart extends Block{
public final static int maxSize = 9;
private final static BlockPart[][] parts = new BlockPart[maxSize][maxSize];
private final int dx, dy;
public BlockPart(int dx, int dy){
super("part_" + dx + "_" + dy);
this.dx = dx;
this.dy = dy;
solid = false;
hasPower = hasItems = hasLiquids = true;
parts[dx + maxSize/2][dy + maxSize/2] = this;
}
public static BlockPart get(int dx, int dy){
if(dx == -maxSize/2 && dy == -maxSize/2) throw new IllegalArgumentException("Why are you getting a [0,0] blockpart? Stop it.");
return parts[dx + maxSize/2][dy + maxSize/2];
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
return tile.link().block().acceptItem(item, tile.link(), source);
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
tile.link().block().handleItem(item, tile.link(), source);
}
@Override
public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){
Block block = tile.link().block();
block.handleLiquid(tile.link(), source, liquid, amount);
}
@Override
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
Block block = tile.link().block();
return block.hasLiquids && block.acceptLiquid(tile.link(), source, liquid, amount);
}
@Override
public Tile linked(Tile tile){
Tile out = tile.getNearby(-dx, -dy);
return out == null ? tile : out;
}
@Override
public void drawTeam(Tile tile){}
@Override
public void draw(Tile tile){}
@Override
public boolean synthetic(){
return true;
}
@Override
public boolean isHidden(){
return true;
}
@Override
public String toString(){
return "BlockPart[" + dx + ", " + dy + "]";
}
}

View File

@@ -63,7 +63,7 @@ public class BuildBlock extends Block{
public static void onConstructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
if(tile == null) return;
float healthf = tile.entity == null ? 1f : tile.entity.healthf();
tile.set(block, team, rotation);
tile.setBlock(block, team, (int)rotation);
if(tile.entity != null){
tile.entity.health(block.health * healthf);
}
@@ -265,8 +265,8 @@ public class BuildBlock extends Block{
if(clampedAmount > 0 && accumulated > 0){ //if it's positive, add it to the core
if(core != null){
int accepting = core.tile().block().acceptStack(requirements[i].item, accumulated, core.tile(), builder);
core.tile().block().handleStack(requirements[i].item, accepting, core.tile(), builder);
int accepting = core.tile().block().acceptStack(core.tile(), requirements[i].item, accumulated, builder);
core.tile().block().handleStack(core.tile(), requirements[i].item, accepting, builder);
accumulator[i] -= accepting;
}else{
accumulator[i] -= accumulated;

View File

@@ -10,6 +10,7 @@ import mindustry.world.*;
import static mindustry.Vars.net;
//TODO remove ?
public class RespawnBlock{
public static void drawRespawn(Tile tile, float heat, float progress, float time, Playerc player, UnitType to){

View File

@@ -18,8 +18,6 @@ import mindustry.world.consumers.*;
import mindustry.world.meta.*;
import mindustry.world.meta.values.*;
import java.io.*;
import static mindustry.Vars.*;
public class ItemTurret extends CooledTurret{
@@ -45,7 +43,7 @@ public class ItemTurret extends CooledTurret{
stats.add(BlockStat.ammo, new AmmoListValue<>(ammo));
consumes.add(new ConsumeItemFilter(i -> ammo.containsKey(i)){
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
MultiReqImage image = new MultiReqImage();
content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)),
() -> tile.entity != null && !((ItemTurretEntity)tile.entity).ammo.isEmpty() && ((ItemEntry)tile.<ItemTurretEntity>ent().ammo.peek()).item == item)));
@@ -72,7 +70,7 @@ public class ItemTurret extends CooledTurret{
//add first ammo item to cheaty blocks so they can shoot properly
if(tile.isEnemyCheat() && ammo.size > 0){
handleItem(ammo.entries().next().key, tile, tile);
handleItem(tile, tile, ammo.entries().next().key);
}
}
@@ -87,7 +85,7 @@ public class ItemTurret extends CooledTurret{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
public int acceptStack(Tile tile, Item item, int amount, Teamc source){
TurretEntity entity = tile.ent();
BulletType type = ammo.get(item);
@@ -98,9 +96,9 @@ public class ItemTurret extends CooledTurret{
}
@Override
public void handleStack(Item item, int amount, Tile tile, Teamc source){
public void handleStack(Tile tile, Item item, int amount, Teamc source){
for(int i = 0; i < amount; i++){
handleItem(item, tile, null);
handleItem(tile, null, item);
}
}
@@ -111,7 +109,7 @@ public class ItemTurret extends CooledTurret{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
TurretEntity entity = tile.ent();
if(entity == null) return;
@@ -144,7 +142,7 @@ public class ItemTurret extends CooledTurret{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
TurretEntity entity = tile.ent();
return ammo != null && ammo.get(item) != null && entity.totalAmmo + ammo.get(item).ammoMultiplier <= maxAmmo;

View File

@@ -123,7 +123,7 @@ public class LiquidTurret extends Turret{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return false;
}

View File

@@ -10,8 +10,8 @@ public class ArmoredConveyor extends Conveyor{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
return super.acceptItem(item, tile, source) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation());
public boolean acceptItem(Tile tile, Tile source, Item item){
return super.acceptItem(tile, source, item) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation());
}
@Override

View File

@@ -5,8 +5,6 @@ import arc.util.io.*;
import mindustry.type.*;
import mindustry.world.*;
import java.io.*;
public class BufferedItemBridge extends ExtendingItemBridge{
public final int timerAccept = timers++;
@@ -29,9 +27,9 @@ public class BufferedItemBridge extends ExtendingItemBridge{
}
Item item = entity.buffer.poll();
if(entity.timer(timerAccept, 4) && item != null && other.block().acceptItem(item, other, tile)){
if(entity.timer(timerAccept, 4) && item != null && other.block().acceptItem(other, tile, item)){
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f);
other.block().handleItem(item, other, tile);
other.block().handleItem(other, tile, item);
entity.buffer.remove();
}else{
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 0f, 0.008f);

View File

@@ -19,8 +19,6 @@ import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.meta.*;
import java.io.*;
import static mindustry.Vars.*;
public class Conveyor extends Block implements Autotiler{
@@ -251,18 +249,18 @@ public class Conveyor extends Block implements Autotiler{
}
@Override
public void getStackOffset(Item item, Tile tile, Vec2 trns){
public void getStackOffset(Tile tile, Item item, Vec2 trns){
trns.trns(tile.rotation() * 90 + 180f, tilesize / 2f);
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
public int acceptStack(Tile tile, Item item, int amount, Teamc source){
ConveyorEntity entity = tile.ent();
return Math.min((int)(entity.minitem / itemSpace), amount);
}
@Override
public void handleStack(Item item, int amount, Tile tile, Teamc source){
public void handleStack(Tile tile, Item item, int amount, Teamc source){
ConveyorEntity e = tile.ent();
amount = Math.min(amount, itemCapacity - e.len);
@@ -278,7 +276,7 @@ public class Conveyor extends Block implements Autotiler{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
ConveyorEntity e = tile.ent();
if(e.len >= capacity) return false;
int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation());
@@ -286,7 +284,7 @@ public class Conveyor extends Block implements Autotiler{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
ConveyorEntity e = tile.ent();
if(e.len >= capacity) return;

View File

@@ -200,8 +200,8 @@ public class ItemBridge extends Block{
if(entity.uptime >= 0.5f && entity.timer(timerTransport, transportTime)){
Item item = entity.items().take();
if(item != null && other.block().acceptItem(item, other, tile)){
other.block().handleItem(item, other, tile);
if(item != null && other.block().acceptItem(other, tile, item)){
other.block().handleItem(other, tile, item);
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f);
}else{
entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f);
@@ -252,7 +252,7 @@ public class ItemBridge extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
if(tile.team() != source.team()) return false;
ItemBridgeEntity entity = tile.ent();

View File

@@ -10,8 +10,6 @@ import mindustry.world.DirectionalItemBuffer;
import mindustry.world.Tile;
import mindustry.world.meta.BlockGroup;
import java.io.IOException;
import static mindustry.Vars.content;
public class Junction extends Block{
@@ -28,7 +26,7 @@ public class Junction extends Block{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
public int acceptStack(Tile tile, Item item, int amount, Teamc source){
return 0;
}
@@ -55,11 +53,11 @@ public class Junction extends Block{
if(dest != null) dest = dest.link();
//skip blocks that don't want the item, keep waiting until they do
if(dest == null || !dest.block().acceptItem(item, dest, tile) || dest.team() != tile.team()){
if(dest == null || !dest.block().acceptItem(dest, tile, item) || dest.team() != tile.team()){
continue;
}
dest.block().handleItem(item, dest, tile);
dest.block().handleItem(dest, tile, item);
System.arraycopy(buffer.buffers[i], 1, buffer.buffers[i], 0, buffer.indexes[i] - 1);
buffer.indexes[i] --;
}
@@ -68,14 +66,14 @@ public class Junction extends Block{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
JunctionEntity entity = tile.ent();
int relative = source.relativeTo(tile.x, tile.y);
entity.buffer.accept(relative, item);
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
JunctionEntity entity = tile.ent();
int relative = source.relativeTo(tile.x, tile.y);

View File

@@ -221,7 +221,7 @@ public class MassDriver extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
//mass drivers that ouput only cannot accept items
return tile.entity.items().total() < itemCapacity && linkValid(tile);
}

View File

@@ -30,7 +30,7 @@ public class OverflowGate extends Block{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
public int acceptStack(Tile tile, Item item, int amount, Teamc source){
return 0;
}
@@ -63,7 +63,7 @@ public class OverflowGate extends Block{
if(target != null && (entity.time >= 1f)){
getTileTarget(tile, entity.lastItem, entity.lastInput, true);
target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target));
target.block().handleItem(target, Edges.getFacingEdge(tile, target), entity.lastItem);
entity.items().remove(entity.lastItem, 1);
entity.lastItem = null;
}
@@ -71,14 +71,14 @@ public class OverflowGate extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
OverflowGateEntity entity = tile.ent();
return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0;
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
OverflowGateEntity entity = tile.ent();
entity.items().add(item, 1);
entity.lastItem = item;
@@ -94,13 +94,13 @@ public class OverflowGate extends Block{
Tile to = tile.getNearby((from + 2) % 4);
if(to == null) return null;
Tile edge = Edges.getFacingEdge(tile, to);
boolean canForward = to.block().acceptItem(item, to, edge) && to.team() == tile.team() && !(to.block() instanceof OverflowGate);
boolean canForward = to.block().acceptItem(to, edge, item) && to.team() == tile.team() && !(to.block() instanceof OverflowGate);
if(!canForward || invert){
Tile a = tile.getNearby(Mathf.mod(from - 1, 4));
Tile b = tile.getNearby(Mathf.mod(from + 1, 4));
boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate) && a.team() == tile.team();
boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate) && b.team() == tile.team();
boolean ac = a != null && a.block().acceptItem(a, edge, item) && !(a.block() instanceof OverflowGate) && a.team() == tile.team();
boolean bc = b != null && b.block().acceptItem(b, edge, item) && !(b.block() instanceof OverflowGate) && b.team() == tile.team();
if(!ac && !bc){
return invert && canForward ? to : null;

View File

@@ -36,7 +36,7 @@ public class Router extends Block{
if(target != null && (entity.time >= 1f || !(target.block() instanceof Router))){
getTileTarget(tile, entity.lastItem, entity.lastInput, true);
target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target));
target.block().handleItem(target, Edges.getFacingEdge(tile, target), entity.lastItem);
entity.items().remove(entity.lastItem, 1);
entity.lastItem = null;
}
@@ -44,14 +44,14 @@ public class Router extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
RouterEntity entity = tile.ent();
return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0;
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
RouterEntity entity = tile.ent();
entity.items().add(item, 1);
entity.lastItem = item;
@@ -66,7 +66,7 @@ public class Router extends Block{
Tile other = proximity.get((i + counter) % proximity.size);
if(set) tile.rotation((byte)((tile.rotation() + 1) % proximity.size));
if(other == from && from.block() == Blocks.overflowGate) continue;
if(other.block().acceptItem(item, other, Edges.getFacingEdge(tile, other))){
if(other.block().acceptItem(other, Edges.getFacingEdge(tile, other), item)){
return other;
}
}

View File

@@ -77,17 +77,17 @@ public class Sorter extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
Tile to = getTileTarget(item, tile, source, false);
return to != null && to.block().acceptItem(item, to, tile) && to.team() == tile.team();
return to != null && to.block().acceptItem(to, tile, item) && to.team() == tile.team();
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
Tile to = getTileTarget(item, tile, source, true);
to.block().handleItem(item, to, tile);
to.block().handleItem(to, tile, item);
}
boolean isSame(Tile tile, Tile other){
@@ -112,9 +112,9 @@ public class Sorter extends Block{
Tile a = dest.getNearby(Mathf.mod(dir - 1, 4));
Tile b = dest.getNearby(Mathf.mod(dir + 1, 4));
boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) &&
a.block().acceptItem(item, a, dest);
a.block().acceptItem(a, dest, item);
boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) &&
b.block().acceptItem(item, b, dest);
b.block().acceptItem(b, dest, item);
if(ac && !bc){
to = a;

View File

@@ -54,7 +54,7 @@ public class LiquidBridge extends ItemBridge{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return false;
}
}

View File

@@ -49,7 +49,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return false;
}
}

View File

@@ -1,22 +1,22 @@
package mindustry.world.blocks.power;
import arc.*;
import arc.struct.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.world.*;
import mindustry.gen.*;
import mindustry.world.consumers.*;
public class PowerGraph{
private final static Queue<Tile> queue = new Queue<>();
private final static Array<Tile> outArray1 = new Array<>();
private final static Array<Tile> outArray2 = new Array<>();
private final static Queue<Tilec> queue = new Queue<>();
private final static Array<Tilec> outArray1 = new Array<>();
private final static Array<Tilec> outArray2 = new Array<>();
private final static IntSet closedSet = new IntSet();
private final ObjectSet<Tile> producers = new ObjectSet<>();
private final ObjectSet<Tile> consumers = new ObjectSet<>();
private final ObjectSet<Tile> batteries = new ObjectSet<>();
private final ObjectSet<Tile> all = new ObjectSet<>();
private final ObjectSet<Tilec> producers = new ObjectSet<>();
private final ObjectSet<Tilec> consumers = new ObjectSet<>();
private final ObjectSet<Tilec> batteries = new ObjectSet<>();
private final ObjectSet<Tilec> all = new ObjectSet<>();
private final WindowedMean powerBalance = new WindowedMean(60);
private float lastPowerProduced, lastPowerNeeded, lastUsageFraction;
@@ -62,21 +62,21 @@ public class PowerGraph{
public float getPowerProduced(){
float powerProduced = 0f;
for(Tile producer : producers){
for(Tilec producer : producers){
if(producer.entity == null) continue;
powerProduced += producer.block().getPowerProduction(producer) * producer.entity.delta();
powerProduced += producer.block().getPowerProduction(producer) * producer.delta();
}
return powerProduced;
}
public float getPowerNeeded(){
float powerNeeded = 0f;
for(Tile consumer : consumers){
for(Tilec consumer : consumers){
Consumers consumes = consumer.block().consumes;
if(consumes.hasPower()){
ConsumePower consumePower = consumes.getPower();
if(otherConsumersAreValid(consumer, consumePower)){
powerNeeded += consumePower.requestedPower(consumer.entity) * consumer.entity.delta();
powerNeeded += consumePower.requestedPower(consumer) * consumer.delta();
}
}
}
@@ -85,10 +85,10 @@ public class PowerGraph{
public float getBatteryStored(){
float totalAccumulator = 0f;
for(Tile battery : batteries){
for(Tilec battery : batteries){
Consumers consumes = battery.block().consumes;
if(consumes.hasPower()){
totalAccumulator += battery.entity.power().status * consumes.getPower().capacity;
totalAccumulator += battery.power().status * consumes.getPower().capacity;
}
}
return totalAccumulator;
@@ -96,10 +96,10 @@ public class PowerGraph{
public float getBatteryCapacity(){
float totalCapacity = 0f;
for(Tile battery : batteries){
for(Tilec battery : batteries){
if(battery.block().consumes.hasPower()){
ConsumePower power = battery.block().consumes.getPower();
totalCapacity += (1f - battery.entity.power().status) * power.capacity;
totalCapacity += (1f - battery.power().status) * power.capacity;
}
}
return totalCapacity;
@@ -107,7 +107,7 @@ public class PowerGraph{
public float getTotalBatteryCapacity(){
float totalCapacity = 0f;
for(Tile battery : batteries){
for(Tilec battery : batteries){
if(battery.block().consumes.hasPower()){
totalCapacity += battery.block().consumes.getPower().capacity;
}
@@ -121,10 +121,10 @@ public class PowerGraph{
float used = Math.min(stored, needed);
float consumedPowerPercentage = Math.min(1.0f, needed / stored);
for(Tile battery : batteries){
for(Tilec battery : batteries){
Consumers consumes = battery.block().consumes;
if(consumes.hasPower()){
battery.entity.power().status *= (1f-consumedPowerPercentage);
battery.power().status *= (1f-consumedPowerPercentage);
}
}
return used;
@@ -136,12 +136,12 @@ public class PowerGraph{
float chargedPercent = Math.min(excess/capacity, 1f);
if(Mathf.equal(capacity, 0f)) return 0f;
for(Tile battery : batteries){
for(Tilec battery : batteries){
Consumers consumes = battery.block().consumes;
if(consumes.hasPower()){
ConsumePower consumePower = consumes.getPower();
if(consumePower.capacity > 0f){
battery.entity.power().status += (1f-battery.entity.power().status) * chargedPercent;
battery.power().status += (1f-battery.power().status) * chargedPercent;
}
}
}
@@ -151,25 +151,25 @@ public class PowerGraph{
public void distributePower(float needed, float produced){
//distribute even if not needed. this is because some might be requiring power but not using it; it updates consumers
float coverage = Mathf.zero(needed) && Mathf.zero(produced) ? 0f : Mathf.zero(needed) ? 1f : Math.min(1, produced / needed);
for(Tile consumer : consumers){
for(Tilec consumer : consumers){
Consumers consumes = consumer.block().consumes;
if(consumes.hasPower()){
ConsumePower consumePower = consumes.getPower();
if(consumePower.buffered){
if(!Mathf.zero(consumePower.capacity)){
// Add an equal percentage of power to all buffers, based on the global power coverage in this graph
float maximumRate = consumePower.requestedPower(consumer.entity) * coverage * consumer.entity.delta();
consumer.entity.power().status = Mathf.clamp(consumer.entity.power().status + maximumRate / consumePower.capacity);
float maximumRate = consumePower.requestedPower(consumer) * coverage * consumer.delta();
consumer.power().status = Mathf.clamp(consumer.power().status + maximumRate / consumePower.capacity);
}
}else{
//valid consumers get power as usual
if(otherConsumersAreValid(consumer, consumePower)){
consumer.entity.power().status = coverage;
consumer.power().status = coverage;
}else{ //invalid consumers get an estimate, if they were to activate
consumer.entity.power().status = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta()));
consumer.power().status = Math.min(1, produced / (needed + consumePower.usage * consumer.delta()));
//just in case
if(Float.isNaN(consumer.entity.power().status)){
consumer.entity.power().status = 0f;
if(Float.isNaN(consumer.power().status)){
consumer.power().status = 0f;
}
}
}
@@ -180,10 +180,10 @@ public class PowerGraph{
public void update(){
if(Core.graphics.getFrameId() == lastFrameUpdated){
return;
}else if(!consumers.isEmpty() && consumers.first().isEnemyCheat()){
}else if(!consumers.isEmpty() && consumers.first().tile().isEnemyCheat()){
//when cheating, just set status to 1
for(Tile tile : consumers){
tile.entity.power().status = 1f;
for(Tilec tile : consumers){
tile.power().status = 1f;
}
lastPowerNeeded = lastPowerProduced = lastUsageFraction = 1f;
@@ -224,14 +224,14 @@ public class PowerGraph{
}
public void add(PowerGraph graph){
for(Tile tile : graph.all){
for(Tilec tile : graph.all){
add(tile);
}
}
public void add(Tile tile){
if(tile.entity == null || tile.entity.power() == null) return;
tile.entity.power().graph = this;
public void add(Tilec tile){
if(tile.entity == null || tile.power() == null) return;
tile.power().graph = this;
all.add(tile);
if(tile.block().outputsPower && tile.block().consumesPower && !tile.block().consumes.getPower().buffered){
@@ -246,14 +246,14 @@ public class PowerGraph{
}
}
public void reflow(Tile tile){
public void reflow(Tilec tile){
queue.clear();
queue.addLast(tile);
closedSet.clear();
while(queue.size > 0){
Tile child = queue.removeFirst();
Tilec child = queue.removeFirst();
add(child);
for(Tile next : child.block().getPowerConnections(child, outArray2)){
for(Tilec next : child.block().getPowerConnections(child, outArray2)){
if(!closedSet.contains(next.pos())){
queue.addLast(next);
closedSet.add(next.pos());
@@ -262,22 +262,22 @@ public class PowerGraph{
}
}
private void removeSingle(Tile tile){
private void removeSingle(Tilec tile){
all.remove(tile);
producers.remove(tile);
consumers.remove(tile);
batteries.remove(tile);
}
public void remove(Tile tile){
public void remove(Tilec tile){
removeSingle(tile);
//begin by clearing the closed set
closedSet.clear();
//go through all the connections of this tile
for(Tile other : tile.block().getPowerConnections(tile, outArray1)){
for(Tilec other : tile.block().getPowerConnections(tile, outArray1)){
//a graph has already been assigned to this tile from a previous call, skip it
if(other.entity.power().graph != this) continue;
if(other.power().graph != this) continue;
//create graph for this branch
PowerGraph graph = new PowerGraph();
@@ -287,16 +287,16 @@ public class PowerGraph{
queue.addLast(other);
while(queue.size > 0){
//get child from queue
Tile child = queue.removeFirst();
Tilec child = queue.removeFirst();
//remove it from this graph
removeSingle(child);
//add it to the new branch graph
graph.add(child);
//go through connections
for(Tile next : child.block().getPowerConnections(child, outArray2)){
for(Tilec next : child.block().getPowerConnections(child, outArray2)){
//make sure it hasn't looped back, and that the new graph being assigned hasn't already been assigned
//also skip closed tiles
if(next != tile && next.entity.power().graph != graph && !closedSet.contains(next.pos())){
if(next != tile && next.power().graph != graph && !closedSet.contains(next.pos())){
queue.addLast(next);
closedSet.add(next.pos());
}
@@ -307,9 +307,9 @@ public class PowerGraph{
}
}
private boolean otherConsumersAreValid(Tile tile, Consume consumePower){
private boolean otherConsumersAreValid(Tilec tile, Consume consumePower){
for(Consume cons : tile.block().consumes.all()){
if(cons != consumePower && !cons.isOptional() && !cons.valid(tile.ent())){
if(cons != consumePower && !cons.isOptional() && !cons.valid(tile)){
return false;
}
}

View File

@@ -313,12 +313,12 @@ public class PowerNode extends PowerBlock{
return tile.entity.power().links.contains(other.pos());
}
public boolean linkValid(Tile tile, Tile link){
public boolean linkValid(Tilec tile, Tilec link){
return linkValid(tile, link, true);
}
public boolean linkValid(Tile tile, Tile link, boolean checkMaxNodes){
if(tile == link || link == null || link.entity == null || tile.entity == null || !link.block().hasPower || tile.team() != link.team()) return false;
public boolean linkValid(Tilec tile, Tilec link, boolean checkMaxNodes){
if(tile == link || link == null || !link.block().hasPower || tile.team() != link.team()) return false;
if(overlaps(tile, link, laserRange * tilesize) || (link.block() instanceof PowerNode && overlaps(link, tile, link.<PowerNode>cblock().laserRange * tilesize))){
if(checkMaxNodes && link.block() instanceof PowerNode){
@@ -369,8 +369,8 @@ public class PowerNode extends PowerBlock{
Draw.color();
}
public static boolean insulated(Tile tile, Tile other){
return insulated(tile.x, tile.y, other.x, other.y);
public static boolean insulated(Tilec tile, Tilec other){
return insulated(tile.tileX(), tile.tileY(), other.tileX(), other.tileY());
}
public static boolean insulated(int x, int y, int x2, int y2){

View File

@@ -59,8 +59,8 @@ public class GenericCrafter extends Block{
}
@Override
public boolean shouldIdleSound(Tile tile){
return tile.entity.cons().valid();
public boolean shouldIdleSound(Tilec tile){
return tile.cons().valid();
}
@Override

View File

@@ -59,14 +59,14 @@ public class Incinerator extends Block{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
if(Mathf.chance(0.3)){
effect.at(tile.drawx(), tile.drawy());
}
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
IncineratorEntity entity = tile.ent();
return entity.heat > 0.5f;
}

View File

@@ -82,7 +82,7 @@ public class ItemSource extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return false;
}

View File

@@ -12,11 +12,11 @@ public class ItemVoid extends Block{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return true;
}
}

View File

@@ -68,7 +68,7 @@ public class CoreBlock extends StorageBlock{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return tile.entity.items().get(item) < getMaximumAccepted(tile, item);
}
@@ -191,9 +191,9 @@ public class CoreBlock extends StorageBlock{
}
@Override
public void handleItem(Item item, Tile tile, Tile source){
public void handleItem(Tile tile, Tile source, Item item){
if(net.server() || !net.active()){
super.handleItem(item, tile, source);
super.handleItem(tile, source, item);
if(state.rules.tutorial){
Events.fire(new CoreItemDeliverEvent());
}

View File

@@ -38,7 +38,7 @@ public class LaunchPad extends StorageBlock{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
return item.type == ItemType.material && tile.entity.items().total() < itemCapacity;
}

View File

@@ -15,9 +15,9 @@ public abstract class StorageBlock extends Block{
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
public boolean acceptItem(Tile tile, Tile source, Item item){
StorageBlockEntity entity = tile.ent();
return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(item, entity.linkedCore, source) : tile.entity.items().get(item) < getMaximumAccepted(tile, item);
return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(entity.linkedCore, source, item) : tile.entity.items().get(item) < getMaximumAccepted(tile, item);
}
@Override

View File

@@ -3,7 +3,6 @@ package mindustry.world.consumers;
import arc.struct.*;
import arc.scene.ui.layout.Table;
import mindustry.gen.*;
import mindustry.world.Tile;
import mindustry.world.meta.BlockStats;
/** An abstract class that defines a type of resource that a block can consume. */
@@ -59,7 +58,7 @@ public abstract class Consume{
public abstract ConsumeType type();
public abstract void build(Tile tile, Table table);
public abstract void build(Tilec tile, Table table);
/** Called when a consumption is triggered manually. */
public void trigger(Tilec entity){

View File

@@ -8,7 +8,6 @@ import mindustry.gen.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.world.*;
import mindustry.world.meta.*;
import mindustry.world.meta.values.*;
@@ -33,7 +32,7 @@ public class ConsumeItemFilter extends Consume{
}
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
MultiReqImage image = new MultiReqImage();
content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(item))));

View File

@@ -7,7 +7,6 @@ import mindustry.gen.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.world.*;
import mindustry.world.meta.*;
import mindustry.world.meta.values.*;
@@ -36,7 +35,7 @@ public class ConsumeItems extends Consume{
}
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
for(ItemStack stack : items){
table.add(new ReqImage(new ItemImage(stack.item.icon(Cicon.medium), stack.amount), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(stack.item, stack.amount))).size(8 * 4).padRight(5);
}

View File

@@ -7,7 +7,6 @@ import mindustry.gen.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.world.*;
import mindustry.world.meta.*;
public class ConsumeLiquid extends ConsumeLiquidBase{
@@ -28,7 +27,7 @@ public class ConsumeLiquid extends ConsumeLiquidBase{
}
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
table.add(new ReqImage(liquid.icon(Cicon.medium), () -> valid(tile.entity))).size(8 * 4);
}

View File

@@ -8,7 +8,6 @@ import mindustry.type.Liquid;
import mindustry.ui.Cicon;
import mindustry.ui.MultiReqImage;
import mindustry.ui.ReqImage;
import mindustry.world.Tile;
import mindustry.world.meta.BlockStat;
import mindustry.world.meta.BlockStats;
import mindustry.world.meta.values.LiquidFilterValue;
@@ -29,7 +28,7 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{
}
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
Array<Liquid> list = content.liquids().select(l -> !l.isHidden() && filter.get(l));
MultiReqImage image = new MultiReqImage();
list.each(liquid -> image.add(new ReqImage(liquid.icon(Cicon.medium), () -> tile.entity != null && tile.entity.liquids() != null && tile.entity.liquids().get(liquid) >= use(tile.entity))));

View File

@@ -3,7 +3,6 @@ package mindustry.world.consumers;
import arc.math.Mathf;
import arc.scene.ui.layout.Table;
import mindustry.gen.*;
import mindustry.world.Tile;
import mindustry.world.meta.*;
/** Consumer class for blocks which consume power while being connected to a power graph. */
@@ -31,7 +30,7 @@ public class ConsumePower extends Consume{
}
@Override
public void build(Tile tile, Table table){
public void build(Tilec tile, Table table){
//No tooltip for power, for now
}