Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features

 Conflicts:
	core/src/mindustry/content/Planets.java
	tools/src/mindustry/tools/Generators.java
This commit is contained in:
Anuken
2021-10-20 10:45:51 -04:00
78 changed files with 585 additions and 156 deletions

View File

@@ -26,6 +26,7 @@ import mindustry.maps.*;
import mindustry.mod.*;
import mindustry.net.*;
import mindustry.service.*;
import mindustry.world.*;
import java.io.*;
import java.nio.charset.*;
@@ -195,6 +196,8 @@ public class Vars implements Loadable{
public static Fi launchIDFile;
/** empty map, indicates no current map */
public static Map emptyMap;
/** empty tile for payloads */
public static Tile emptyTile;
/** map file extension */
public static final String mapExtension = "msav";
/** save file extension */
@@ -310,6 +313,10 @@ public class Vars implements Loadable{
modDirectory.mkdirs();
Events.on(ContentInitEvent.class, e -> {
emptyTile = new Tile(Short.MAX_VALUE - 20, Short.MAX_VALUE - 20);
});
mods.load();
maps.load();
}

View File

@@ -23,7 +23,7 @@ public class Planets implements ContentList{
@Override
public void load(){
sun = new Planet("sun", null, 4){{
sun = new Planet("sun", null, 4f){{
bloom = true;
accessible = false;
@@ -40,7 +40,7 @@ public class Planets implements ContentList{
);
}};
erekir = new Planet("erekir", sun, 1, 2){{
erekir = new Planet("erekir", sun, 1f, 2){{
generator = new ErekirPlanetGenerator();
meshLoader = () -> new HexMesh(this, 5);
atmosphereColor = Color.valueOf("f07218");
@@ -71,7 +71,7 @@ public class Planets implements ContentList{
gen.max += 2;
});
tantros = new Planet("tantros", sun, 1, 2){{
tantros = new Planet("tantros", sun, 1f, 2){{
generator = new TantrosPlanetGenerator();
meshLoader = () -> new HexMesh(this, 4);
atmosphereColor = Color.valueOf("3db899");
@@ -81,7 +81,7 @@ public class Planets implements ContentList{
alwaysUnlocked = true;
}};
serpulo = new Planet("serpulo", sun, 1, 3){{
serpulo = new Planet("serpulo", sun, 1f, 3){{
generator = new SerpuloPlanetGenerator();
meshLoader = () -> new HexMesh(this, 6);
cloudMeshLoader = () -> new MultiMesh(

View File

@@ -88,7 +88,9 @@ public class TechTree implements ContentList{
node(conduit, () -> {
node(liquidJunction, () -> {
node(liquidRouter, () -> {
node(liquidTank);
node(liquidContainer, () -> {
node(liquidTank);
});
node(bridgeConduit);

View File

@@ -587,6 +587,7 @@ public class UnitTypes implements ContentList{
ammoType = new ItemAmmoType(Items.coal);
weapons.add(new Weapon(){{
shootOnDeath = true;
reload = 24f;
shootCone = 180f;
ejectEffect = Fx.none;
@@ -597,7 +598,7 @@ public class UnitTypes implements ContentList{
hitEffect = Fx.pulverize;
lifetime = 10f;
speed = 1f;
splashDamageRadius = 60f;
splashDamageRadius = 55f;
instantDisappear = true;
splashDamage = 90f;
killShooter = true;

View File

@@ -18,7 +18,7 @@ abstract class BlockUnitComp implements Unitc{
//sets up block stats
maxHealth(tile.block.health);
health(tile.health());
health(tile.health);
hitSize(tile.block.size * tilesize * 0.7f);
set(tile);
}

View File

@@ -291,7 +291,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public byte relativeTo(Building tile){
return relativeTo(tile.tile());
return relativeTo(tile.tile);
}
public byte relativeToEdge(Tile other){
@@ -413,25 +413,28 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public void handleUnitPayload(Unit player, Cons<Payload> grabber){
Fx.spawn.at(player);
public void handleUnitPayload(Unit unit, Cons<Payload> grabber){
Fx.spawn.at(unit);
if(player.isPlayer()){
player.getPlayer().clearUnit();
if(unit.isPlayer()){
unit.getPlayer().clearUnit();
}
player.remove();
grabber.get(new UnitPayload(player));
Fx.unitDrop.at(player);
if(Vars.net.client()){
Vars.netClient.clearRemovedEntity(player.id);
}
unit.remove();
//needs new ID as it is now a payload
unit.id = EntityGroup.nextId();
grabber.get(new UnitPayload(unit));
Fx.unitDrop.at(unit);
}
public boolean canUnload(){
return block.unloadable;
}
public boolean payloadCheck(int conveyorRotation){
return block.rotate && (rotation + 2) % 4 == conveyorRotation;
}
/** Called when an unloader takes an item. */
public void itemTaken(Item item){
@@ -920,6 +923,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
drawTeamTop();
}
public void payloadDraw(){
draw();
}
public void drawTeamTop(){
if(block.teamRegion.found()){
if(block.teamRegions[team.id] == block.teamRegion) Draw.color(team.color);
@@ -971,6 +978,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
}
/** @return whether this building is in a payload */
public boolean isPayload(){
return tile == emptyTile;
}
/**
* 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. */
@@ -1059,7 +1071,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){
Time.run(i / 2f, () -> {
Tile other = world.tile(tileX() + Mathf.range(block.size / 2), tileY() + Mathf.range(block.size / 2));
Tile other = world.tileWorld(x + Mathf.range(block.size * tilesize / 2), y + Mathf.range(block.size * tilesize / 2));
if(other != null){
Puddles.deposit(other, liquid, splash);
}

View File

@@ -36,7 +36,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
@Override
@Replace
public int pathType(){
return type.allowLegStep ? Pathfinder.costGround : Pathfinder.costLegs;
return type.allowLegStep ? Pathfinder.costLegs : Pathfinder.costGround;
}
@Override

View File

@@ -61,6 +61,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
void pickup(Building tile){
tile.pickedUp();
tile.tile.remove();
tile.tile = Vars.emptyTile;
payloads.add(new BuildPayload(tile));
Fx.unitPickup.at(tile);
Events.fire(new PickupEvent(self(), tile));

View File

@@ -155,6 +155,7 @@ public class Saves{
SaveSlot slot = new SaveSlot(getNextSlotFile());
slot.importFile(file);
slot.setName(file.nameWithoutExtension());
saves.add(slot);
slot.meta = SaveIO.getMeta(slot.file);
current = slot;
@@ -330,6 +331,10 @@ public class Saves{
public void importFile(Fi from) throws IOException{
try{
from.copyTo(file);
if(previewFile().exists()){
requestedPreview = false;
previewFile().delete();
}
}catch(Exception e){
throw new IOException(e);
}

View File

@@ -285,7 +285,7 @@ public class Waves{
if(naval){
species = Structs.filter(UnitType[].class, species, v -> v[0].flying || v[0].naval);
}else{
species = Structs.filter(UnitType[].class, species, v -> v[0].flying && !v[0].naval);
species = Structs.filter(UnitType[].class, species, v -> !v[0].naval);
}
UnitType[][] fspec = species;

View File

@@ -335,7 +335,7 @@ public class LExecutor{
/** Checks is a unit is valid for logic AI control, and returns the controller. */
@Nullable
public static LogicAI checkLogicAI(LExecutor exec, Object unitObj){
if(unitObj instanceof Unit unit && exec.obj(varUnit) == unit && unit.team == exec.team && !unit.isPlayer() && !(unit.controller() instanceof FormationAI)){
if(unitObj instanceof Unit unit && unit.isValid() && exec.obj(varUnit) == unit && unit.team == exec.team && !unit.isPlayer() && !(unit.controller() instanceof FormationAI)){
if(unit.controller() instanceof LogicAI la){
la.controller = exec.building(varThis);
return la;
@@ -934,27 +934,31 @@ public class LExecutor{
//this should avoid any garbage allocation
Var v = exec.var(value);
if(v.isobj && value != 0){
String strValue =
v.objval == null ? "null" :
v.objval instanceof String s ? s :
v.objval == Blocks.stoneWall ? "solid" : //special alias
v.objval instanceof MappableContent content ? content.name :
v.objval instanceof Content ? "[content]" :
v.objval instanceof Building build ? build.block.name :
v.objval instanceof Unit unit ? unit.type.name :
v.objval instanceof Enum<?> e ? e.name() :
"[object]";
String strValue = toString(v.objval);
exec.textBuffer.append(strValue);
}else{
//display integer version when possible
if(Math.abs(v.numval - (long)v.numval) < 0.000001){
if(Math.abs(v.numval - (long)v.numval) < 0.00001){
exec.textBuffer.append((long)v.numval);
}else{
exec.textBuffer.append(v.numval);
}
}
}
public static String toString(Object obj){
return
obj == null ? "null" :
obj instanceof String s ? s :
obj == Blocks.stoneWall ? "solid" : //special alias
obj instanceof MappableContent content ? content.name :
obj instanceof Content ? "[content]" :
obj instanceof Building build ? build.block.name :
obj instanceof Unit unit ? unit.type.name :
obj instanceof Enum<?> e ? e.name() :
"[object]";
}
}
public static class PrintFlushI implements LInstruction{

View File

@@ -2,9 +2,16 @@ package mindustry.logic;
import arc.*;
import arc.func.*;
import arc.graphics.*;
import arc.scene.actions.*;
import arc.scene.ui.*;
import arc.scene.ui.TextButton.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.logic.LExecutor.*;
import mindustry.logic.LStatements.*;
import mindustry.ui.*;
import mindustry.ui.dialogs.*;
@@ -15,6 +22,7 @@ import static mindustry.logic.LCanvas.*;
public class LogicDialog extends BaseDialog{
public LCanvas canvas;
Cons<String> consumer = s -> {};
@Nullable LExecutor executor;
public LogicDialog(){
super("logic");
@@ -57,6 +65,90 @@ public class LogicDialog extends BaseDialog{
dialog.show();
}).name("edit");
buttons.button("@variables", Icon.menu, () -> {
BaseDialog dialog = new BaseDialog("@variables");
dialog.hidden(() -> {
if(!wasPaused){
state.set(State.paused);
}
});
dialog.shown(() -> {
if(!wasPaused){
state.set(State.playing);
}
});
dialog.cont.pane(p -> {
p.margin(10f).marginRight(16f);
p.table(Tex.button, t -> {
t.defaults().fillX().height(45f);
for(var s : executor.vars){
if(s.constant) continue;
Color varColor = Pal.gray;
float stub = 8f, mul = 0.5f, pad = 4;
Color color =
!s.isobj ? Pal.place :
s.objval == null ? Color.darkGray :
s.objval instanceof String ? Pal.ammo :
s.objval instanceof Content ? Pal.logicOperations :
s.objval instanceof Building ? Pal.logicBlocks :
s.objval instanceof Unit ? Pal.logicUnits :
s.objval instanceof Enum<?> ? Pal.logicIo :
Color.white;
String typeName =
!s.isobj ? "number" :
s.objval == null ? "null" :
s.objval instanceof String ? "string" :
s.objval instanceof Content ? "content" :
s.objval instanceof Building ? "building" :
s.objval instanceof Unit ? "unit" :
s.objval instanceof Enum<?> ? "enum" :
"unknown";
t.add(new Image(Tex.whiteui, varColor.cpy().mul(mul))).width(stub);
t.stack(new Image(Tex.whiteui, varColor), new Label(" " + s.name + " ", Styles.outlineLabel){{
setColor(Pal.accent);
}}).padRight(pad);
t.add(new Image(Tex.whiteui, Pal.gray.cpy().mul(mul))).width(stub);
t.table(Tex.pane, out -> {
float period = 15f;
float[] counter = {-1f};
Label label = out.add("").style(Styles.outlineLabel).padLeft(4).padRight(4).width(140f).wrap().get();
label.update(() -> {
if(counter[0] < 0 || (counter[0] += Time.delta) >= period){
String text = s.isobj ? PrintI.toString(s.objval) : Math.abs(s.numval - (long)s.numval) < 0.00001 ? (long)s.numval + "" : s.numval + "";
if(!label.textEquals(text)){
label.setText(text);
if(counter[0] >= 0f){
label.actions(Actions.color(Pal.accent), Actions.color(Color.white, 0.2f));
}
}
counter[0] = 0f;
}
});
label.act(1f);
}).padRight(pad);
//TODO type name does not update, is this important?
t.add(new Image(Tex.whiteui, color.cpy().mul(mul))).width(stub);
t.stack(new Image(Tex.whiteui, color), new Label(" " + typeName + " ", Styles.outlineLabel));
t.row();
t.add().growX().colspan(6).height(4).row();
}
});
});
dialog.addCloseButton();
dialog.show();
}).name("variables").disabled(b -> executor == null || executor.vars.length == 0);
buttons.button("@add", Icon.add, () -> {
BaseDialog dialog = new BaseDialog("@add");
dialog.cont.pane(t -> {
@@ -92,7 +184,8 @@ public class LogicDialog extends BaseDialog{
onResize(() -> canvas.rebuild());
}
public void show(String code, Cons<String> modified){
public void show(String code, LExecutor executor, Cons<String> modified){
this.executor = executor;
canvas.statements.clearChildren();
canvas.rebuild();
try{

View File

@@ -176,7 +176,7 @@ public class GameService{
});
Events.on(UnitControlEvent.class, e -> {
if(e.unit instanceof BlockUnitc && ((BlockUnitc)e.unit).tile().block == Blocks.router){
if(e.unit instanceof BlockUnitc unit && unit.tile().block == Blocks.router){
becomeRouter.complete();
}
});

View File

@@ -132,6 +132,12 @@ public class Planet extends UnlockableContent{
}
}
/** @deprecated confusing parameter orer, use the other constructor instead */
@Deprecated
public Planet(String name, Planet parent, int sectorSize, float radius){
this(name, parent, radius, sectorSize);
}
public @Nullable Sector getLastSector(){
if(sectors.isEmpty()){
return null;

View File

@@ -11,7 +11,7 @@ import mindustry.graphics.*;
import static mindustry.Vars.*;
public class BaseDialog extends Dialog{
private boolean wasPaused;
protected boolean wasPaused;
protected boolean shouldPause;
public BaseDialog(String title, DialogStyle style){

View File

@@ -50,6 +50,7 @@ public class Block extends UnlockableContent{
public boolean outputsPayload = false;
public boolean acceptsPayload = false;
public boolean acceptsItems = false;
public boolean separateItemCapacity = false;
public int itemCapacity = 10;
public float liquidCapacity = 10f;

View File

@@ -106,7 +106,7 @@ public class LaserTurret extends PowerTurret{
@Override
protected void bullet(BulletType type, float angle){
bullet = type.create(tile.build, team, x + tr.x, y + tr.y, angle);
bullet = type.create(this, team, x + tr.x, y + tr.y, angle);
bulletLife = shootDuration;
}

View File

@@ -4,6 +4,7 @@ import arc.graphics.g2d.*;
import arc.struct.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.core.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.gen.*;
@@ -90,9 +91,7 @@ public class LiquidTurret extends Turret{
@Override
public void updateTile(){
if(unit != null){
unit.ammo(unit.type().ammoCapacity * liquids.currentAmount() / liquidCapacity);
}
unit.ammo(unit.type().ammoCapacity * liquids.currentAmount() / liquidCapacity);
super.updateTile();
}
@@ -100,13 +99,14 @@ public class LiquidTurret extends Turret{
@Override
protected void findTarget(){
if(extinguish && liquids.current().canExtinguish()){
int tx = World.toTile(x), ty = World.toTile(y);
Fire result = null;
float mindst = 0f;
int tr = (int)(range / tilesize);
for(int x = -tr; x <= tr; x++){
for(int y = -tr; y <= tr; y++){
Tile other = world.tile(x + tile.x, y + tile.y);
var fire = Fires.get(x + tile.x, y + tile.y);
Tile other = world.tile(x + tx, y + ty);
var fire = Fires.get(x + tx, y + ty);
float dst = fire == null ? 0 : dst2(fire);
//do not extinguish fires on other team blocks
if(other != null && fire != null && Fires.has(other.x, other.y) && dst <= range * range && (result == null || dst < mindst) && (other.build == null || other.team() == team)){

View File

@@ -31,9 +31,7 @@ public class PowerTurret extends Turret{
@Override
public void updateTile(){
if(unit != null){
unit.ammo(power.status * unit.type().ammoCapacity);
}
unit.ammo(power.status * unit.type().ammoCapacity);
super.updateTile();
}

View File

@@ -149,15 +149,9 @@ public class Turret extends ReloadTurret{
public boolean logicShooting = false;
public @Nullable Posc target;
public Vec2 targetPos = new Vec2();
public @Nullable BlockUnitc unit;
public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team);
public boolean wasShooting, charging;
@Override
public void created(){
unit = (BlockUnitc)UnitTypes.block.create(team);
unit.tile(this);
}
@Override
public boolean canControl(){
return playerControllable;
@@ -165,7 +159,7 @@ public class Turret extends ReloadTurret{
@Override
public void control(LAccess type, double p1, double p2, double p3, double p4){
if(type == LAccess.shoot && (unit == null || !unit.isPlayer())){
if(type == LAccess.shoot && !unit.isPlayer()){
targetPos.set(World.unconv((float)p1), World.unconv((float)p2));
logicControlTime = logicControlCooldown;
logicShooting = !Mathf.zero(p3);
@@ -203,15 +197,14 @@ public class Turret extends ReloadTurret{
}
public boolean isShooting(){
return (isControlled() ? (unit != null && unit.isShooting()) : logicControlled() ? logicShooting : target != null);
return (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : target != null);
}
@Override
public Unit unit(){
if(unit == null){
unit = (BlockUnitc)UnitTypes.block.create(team);
unit.tile(this);
}
//make sure stats are correct
unit.tile(this);
unit.team(team);
return (Unit)unit;
}
@@ -267,12 +260,9 @@ public class Turret extends ReloadTurret{
recoil = Mathf.lerpDelta(recoil, 0f, restitution);
heat = Mathf.lerpDelta(heat, 0f, cooldown);
if(unit != null){
unit.health(health);
unit.rotation(rotation);
unit.team(team);
unit.set(x, y);
}
unit.tile(this);
unit.rotation(rotation);
unit.team(team);
if(logicControlTime > 0){
logicControlTime -= Time.delta;
@@ -338,7 +328,7 @@ public class Turret extends ReloadTurret{
if(targetAir && !targetGround){
target = Units.bestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded(), unitSort);
}else{
target = Units.bestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround), b -> true, unitSort);
target = Units.bestTarget(team, x, y, range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround), b -> targetGround, unitSort);
if(target == null && canHeal()){
target = Units.findAllyTile(team, x, y, range, b -> b.damaged() && b != this);
@@ -405,7 +395,7 @@ public class Turret extends ReloadTurret{
for(int i = 0; i < chargeEffects; i++){
Time.run(Mathf.random(chargeMaxDelay), () -> {
if(!isValid()) return;
if(dead) return;
tr.trns(rotation, shootLength);
chargeEffect.at(x + tr.x, y + tr.y, rotation);
});
@@ -414,7 +404,7 @@ public class Turret extends ReloadTurret{
charging = true;
Time.run(chargeTime, () -> {
if(!isValid()) return;
if(dead) return;
tr.trns(rotation, shootLength);
recoil = recoilAmount;
heat = 1f;
@@ -428,7 +418,7 @@ public class Turret extends ReloadTurret{
for(int i = 0; i < shots; i++){
int ii = i;
Time.run(burstSpacing * i, () -> {
if(!isValid() || !hasAmmo()) return;
if(dead || !hasAmmo()) return;
recoil = recoilAmount;
@@ -488,7 +478,7 @@ public class Turret extends ReloadTurret{
}
protected void ejectEffects(){
if(!isValid()) return;
if(dead) return;
//alternate sides when using a double turret
float scl = (shots == 2 && alternate && shotCounter % 2 == 1 ? -1f : 1f);

View File

@@ -22,7 +22,7 @@ import static mindustry.Vars.*;
public class Conveyor extends Block implements Autotiler{
private static final float itemSpace = 0.4f;
private static final int capacity = 4;
private static final int capacity = 3;
final Vec2 tr1 = new Vec2();
final Vec2 tr2 = new Vec2();
@@ -40,7 +40,7 @@ public class Conveyor extends Block implements Autotiler{
update = true;
group = BlockGroup.transportation;
hasItems = true;
itemCapacity = 4;
itemCapacity = capacity;
conveyorPlacement = true;
ambientSound = Sounds.conveyor;
@@ -132,7 +132,7 @@ public class Conveyor extends Block implements Autotiler{
public float minitem = 1;
public int blendbits, blending;
public int blendsclx, blendscly;
public int blendsclx = 1, blendscly = 1;
public float clogHeat = 0f;
@@ -163,12 +163,17 @@ public class Conveyor extends Block implements Autotiler{
tr2.trns(rotation * 90, -tilesize / 2f, xs[i] * tilesize / 2f);
Draw.rect(item.fullIcon,
(tile.x * tilesize + tr1.x * ys[i] + tr2.x),
(tile.y * tilesize + tr1.y * ys[i] + tr2.y),
(x + tr1.x * ys[i] + tr2.x),
(y + tr1.y * ys[i] + tr2.y),
itemSize, itemSize);
}
}
@Override
public void payloadDraw(){
Draw.rect(block.fullIcon,x, y);
}
@Override
public void drawCracks(){
Draw.z(Layer.block - 0.15f);
@@ -323,7 +328,7 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void handleStack(Item item, int amount, Teamc source){
amount = Math.min(amount, itemCapacity - len);
amount = Math.min(amount, capacity - len);
for(int i = amount - 1; i >= 0; i--){
add(0);

View File

@@ -184,6 +184,11 @@ public class ItemBridge extends Block{
public boolean wasMoved, moved;
public float transportCounter;
@Override
public void pickedUp(){
link = -1;
}
@Override
public void playerPlaced(Object config){
super.playerPlaced(config);

View File

@@ -165,7 +165,7 @@ public class MassDriver extends Block{
}
//align to shooter rotation
rotation = Angles.moveToward(rotation, tile.angleTo(currentShooter()), rotateSpeed * efficiency());
rotation = Angles.moveToward(rotation, angleTo(currentShooter()), rotateSpeed * efficiency());
}else if(state == DriverState.shooting){
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
if(!hasLink || (!waitingShooters.isEmpty() && (itemCapacity - items.total() >= minDistribute))){
@@ -173,7 +173,7 @@ public class MassDriver extends Block{
return;
}
float targetRotation = tile.angleTo(link);
float targetRotation = angleTo(link);
if(
items.total() >= minDistribute && //must shoot minimum amount of items

View File

@@ -114,7 +114,7 @@ public class PayloadConveyor extends Block{
int ntrns = 1 + size/2;
Tile next = tile.nearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
blocked = (next != null && next.solid() && !(next.block().outputsPayload || next.block().acceptsPayload)) || (this.next != null && this.next.block.rotate && (this.next.rotation + 2) % 4 == rotation);
blocked = (next != null && next.solid() && !(next.block().outputsPayload || next.block().acceptsPayload)) || (this.next != null && this.next.payloadCheck(rotation));
}
@Override
@@ -126,6 +126,10 @@ public class PayloadConveyor extends Block{
public void updateTile(){
if(!enabled) return;
if(item != null){
item.update();
}
lastInterp = curInterp;
curInterp = fract();
//rollover skip
@@ -231,6 +235,11 @@ public class PayloadConveyor extends Block{
}
}
@Override
public void payloadDraw(){
Draw.rect(block.fullIcon,x, y);
}
public float time(){
return Time.time;
}

View File

@@ -97,7 +97,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
public class ConduitBuild extends LiquidBuild implements ChainedBuilding{
public float smoothLiquid;
public int blendbits, xscl, yscl, blending;
public int blendbits, xscl = 1, yscl = 1, blending;
public boolean capped;
@Override

View File

@@ -7,7 +7,6 @@ import arc.struct.Bits;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.ai.types.*;
import mindustry.core.*;
import mindustry.gen.*;
@@ -493,7 +492,7 @@ public class LogicBlock extends Block{
@Override
public void buildConfiguration(Table table){
table.button(Icon.pencil, Styles.clearTransi, () -> {
Vars.ui.logic.show(code, code -> configure(compress(code, relativeConnections())));
ui.logic.show(code, executor, code -> configure(compress(code, relativeConnections())));
}).size(40);
}

View File

@@ -119,7 +119,7 @@ public class MessageBlock extends Block{
dialog.hide();
}).size(130f, 60f);
dialog.update(() -> {
if(tile.block() != MessageBlock.this){
if(tile.build != this){
dialog.hide();
}
});

View File

@@ -78,6 +78,7 @@ public abstract class BlockProducer extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
var recipe = recipe();
boolean produce = recipe != null && consValid() && payload == null;

View File

@@ -1,6 +1,7 @@
package mindustry.world.blocks.payloads;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.io.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -15,6 +16,7 @@ public class BuildPayload implements Payload{
public BuildPayload(Block block, Team team){
this.build = block.newBuilding().create(block, team);
this.build.tile = emptyTile;
}
public BuildPayload(Building build){
@@ -34,6 +36,12 @@ public class BuildPayload implements Payload{
build.dropped();
}
@Override
public void update(){
if(build.tile == null) build.tile = emptyTile;
build.update();
}
@Override
public ItemStack[] requirements(){
return build.block.requirements;
@@ -80,7 +88,10 @@ public class BuildPayload implements Payload{
@Override
public void draw(){
drawShadow(1f);
Draw.rect(build.block.fullIcon, build.x, build.y);
float prevZ = Draw.z();
Draw.zTransform(z -> 0.0011f + Mathf.clamp(z, prevZ - 0.001f, prevZ + 0.9f));
build.payloadDraw();
Draw.zTransform();
}
@Override

View File

@@ -8,6 +8,7 @@ import arc.util.io.*;
import mindustry.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.storage.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -23,6 +24,7 @@ public class Constructor extends BlockProducer{
size = 3;
configurable = true;
configClear((ConstructorBuild tile) -> tile.recipe = null);
config(Block.class, (ConstructorBuild tile, Block block) -> {
if(tile.recipe != block) tile.progress = 0f;
if(canProduce(block)){
@@ -40,7 +42,7 @@ public class Constructor extends BlockProducer{
}
public boolean canProduce(Block b){
return b.isVisible() && b.size >= minBlockSize && b.size <= maxBlockSize;
return b.isVisible() && b.size >= minBlockSize && b.size <= maxBlockSize && !(b instanceof CoreBlock) && !state.rules.bannedBlocks.contains(b);
}
public class ConstructorBuild extends BlockProducerBuild{

View File

@@ -36,6 +36,9 @@ public interface Payload extends Position{
/** @return the time taken to build this payload. */
float buildTime();
/** update this payload if it is a block */
default void update(){}
/** @return whether this payload was dumped. */
default boolean dump(){
return false;
@@ -94,6 +97,7 @@ public interface Payload extends Position{
BuildPayload payload = new BuildPayload(block, Team.derelict);
byte version = read.b();
payload.build.readAll(read, version);
payload.build.tile = emptyTile;
return (T)payload;
}else if(type == payloadUnit){
byte id = read.b();

View File

@@ -135,6 +135,13 @@ public class PayloadBlock extends Block{
if(payload != null && !carried) payload.dump();
}
@Override
public void updateTile(){
if(payload != null){
payload.update();
}
}
public boolean blends(int direction){
return PayloadBlock.blends(this, direction);
}

View File

@@ -85,6 +85,11 @@ public class PayloadDeconstructor extends PayloadBlock{
Draw.rect(topRegion, x, y);
}
@Override
public boolean acceptUnitPayload(Unit unit){
return payload == null && deconstructing == null && !unit.spawnedByCore && unit.type.getTotalRequirements().length > 0 && unit.hitSize / tilesize <= maxPayloadSize;
}
@Override
public void handlePayload(Building source, Payload payload){
super.handlePayload(source, payload);
@@ -93,11 +98,12 @@ public class PayloadDeconstructor extends PayloadBlock{
@Override
public boolean acceptPayload(Building source, Payload payload){
return deconstructing == null && super.acceptPayload(source, payload) && payload.requirements().length > 0 && payload.fits(maxPayloadSize);
return deconstructing == null && this.payload == null && super.acceptPayload(source, payload) && payload.requirements().length > 0 && payload.fits(maxPayloadSize);
}
@Override
public void updateTile(){
super.updateTile();
if(items.total() > 0){
for(int i = 0; i < dumpRate; i++){
dumpAccumulate();
@@ -153,10 +159,26 @@ public class PayloadDeconstructor extends PayloadBlock{
//finish deconstruction, prepare for next payload.
if(progress >= 1f){
Fx.breakBlock.at(x, y, deconstructing.size() / tilesize);
canProgress = true;
//check for rounding errors
for(int i = 0; i < reqs.length; i++){
if(Mathf.equal(accum[i], 1f, 0.0001f)){
if(items.total() < itemCapacity){
items.add(reqs[i].item, 1);
accum[i] = 0f;
}else{
canProgress = false;
break;
}
}
}
deconstructing = null;
accum = null;
if(canProgress){
Fx.breakBlock.at(x, y, deconstructing.size() / tilesize);
deconstructing = null;
accum = null;
}
}
}else if(moveInPayload(false) && payload != null){
accum = new float[payload.requirements().length];

View File

@@ -3,6 +3,7 @@ package mindustry.world.blocks.payloads;
import arc.*;
import arc.graphics.g2d.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.graphics.*;
@@ -58,15 +59,23 @@ public class PayloadLoader extends PayloadBlock{
}
public class PayloadLoaderBuild extends PayloadBlockBuild<BuildPayload>{
public boolean exporting = false;
@Override
public boolean acceptPayload(Building source, Payload payload){
return super.acceptPayload(source, payload) &&
payload.fits(maxBlockSize) &&
payload instanceof BuildPayload build &&
((build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize) ||
build.build.block().hasLiquids && build.block().liquidCapacity >= 10f);
}
@Override
public void handlePayload(Building source, Payload payload){
super.handlePayload(source, payload);
exporting = false;
}
@Override
public boolean acceptItem(Building source, Item item){
return items.total() < itemCapacity;
@@ -102,6 +111,7 @@ public class PayloadLoader extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
if(shouldExport()){
moveOutPayload();
}else if(moveInPayload()){
@@ -119,6 +129,9 @@ public class PayloadLoader extends PayloadBlock{
payload.build.handleItem(payload.build, item);
items.remove(item, 1);
break;
}else if(payload.block().separateItemCapacity || payload.block().consumes.consumesItem(item)){
exporting = true;
break;
}
}
}
@@ -146,8 +159,28 @@ public class PayloadLoader extends PayloadBlock{
public boolean shouldExport(){
return payload != null && (
exporting ||
(payload.block().hasLiquids && payload.build.liquids.total() >= payload.block().liquidCapacity - 0.001f) ||
(payload.block().hasItems && payload.build.items.total() >= payload.block().itemCapacity));
(payload.block().hasItems && payload.block().separateItemCapacity && content.items().contains(i -> payload.build.items.get(i) >= payload.block().itemCapacity)));
}
@Override
public byte version(){
return 1;
}
@Override
public void write(Writes write){
super.write(write);
write.bool(exporting);
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
if(revision >= 1){
exporting = read.bool();
}
}
}
}

View File

@@ -143,6 +143,7 @@ public class PayloadMassDriver extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
Building link = world.build(this.link);
boolean hasLink = linkValid();
@@ -233,7 +234,7 @@ public class PayloadMassDriver extends PayloadBlock{
}
//align to shooter rotation
turretRotation = Angles.moveToward(turretRotation, tile.angleTo(currentShooter()), rotateSpeed * efficiency());
turretRotation = Angles.moveToward(turretRotation, angleTo(currentShooter()), rotateSpeed * efficiency());
}else if(state == shooting){
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
if(!hasLink || (!waitingShooters.isEmpty() && payload == null)){
@@ -241,7 +242,7 @@ public class PayloadMassDriver extends PayloadBlock{
return;
}
float targetRotation = tile.angleTo(link);
float targetRotation = angleTo(link);
boolean movedOut = false;
payRotation = Angles.moveToward(payRotation, turretRotation, payloadRotateSpeed * delta());

View File

@@ -103,6 +103,7 @@ public class PayloadSource extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
if(payload == null){
scl = 0f;
if(unit != null){

View File

@@ -36,6 +36,7 @@ public class PayloadUnloader extends PayloadLoader{
@Override
public void updateTile(){
super.updateTile();
if(shouldExport()){
//one-use, disposable block
if(payload.block().instantDeconstruct){

View File

@@ -55,6 +55,7 @@ public class PayloadVoid extends PayloadBlock{
@Override
public void updateTile(){
super.updateTile();
if(moveInPayload(false) && cons.valid()){
payload = null;
incinerateEffect.at(this);

View File

@@ -141,7 +141,7 @@ public class ImpactReactor extends PowerGenerator{
if(warmup < 0.3f || !state.rules.reactorExplosions) return;
Sounds.explosionbig.at(tile);
Sounds.explosionbig.at(this);
Damage.damage(x, y, explosionRadius * tilesize, explosionDamage * 4);

View File

@@ -76,6 +76,7 @@ public class NuclearReactor extends PowerGenerator{
public class NuclearReactorBuild extends GeneratorBuild{
public float heat;
public float flash;
@Override
public void updateTile(){
@@ -130,7 +131,7 @@ public class NuclearReactor extends PowerGenerator{
public void onDestroyed(){
super.onDestroyed();
Sounds.explosionbig.at(tile);
Sounds.explosionbig.at(this);
int fuel = items.get(consumes.<ConsumeItems>get(ConsumeType.item).items[0].item);
@@ -160,10 +161,9 @@ public class NuclearReactor extends PowerGenerator{
Draw.rect(topRegion, x, y);
if(heat > flashThreshold){
float flash = 1f + ((heat - flashThreshold) / (1f - flashThreshold)) * 5.4f;
flash += flash * Time.delta;
flash += (1f + ((heat - flashThreshold) / (1f - flashThreshold)) * 5.4f) * Time.delta;
Draw.color(Color.red, Color.yellow, Mathf.absin(flash, 9f, 1f));
Draw.alpha(0.6f);
Draw.alpha(0.3f);
Draw.rect(lightsRegion, x, y);
}

View File

@@ -56,7 +56,7 @@ public class PowerDiode extends Block{
public void updateTile(){
super.updateTile();
if(front() == null || back() == null || !back().block.hasPower || !front().block.hasPower || back().team != front().team) return;
if(tile == null || front() == null || back() == null || !back().block.hasPower || !front().block.hasPower || back().team != front().team) return;
PowerGraph backGraph = back().power.graph;
PowerGraph frontGraph = front().power.graph;

View File

@@ -444,7 +444,7 @@ public class PowerNode extends PowerBlock{
public void draw(){
super.draw();
if(Mathf.zero(Renderer.laserOpacity)) return;
if(Mathf.zero(Renderer.laserOpacity) || isPayload()) return;
Draw.z(Layer.power);
setupColor(power.graph.getSatisfaction());

View File

@@ -52,6 +52,11 @@ public class AttributeCrafter extends GenericCrafter{
return baseEfficiency + Math.min(maxBoost, boostScale * attrsum) + attribute.env();
}
@Override
public void pickedUp(){
attrsum = 0f;
}
@Override
public void onProximityUpdate(){
super.onProximityUpdate();

View File

@@ -243,6 +243,11 @@ public class Drill extends Block{
}
}
@Override
public void pickedUp(){
dominantItem = null;
}
@Override
public void onProximityUpdate(){
super.onProximityUpdate();

View File

@@ -91,6 +91,11 @@ public class Pump extends LiquidBlock{
Drawf.liquid(liquidRegion, x, y, liquids.currentAmount() / liquidCapacity, liquids.current().color);
}
@Override
public void pickedUp(){
amount = 0f;
}
@Override
public void onProximityUpdate(){
super.onProximityUpdate();

View File

@@ -95,6 +95,11 @@ public class SolidPump extends Pump{
@Override
public void drawCracks(){}
@Override
public void pickedUp(){
boost = validTiles = 0f;
}
@Override
public void draw(){
Draw.rect(region, x, y);

View File

@@ -20,6 +20,7 @@ public class StorageBlock extends Block{
solid = true;
update = false;
destructible = true;
separateItemCapacity = true;
group = BlockGroup.transportation;
flags = EnumSet.of(BlockFlag.storage);
allowResupply = true;

View File

@@ -97,9 +97,9 @@ public class CommandCenter extends Block{
float size = 6f;
Draw.color(bottomColor);
Draw.rect(commandRegions[team.data().command.ordinal()].getRegion(), tile.drawx(), tile.drawy() - 1, size, size);
Draw.rect(commandRegions[team.data().command.ordinal()].getRegion(), x, y - 1, size, size);
Draw.color(topColor == null ? team.color : topColor);
Draw.rect(commandRegions[team.data().command.ordinal()].getRegion(), tile.drawx(), tile.drawy(), size, size);
Draw.rect(commandRegions[team.data().command.ordinal()].getRegion(), x, y, size, size);
Draw.color();
}

View File

@@ -185,6 +185,12 @@ public class Reconstructor extends UnitBlock{
Draw.rect(topRegion, x, y);
}
@Override
public Object senseObject(LAccess sensor){
if(sensor == LAccess.config) return unit();
return super.senseObject(sensor);
}
@Override
public void updateTile(){
boolean valid = false;

View File

@@ -176,7 +176,7 @@ public class RepairPoint extends Block{
multiplier = liq.valid(this) ? 1f + liquids.current().heatCapacity * coolantMultiplier : 1f;
}
if(target != null && (target.dead() || target.dst(tile) - target.hitSize/2f > repairRadius || target.health() >= target.maxHealth())){
if(target != null && (target.dead() || target.dst(this) - target.hitSize/2f > repairRadius || target.health() >= target.maxHealth())){
target = null;
}

View File

@@ -68,7 +68,7 @@ public class ConsumePower extends Consume{
* @return The amount of power which is requested per tick.
*/
public float requestedPower(Building entity){
if(entity.tile().build == null) return 0f;
if(entity.tile == null || entity.tile.build == null) return 0f;
if(buffered){
return (1f-entity.power.status)*capacity;
}else{

View File

@@ -16,6 +16,14 @@ public class Consumers{
public final Bits itemFilters = new Bits(Vars.content.items().size);
public final Bits liquidfilters = new Bits(Vars.content.liquids().size);
public boolean consumesItem(Item item){
return itemFilters.get(item.id);
}
public boolean consumesLiquid(Liquid liq){
return liquidfilters.get(liq.id);
}
public boolean any(){
return results != null && results.length > 0;
}

View File

@@ -6,7 +6,8 @@ import mindustry.graphics.*;
public enum BlockStatus{
active(Color.valueOf("5ce677")),
noOutput(Color.orange),
noInput(Pal.remove);
noInput(Pal.remove),
logicDisable(Color.valueOf("8a73c6"));
public final Color color;

View File

@@ -14,6 +14,10 @@ public class ConsumeModule extends BlockModule{
}
public BlockStatus status(){
if(entity.enabledControlTime > 0 && !entity.enabled){
return BlockStatus.logicDisable;
}
if(!entity.shouldConsume()){
return BlockStatus.noOutput;
}