Merging changes from private branch

This commit is contained in:
Anuken
2025-04-04 11:47:35 -04:00
parent cf5c6d0905
commit b7dbe54d76
161 changed files with 2484 additions and 1137 deletions
+38 -12
View File
@@ -156,6 +156,8 @@ public class Block extends UnlockableContent implements Senseable{
public boolean updateInUnits = true;
/** if true, this block updates in payloads in units regardless of the experimental game rule */
public boolean alwaysUpdateInUnits = false;
/** if true, this block can be picked up in payloads */
public boolean canPickup = true;
/** if false, only incinerable liquids are dropped when deconstructing; otherwise, all liquids are dropped. */
public boolean deconstructDropAllLiquid = false;
/** Whether to use this block's color in the minimap. Only used for overlays. */
@@ -174,6 +176,8 @@ public class Block extends UnlockableContent implements Senseable{
public float armor = 0f;
/** base block explosiveness */
public float baseExplosiveness = 0f;
/** base value for screen shake upon destruction */
public float baseShake = 3f;
/** bullet that this block spawns when destroyed */
public @Nullable BulletType destroyBullet = null;
/** if true, destroyBullet is spawned on the block's team instead of Derelict team */
@@ -194,6 +198,8 @@ public class Block extends UnlockableContent implements Senseable{
public int sizeOffset = 0;
/** Clipping size of this block. Should be as large as the block will draw. */
public float clipSize = -1f;
/** Clipping size for lights only. */
public float lightClipSize;
/** When placeRangeCheck is enabled, this is the range checked for enemy blocks. */
public float placeOverlapRange = 50f;
/** Multiplier of damage dealt to this block by tanks. Does not apply to crawlers. */
@@ -290,13 +296,13 @@ public class Block extends UnlockableContent implements Senseable{
public Sound breakSound = Sounds.breaks;
/** Sounds made when this block is destroyed.*/
public Sound destroySound = Sounds.boom;
/** Range of destroy sound. */
public float destroyPitchMin = 1f, destroyPitchMax = 1f;
/** How reflective this block is. */
public float albedo = 0f;
/** Environmental passive light color. */
public Color lightColor = Color.white.cpy();
/**
* Whether this environmental block passively emits light.
* Does not change behavior for non-environmental blocks, but still updates clipSize. */
/** If true, drawLight() will be called for this block. */
public boolean emitLight = false;
/** Radius of the light emitted by this block. */
public float lightRadius = 60f;
@@ -304,11 +310,6 @@ public class Block extends UnlockableContent implements Senseable{
/** How much fog this block uncovers, in tiles. Cannot be dynamic. <= 0 to disable. */
public int fogRadius = -1;
/** The sound that this block makes while active. One sound loop. Do not overuse. */
public Sound loopSound = Sounds.none;
/** Active sound base volume. */
public float loopSoundVolume = 0.5f;
/** The sound that this block makes while idle. Uses one sound loop for all blocks. */
public Sound ambientSound = Sounds.none;
/** Idle sound base volume. */
@@ -344,6 +345,8 @@ public class Block extends UnlockableContent implements Senseable{
public ObjectFloatMap<Item> researchCostMultipliers = new ObjectFloatMap<>();
/** Override for research cost. Uses multipliers above and building requirements if not set. */
public @Nullable ItemStack[] researchCost;
/** If set, all blocks will be forced to be this team. */
public @Nullable Team forceTeam;
/** Whether this block has instant transfer.*/
public boolean instantTransfer = false;
/** Whether you can rotate this block after it is placed. */
@@ -434,6 +437,18 @@ public class Block extends UnlockableContent implements Senseable{
drawOverlay(x * tilesize + offset, y * tilesize + offset, rotation);
}
/** Draws a region to overlay a specific side of this block. This method makes sure it is placed at the edge of the side. */
public void drawSideRegion(TextureRegion region, float x, float y, int rotation){
var p = Geometry.d4[Mathf.mod(rotation, 4)];
float s = size * tilesize/2f;
Draw.rect(region,
x + p.x * (s - region.width/2f * region.scl()),
y + p.y * (s - region.width/2f * region.scl()),
rotation * 90f
);
}
public void drawPotentialLinks(int x, int y){
if((consumesPower || outputsPower) && hasPower && connectedPower){
Tile tile = world.tile(x, y);
@@ -492,6 +507,10 @@ public class Block extends UnlockableContent implements Senseable{
public void drawOverlay(float x, float y, int rotation){
}
public boolean displayShadow(Tile tile){
return hasShadow;
}
public float sumAttribute(@Nullable Attribute attr, int x, int y){
if(attr == null) return 0;
Tile tile = world.tile(x, y);
@@ -887,8 +906,8 @@ public class Block extends UnlockableContent implements Senseable{
return buildType.get();
}
public void updateClipRadius(float size){
clipSize = Math.max(clipSize, size * tilesize + size * 2f);
public void updateClipRadius(float radiusInWorldUnits){
clipSize = Math.max(clipSize, this.size * tilesize + radiusInWorldUnits * 2f);
}
public Rect bounds(int x, int y, Rect rect){
@@ -1196,6 +1215,10 @@ public class Block extends UnlockableContent implements Senseable{
hasShadow = false;
}
if(underBullets){
priority = TargetPriority.under;
}
if(fogRadius > 0){
flags = flags.with(BlockFlag.hasFogRadius);
}
@@ -1222,12 +1245,15 @@ public class Block extends UnlockableContent implements Senseable{
clipSize = Math.max(clipSize, size * tilesize);
lightClipSize = Math.max(lightClipSize, clipSize);
if(hasLiquids && drawLiquidLight){
clipSize = Math.max(size * 30f * 2f, clipSize);
emitLight = true;
lightClipSize = Math.max(lightClipSize, size * 30f * 2f);
}
if(emitLight){
clipSize = Math.max(clipSize, lightRadius * 2f);
lightClipSize = Math.max(lightClipSize, lightRadius * 2f);
}
if(group == BlockGroup.transportation || category == Category.distribution){
+13 -7
View File
@@ -164,7 +164,12 @@ public class Build{
/** @return whether a tile can be placed at this location by this team. */
public static boolean validPlace(Block type, Team team, int x, int y, int rotation, boolean checkVisible){
return validPlaceIgnoreUnits(type, team, x, y, rotation, checkVisible) && checkNoUnitOverlap(type, x, y);
return validPlace(type, team, x, y, rotation, checkVisible, true);
}
/** @return whether a tile can be placed at this location by this team. */
public static boolean validPlace(Block type, Team team, int x, int y, int rotation, boolean checkVisible, boolean ignoreCoreRadius){
return validPlaceIgnoreUnits(type, team, x, y, rotation, checkVisible, ignoreCoreRadius) && checkNoUnitOverlap(type, x, y);
}
/** @return whether a tile can be placed at this location by this team. */
@@ -172,14 +177,14 @@ public class Build{
return (!type.solid && !type.solidifes) || !Units.anyEntities(x * tilesize + type.offset - type.size * tilesize / 2f, y * tilesize + type.offset - type.size * tilesize / 2f, type.size * tilesize, type.size * tilesize);
}
/** Returns whether a tile can be placed at this location by this team. Ignores units at this location. */
public static boolean validPlaceIgnoreUnits(Block type, Team team, int x, int y, int rotation, boolean checkVisible){
/** @return whether a tile can be placed at this location by this team. Ignores units at this location. */
public static boolean validPlaceIgnoreUnits(Block type, Team team, int x, int y, int rotation, boolean checkVisible, boolean checkCoreRadius){
//the wave team can build whatever they want as long as it's visible - banned blocks are not applicable
if(type == null || (!state.rules.editor && (checkVisible && (!type.environmentBuildable() || (!type.isPlaceable() && !(state.rules.waves && team == state.rules.waveTeam && type.isVisible())))))){
return false;
}
if(!state.rules.editor){
if(!state.rules.editor && checkCoreRadius){
//find closest core, if it doesn't match the team, placing is not legal
if(state.rules.polygonCoreProtection){
float mindst = Float.MAX_VALUE;
@@ -240,8 +245,9 @@ public class Build{
(type == check.block() && check.build != null && rotation == check.build.rotation && type.rotate && !((type == check.block && team != Team.derelict && check.team() == Team.derelict))) || //same block, same rotation
!check.interactable(team) || //cannot interact
!check.floor().placeableOn && !type.ignoreBuildDarkness || //solid floor
(!checkVisible && !check.block().alwaysReplace) || //replacing a block that should be replaced (e.g. payload placement)
!(((type.canReplace(check.block()) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type
//when you have a payload, you cannot place blocks on things, even if normal placement rules allow it. this is a hack that assumes checkVisible = true means it's coming from a payload
(!checkVisible && checkCoreRadius && !check.block().alwaysReplace) || //replacing a block that should be replaced (e.g. payload placement)
!(((type.canReplace(check.block()) || (check.build != null && check.build.canBeReplaced(type)) || (type == check.block && team != Team.derelict && state.rules.derelictRepair && check.team() == Team.derelict)) || //can replace type OR can replace derelict block of same type
(check.build instanceof ConstructBuild build && build.current == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction
type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement
(type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found
@@ -249,7 +255,7 @@ public class Build{
}
}
if(state.rules.placeRangeCheck && !state.isEditor() && getEnemyOverlap(type, team, x, y) != null){
if(state.rules.placeRangeCheck && checkCoreRadius && !state.isEditor() && getEnemyOverlap(type, team, x, y) != null){
return false;
}
+3 -3
View File
@@ -28,11 +28,11 @@ public class CachedTile extends Tile{
if(block.hasBuilding()){
Building n = entityprov.get();
n.tile(this);
n.tile = this;
n.block = block;
if(block.hasItems) n.items = new ItemModule();
if(block.hasLiquids) n.liquids(new LiquidModule());
if(block.hasPower) n.power(new PowerModule());
if(block.hasLiquids) n.liquids = new LiquidModule();
if(block.hasPower) n.power = new PowerModule();
build = n;
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ public class Edges{
}
public static Tile getFacingEdge(Building tile, Building other){
Tile res = getFacingEdge(tile.block, tile.tileX(), tile.tileY(), other.tile());
Tile res = getFacingEdge(tile.block, tile.tileX(), tile.tileY(), other.tile);
return res == null ? tile.tile : res;
}
+9 -1
View File
@@ -23,6 +23,7 @@ import static mindustry.Vars.*;
public class Tile implements Position, QuadTreeObject, Displayable{
private static final TileChangeEvent tileChange = new TileChangeEvent();
private static final TilePreChangeEvent preChange = new TilePreChangeEvent();
private static final TileFloorChangeEvent floorChange = new TileFloorChangeEvent();
private static final ObjectSet<Building> tileSet = new ObjectSet<>();
/** Extra data for very specific blocks. */
@@ -223,6 +224,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{
recacheWall();
}
if(type.forceTeam != null) team = type.forceTeam;
preChanged();
this.block = type;
@@ -282,6 +285,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
/** This resets the overlay! */
public void setFloor(Floor type){
var prev = this.floor;
this.floor = type;
this.overlay = (Floor)Blocks.air;
@@ -293,9 +297,13 @@ public class Tile implements Position, QuadTreeObject, Displayable{
if(build != null){
build.onProximityUpdate();
}
if(!world.isGenerating() && pathfinder != null){
if(!world.isGenerating() && pathfinder != null && !state.isEditor()){
pathfinder.updateTile(this);
}
if(!world.isGenerating() && prev != type){
Events.fire(floorChange.set(this, prev, type));
}
}
public boolean isEditorTile(){
-1
View File
@@ -40,7 +40,6 @@ public class Tiles implements Iterable<Tile>{
fires[pos] = f;
}
public void each(Intc2 cons){
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
@@ -342,7 +342,6 @@ public class LandingPad extends Block{
@Override
public void drawSelect(){
if(config != null){
drawItemSelection(config);
float dx = x - size * tilesize/2f, dy = y + size * tilesize/2f, s = iconSmall / 4f;
Draw.mixcol(Color.darkGray, 1f);
@@ -52,7 +52,7 @@ public class Door extends Wall{
if(chainEffect) entity.effect();
entity.open = open;
if(!world.isGenerating()) pathfinder.updateTile(entity.tile());
if(!world.isGenerating()) pathfinder.updateTile(entity.tile);
}
});
}
@@ -3,6 +3,7 @@ package mindustry.world.blocks.defense;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
@@ -39,6 +40,7 @@ public class MendProjector extends Block{
lightRadius = 50f;
suppressable = true;
envEnabled |= Env.space;
flags = EnumSet.of(BlockFlag.blockRepair);
}
@Override
@@ -19,9 +19,6 @@ import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class OverdriveProjector extends Block{
@Deprecated
public final int timerUse = timers++;
public @Load("@-top") TextureRegion topRegion;
public float reload = 60f;
public float range = 80f;
@@ -46,6 +46,7 @@ public class RegenProjector extends Block{
suppressable = true;
envEnabled |= Env.space;
rotateDraw = false;
flags = EnumSet.of(BlockFlag.blockRepair);
}
@Override
@@ -133,8 +134,6 @@ public class RegenProjector extends Block{
return;
}
anyTargets = targets.contains(b -> b.damaged());
if(efficiency > 0){
if((optionalTimer += Time.delta * optionalEfficiency) >= optionalUseTime){
consume();
@@ -148,6 +147,7 @@ public class RegenProjector extends Block{
if(!build.damaged() || build.isHealSuppressed()) continue;
didRegen = true;
anyTargets = true;
int pos = build.pos();
//TODO periodic effect
@@ -10,6 +10,7 @@ import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.audio.*;
import mindustry.content.*;
import mindustry.core.*;
import mindustry.entities.*;
@@ -118,6 +119,10 @@ public class Turret extends ReloadTurret{
public Sound shootSound = Sounds.shoot;
/** Sound emitted when shoot.firstShotDelay is >0 and shooting begins. */
public Sound chargeSound = Sounds.none;
/** The sound that this block makes while active. One sound loop. Do not overuse. */
public Sound loopSound = Sounds.none;
/** Active sound base volume. */
public float loopSoundVolume = 0.5f;
/** Range for pitch of shoot sound. */
public float soundPitchMin = 0.9f, soundPitchMax = 1.1f;
/** Backwards Y offset of ammo eject effect. */
@@ -254,8 +259,26 @@ public class Turret extends ReloadTurret{
public float heatReq;
public float[] sideHeat = new float[4];
public @Nullable SoundLoop soundLoop = (loopSound == Sounds.none ? null : new SoundLoop(loopSound, loopSoundVolume));
float lastRangeChange;
@Override
public void remove(){
super.remove();
if(soundLoop != null){
soundLoop.stop();
}
}
@Override
public void onDestroyed(){
super.onDestroyed();
if(soundLoop != null){
soundLoop.stop();
}
}
@Override
public float estimateDps(){
if(!hasAmmo()) return 0f;
@@ -410,6 +433,10 @@ public class Turret extends ReloadTurret{
public void updateTile(){
if(!validateTarget()) target = null;
if(soundLoop != null){
soundLoop.update(x, y, shouldActiveSound(), activeSoundVolume());
}
float warmupTarget = (isShooting() && canConsume()) || charging() ? 1f : 0f;
if(warmupTarget > 0 && !isControlled()){
warmupHold = 1f;
@@ -705,12 +732,10 @@ public class Turret extends ReloadTurret{
}
@Override
public float activeSoundVolume(){
return shootWarmup;
}
@Override
public boolean shouldActiveSound(){
return shootWarmup > 0.01f && loopSound != Sounds.none;
}
@@ -29,7 +29,7 @@ public class ArmoredConveyor extends Conveyor{
public class ArmoredConveyorBuild extends ConveyorBuild{
@Override
public boolean acceptItem(Building source, Item item){
return super.acceptItem(source, item) && (source.block instanceof Conveyor || Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation);
return super.acceptItem(source, item) && (source.block instanceof Conveyor || Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation);
}
}
}
@@ -1,6 +1,7 @@
package mindustry.world.blocks.distribution;
import arc.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
@@ -30,7 +31,7 @@ public class Duct extends Block implements Autotiler{
public @Load(value = "@-top-#", length = 5) TextureRegion[] topRegions;
public @Load(value = "@-bottom-#", length = 5, fallback = "duct-bottom-#") TextureRegion[] botRegions;
public @Nullable Block bridgeReplacement;
public @Nullable Block bridgeReplacement, junctionReplacement;
public Duct(String name){
super(name);
@@ -63,6 +64,7 @@ public class Duct extends Block implements Autotiler{
super.init();
if(bridgeReplacement == null || !(bridgeReplacement instanceof DuctBridge || bridgeReplacement instanceof ItemBridge)) bridgeReplacement = Blocks.ductBridge;
//if(junctionReplacement == null) junctionReplacement = Blocks.ductJunction;
}
@Override
@@ -103,11 +105,24 @@ public class Duct extends Block implements Autotiler{
return new TextureRegion[]{Core.atlas.find("duct-bottom"), topRegions[0]};
}
@Override
public Block getReplacement(BuildPlan req, Seq<BuildPlan> plans){
if(junctionReplacement == null || !junctionReplacement.unlockedNow() || junctionReplacement.isHidden()) return this;
Boolf<Point2> cont = p -> plans.contains(o -> o.x == req.x + p.x && o.y == req.y + p.y && (req.block instanceof Duct || req.block instanceof DuctJunction));
return cont.get(Geometry.d4(req.rotation)) &&
cont.get(Geometry.d4(req.rotation - 2)) &&
req.tile() != null &&
req.tile().block() instanceof Duct &&
Mathf.mod(req.tile().build.rotation - req.rotation, 2) == 1 ? junctionReplacement : this;
}
@Override
public void handlePlacementLine(Seq<BuildPlan> plans){
if(bridgeReplacement == null) return;
if(bridgeReplacement instanceof ItemBridge bridge) Placement.calculateBridges(plans, bridge, false, b -> b instanceof Duct || b instanceof StackConveyor || b instanceof Conveyor);
if(bridgeReplacement instanceof DuctBridge bridge) Placement.calculateBridges(plans, bridge, false, b -> b instanceof Duct || b instanceof StackConveyor || b instanceof Conveyor);
boolean hasJunction = junctionReplacement != null && junctionReplacement.unlockedNow() && !junctionReplacement.isHidden();
if(bridgeReplacement instanceof ItemBridge bridge) Placement.calculateBridges(plans, bridge, hasJunction, b -> b instanceof Duct || b instanceof StackConveyor || b instanceof Conveyor);
if(bridgeReplacement instanceof DuctBridge bridge) Placement.calculateBridges(plans, bridge, hasJunction, b -> b instanceof Duct || b instanceof StackConveyor || b instanceof Conveyor);
}
public class DuctBuild extends Building{
@@ -137,7 +152,7 @@ public class Duct extends Block implements Autotiler{
Draw.z(Layer.blockUnder + 0.1f);
Tmp.v1.set(Geometry.d4x(recDir) * tilesize / 2f, Geometry.d4y(recDir) * tilesize / 2f)
.lerp(Geometry.d4x(r) * tilesize / 2f, Geometry.d4y(r) * tilesize / 2f,
Mathf.clamp((progress + 1f) / 2f));
Mathf.clamp((progress + 1f) / (2f - 1f/speed)));
Draw.rect(current.fullIcon, x + Tmp.v1.x, y + Tmp.v1.y, itemSize, itemSize);
}
@@ -188,7 +203,7 @@ public class Duct extends Block implements Autotiler{
(armored ?
//armored acceptance
((source.block.rotate && source.front() == this && source.block.hasItems && source.block.isDuct) ||
Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation) :
Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation) :
//standard acceptance - do not accept from front
!(source.block.rotate && next == source) && Edges.getFacingEdge(source.tile, tile) != null && Math.abs(Edges.getFacingEdge(source.tile, tile).relativeTo(tile.x, tile.y) - rotation) != 2
);
@@ -0,0 +1,179 @@
package mindustry.world.blocks.distribution;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class DuctJunction extends Block{
public Color transparentColor = new Color(0.4f, 0.4f, 0.4f, 0.1f);
public @Load("@-bottom") TextureRegion bottomRegion;
public @Load("@-top") TextureRegion topRegion;
public float speed = 5f;
public DuctJunction(String name){
super(name);
update = true;
solid = false;
underBullets = true;
group = BlockGroup.transportation;
unloadable = false;
floating = true;
noUpdateDisabled = true;
hasItems = true;
priority = TargetPriority.transport;
envEnabled = Env.space | Env.terrestrial | Env.underwater;
}
@Override
public void setStats(){
super.setStats();
//4 tems is misleading
stats.remove(Stat.itemCapacity);
}
@Override
public void load(){
super.load();
squareSprite = true;
}
@Override
public boolean outputsItems(){
return true;
}
@Override
public void init(){
itemCapacity = 4;
super.init();
}
public class DuctJunctionBuild extends Building{
Item[] itemdata = new Item[4];
float[] times = new float[4];
@Override
public void draw(){
Draw.z(Layer.blockUnder);
Draw.rect(bottomRegion, x, y);
Draw.z(Layer.blockUnder + 0.1f);
for(int i = 0; i < 4; i++){
Item current = itemdata[i];
if(current != null){
float progress = (Mathf.clamp((times[i] + 1f) / (2f - 1f/speed)) - 0.5f) * 2f;
Draw.rect(current.fullIcon,
x + Geometry.d4x(i) * tilesize / 2f * progress,
y + Geometry.d4y(i) * tilesize / 2f * progress,
itemSize, itemSize
);
}
}
Draw.color(transparentColor);
Draw.rect(bottomRegion, x, y);
Draw.color();
Draw.z(Layer.blockUnder + 0.2f);
Draw.rect(topRegion, x, y);
}
@Override
public void updateTile(){
float inc = edelta() / speed * 2f;
for(int i = 0; i < 4; i++){
Item item = itemdata[i];
if(item != null){
times[i] += inc;
if(times[i] >= (1f - 1f/speed)){
Building next = nearby(i);
if(next != null && next.team == team && next.acceptItem(this, item)){
next.handleItem(this, item);
itemdata[i] = null;
items.remove(item, 1);
times[i] %= (1f - 1f/speed);
}
}
}else{
//TODO: reset progress or not?
times[i] = 0f;
}
}
}
@Override
public void handleItem(Building source, Item item){
int relative = source.relativeTo(tile);
if(relative == -1) return;
itemdata[relative] = item;
times[relative] = -1f;
items.add(item, 1);
}
@Override
public boolean acceptItem(Building source, Item item){
int relative = source.relativeTo(tile);
if(relative == -1 || itemdata[relative] != null) return false;
Building to = nearby(relative);
return to != null && to.team == team;
}
@Override
public int acceptStack(Item item, int amount, Teamc source){
return 0;
}
@Override
public int removeStack(Item item, int amount){
int removed = 0;
for(int i = 0; i < 4 && amount > 0; i++){
if(itemdata[i] == item){
amount --;
removed ++;
itemdata[i] = null;
items.remove(item, 1);
}
}
return removed;
}
@Override
public void write(Writes write){
super.write(write);
for(int i = 0; i < 4; i++){
write.f(times[i]);
TypeIO.writeItem(write, itemdata[i]);
}
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
for(int i = 0; i < 4; i++){
times[i] = read.f();
itemdata[i] = TypeIO.readItem(read);
}
}
}
}
@@ -147,7 +147,7 @@ public class DuctRouter extends Block{
@Override
public boolean acceptItem(Building source, Item item){
return current == null && items.total() == 0 &&
(Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation);
(Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation);
}
@Override
@@ -248,7 +248,7 @@ public class MassDriver extends Block{
if(linkValid()){
Building target = world.build(link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place);
Drawf.circles(target.x, target.y, (target.block.size / 2f + 1) * tilesize + sin - 2f, Pal.place);
Drawf.arrow(x, y, target.x, target.y, size * tilesize + sin, 4f + sin);
}
@@ -132,7 +132,7 @@ public class OverflowDuct extends Block{
@Override
public boolean acceptItem(Building source, Item item){
return current == null && items.total() == 0 &&
(Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation);
(Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation);
}
@Override
@@ -83,7 +83,7 @@ public class Router extends Block{
items.add(item, 1);
lastItem = item;
time = 0f;
lastInput = source.tile();
lastInput = source.tile;
}
@Override
@@ -85,7 +85,7 @@ public class StackRouter extends DuctRouter{
@Override
public boolean acceptItem(Building source, Item item){
return !unloading && (current == null || item == current) && items.total() < itemCapacity &&
(Edges.getFacingEdge(source.tile(), tile).relativeTo(tile) == rotation);
(Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation);
}
}
}
@@ -213,6 +213,11 @@ public class Floor extends Block{
return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")};
}
/** @return whether to index this floor by flag */
public boolean shouldIndex(Tile tile){
return true;
}
//TODO currently broken for dynamically edited floor tiles
/** @return true if this floor should be updated in the render loop, e.g. for effects. Do NOT overuse this! */
public boolean updateRender(Tile tile){
@@ -319,11 +324,6 @@ public class Floor extends Block{
return edges(x, y)[rx][2 - ry];
}
@Deprecated
protected TextureRegion[][] edges(){
return edges(0, 0);
}
/** @return whether the edges from {@param other} should be drawn onto this tile **/
protected boolean doEdge(Tile tile, Tile otherTile, Floor other){
return (other.realBlendId(otherTile) > realBlendId(tile) || edges(tile.x, tile.y) == null);
@@ -4,12 +4,14 @@ import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.graphics.*;
import mindustry.world.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -41,6 +43,7 @@ public class SteamVent extends Floor{
public SteamVent(String name){
super(name);
variants = 2;
flags = EnumSet.of(BlockFlag.steamVent);
}
@Override
@@ -58,6 +61,16 @@ public class SteamVent extends Floor{
return checkAdjacent(tile);
}
@Override
public boolean shouldIndex(Tile tile){
return isCenterVent(tile);
}
public boolean isCenterVent(Tile tile){
Tile topRight = tile.nearby(1, 1);
return topRight != null && topRight.floor() == tile.floor() && checkAdjacent(topRight);
}
@Override
public void renderUpdate(UpdateRenderState state){
if(state.tile.nearby(-1, -1) != null && state.tile.nearby(-1, -1).block() == Blocks.air && (state.data += Time.delta) >= effectSpacing){
@@ -66,6 +79,7 @@ public class SteamVent extends Floor{
}
}
//note that only the top right tile works for this; render order reasons.
public boolean checkAdjacent(Tile tile){
for(var point : offsets){
Tile other = Vars.world.tile(tile.x + point.x, tile.y + point.y);
@@ -1,6 +1,7 @@
package mindustry.world.blocks.heat;
import arc.math.*;
import arc.struct.*;
import arc.util.io.*;
import mindustry.graphics.*;
import mindustry.ui.*;
@@ -20,6 +21,8 @@ public class HeatProducer extends GenericCrafter{
rotate = true;
canOverdrive = false;
drawArrow = true;
//it doesn't count as a standard crafter
flags = EnumSet.of();
}
@Override
@@ -88,7 +88,7 @@ public class MessageBlock extends Block{
Draw.color(0f, 0f, 0f, 0.2f);
Fill.rect(x, y - tilesize/2f - l.height/2f - offset, l.width + offset*2f, l.height + offset*2f);
Draw.color();
font.setColor(Color.white);
font.setColor(message.length() == 0 ? Color.lightGray : Color.white);
font.draw(text, x - l.width/2f, y - tilesize/2f - offset, 90f, Align.left, true);
font.setUseIntegerPositions(ints);
@@ -84,7 +84,7 @@ public class BuildPayload implements Payload{
@Override
public void remove(){
build.stopSound();
build.remove();
}
@Override
@@ -207,7 +207,7 @@ public class PayloadBlock extends Block{
payVector.approach(dest, payloadSpeed * delta());
Building front = front();
boolean canDump = front == null || !front.tile().solid();
boolean canDump = front == null || !front.tile.solid();
boolean canMove = front != null && (front.block.outputsPayload || front.block.acceptsPayload);
if(canDump && !canMove){
@@ -94,7 +94,7 @@ public class PayloadLoader extends PayloadBlock{
//item container
(build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize) ||
//liquid container
(build.build.block().hasLiquids && build.block().liquidCapacity >= 10f) ||
(build.build.block.hasLiquids && build.block().liquidCapacity >= 10f) ||
//battery
(build.build.block.consPower != null && build.build.block.consPower.buffered)
);
@@ -22,7 +22,7 @@ import static mindustry.world.blocks.payloads.PayloadMassDriver.PayloadDriverSta
public class PayloadMassDriver extends PayloadBlock{
public float range = 100f;
public float rotateSpeed = 2f;
public float rotateSpeed = 5f;
public float length = 89 / 8f;
public float knockback = 5f;
public float reload = 30f;
@@ -72,7 +72,7 @@ public class PayloadMassDriver extends PayloadBlock{
@Override
public void init(){
super.init();
updateClipRadius(range);
updateClipRadius(range + 4f);
}
@Override
@@ -430,7 +430,7 @@ public class PayloadMassDriver extends PayloadBlock{
if(linkValid()){
Building target = world.build(link);
Drawf.circles(target.x, target.y, (target.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place);
Drawf.circles(target.x, target.y, (target.block.size / 2f + 1) * tilesize + sin - 2f, Pal.place);
Drawf.arrow(x, y, target.x, target.y, size * tilesize + sin, 4f + sin);
}
@@ -149,6 +149,7 @@ public class UnitPayload implements Payload{
float e = unit.elevation;
unit.elevation = 0f;
Draw.scl(1f, 1f);
unit.type.draw(unit);
unit.elevation = e;
@@ -5,7 +5,6 @@ import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.world.draw.*;
@@ -17,9 +16,6 @@ public class Battery extends PowerDistributor{
public Color emptyLightColor = Color.valueOf("f8c266");
public Color fullLightColor = Color.valueOf("fb9567");
@Deprecated
public @Load("@-top") TextureRegion topRegion;
public Battery(String name){
super(name);
outputsPower = true;
@@ -39,7 +39,7 @@ public class LightBlock extends Block{
@Override
public void init(){
lightRadius = radius*2.5f;
clipSize = Math.max(clipSize, lightRadius * 3f);
lightClipSize = Math.max(lightClipSize, lightRadius * 3f);
emitLight = true;
super.init();
@@ -49,6 +49,7 @@ public class NuclearReactor extends PowerGenerator{
hasItems = true;
hasLiquids = true;
rebuildable = false;
emitLight = true;
flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator);
schematicPriority = -5;
envEnabled = Env.any;
@@ -194,7 +194,7 @@ public class PowerNode extends PowerBlock{
}
protected boolean overlaps(Building src, Building other, float range){
return overlaps(src.x, src.y, other.tile(), range);
return overlaps(src.x, src.y, other.tile, range);
}
protected boolean overlaps(Tile src, Tile other, float range){
@@ -209,9 +209,9 @@ public class PowerNode extends PowerBlock{
protected void getPotentialLinks(Tile tile, Team team, Cons<Building> others){
if(!autolink) return;
Boolf<Building> valid = other -> other != null && other.tile() != tile && other.block.connectedPower && other.power != null &&
Boolf<Building> valid = other -> other != null && other.tile != tile && other.block.connectedPower && other.power != null &&
(other.block.outputsPower || other.block.consumesPower || other.block instanceof PowerNode) &&
overlaps(tile.x * tilesize + offset, tile.y * tilesize + offset, other.tile(), laserRange * tilesize) && other.team == team &&
overlaps(tile.x * tilesize + offset, tile.y * tilesize + offset, other.tile, laserRange * tilesize) && other.team == team &&
!graphs.contains(other.power.graph) &&
!PowerNode.insulated(tile, other.tile) &&
!(other instanceof PowerNodeBuild obuild && obuild.power.links.size >= ((PowerNode)obuild.block).maxNodes) &&
@@ -264,7 +264,7 @@ public class PowerNode extends PowerBlock{
//TODO code duplication w/ method above?
/** Iterates through linked nodes of a block at a tile. All returned buildings are power nodes. */
public static void getNodeLinks(Tile tile, Block block, Team team, Cons<Building> others){
Boolf<Building> valid = other -> other != null && other.tile() != tile && other.block instanceof PowerNode node &&
Boolf<Building> valid = other -> other != null && other.tile != tile && other.block instanceof PowerNode node &&
node.autolink &&
other.power.links.size < node.maxNodes &&
node.overlaps(other.x, other.y, tile, block, node.laserRange * tilesize) && other.team == team
@@ -37,9 +37,10 @@ public class ThermalGenerator extends PowerGenerator{
outputsLiquid = true;
hasLiquids = true;
}
emitLight = true;
super.init();
//proper light clipping
clipSize = Math.max(clipSize, 45f * size * 2f * 2f);
lightClipSize = Math.max(lightClipSize, 45f * size * 2f * 2f);
}
@Override
@@ -43,7 +43,7 @@ public class CoreBlock extends StorageBlock{
public @Load(value = "@-thruster1", fallback = "clear-effect") TextureRegion thruster1; //top right
public @Load(value = "@-thruster2", fallback = "clear-effect") TextureRegion thruster2; //bot left
public float thrusterLength = 14f/4f;
public float thrusterLength = 14f/4f, thrusterOffset = 0f;
public boolean isFirstTier;
/** If true, this core type requires a core zone to upgrade. */
public boolean requiresCoreZone;
@@ -69,8 +69,6 @@ public class CoreBlock extends StorageBlock{
priority = TargetPriority.core;
flags = EnumSet.of(BlockFlag.core);
unitCapModifier = 10;
loopSound = Sounds.respawning;
loopSoundVolume = 1f;
drawDisabled = false;
canOverdrive = false;
envEnabled |= Env.space;
@@ -92,6 +90,10 @@ public class CoreBlock extends StorageBlock{
if(!net.client()){
Unit unit = spawnType.create(tile.team());
//reset reload so that the player can't shoot immediately
for(var mount : unit.mounts){
mount.reload = mount.weapon.reload;
}
unit.set(core);
unit.rotation(90f);
unit.impulse(0f, 3f);
@@ -649,24 +651,23 @@ public class CoreBlock extends StorageBlock{
super.onProximityUpdate();
for(Building other : state.teams.cores(team)){
if(other.tile() != tile){
if(other.tile != tile){
this.items = other.items;
}
}
state.teams.registerCore(this);
storageCapacity = itemCapacity + proximity().sum(e -> owns(e) ? e.block.itemCapacity : 0);
storageCapacity = itemCapacity + proximity.sum(e -> owns(e) ? e.block.itemCapacity : 0);
proximity.each(this::owns, t -> {
t.items = items;
((StorageBuild)t).linkedCore = this;
});
for(Building other : state.teams.cores(team)){
if(other.tile() == tile) continue;
storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> owns(other, e) ? e.block.itemCapacity : 0);
if(other.tile == tile) continue;
storageCapacity += other.block.itemCapacity + other.proximity.sum(e -> owns(other, e) ? e.block.itemCapacity : 0);
}
//Team.sharded.core().items.set(Items.surgeAlloy, 12000)
if(!world.isGenerating()){
for(Item item : content.items()){
items.set(item, Math.min(items.get(item), storageCapacity));
@@ -142,15 +142,12 @@ public class Reconstructor extends UnitBlock{
public @Nullable Vec2 commandPos;
public @Nullable UnitCommand command;
boolean constructing;
public float fraction(){
return progress / constructTime;
}
@Override
public boolean shouldActiveSound(){
return shouldConsume();
}
@Override
public Vec2 getCommandPosition(){
return commandPos;
@@ -290,6 +287,8 @@ public class Reconstructor extends UnitBlock{
@Override
public void updateTile(){
//cache value to prevent repeated calls and multithreading issues
constructing = constructing();
boolean valid = false;
if(payload != null){
@@ -338,7 +337,7 @@ public class Reconstructor extends UnitBlock{
@Override
public boolean shouldConsume(){
return constructing() && enabled;
return constructing && enabled;
}
@Override
@@ -85,7 +85,7 @@ public class RepairTurret extends Block{
}
consumePowerCond(powerUse, (RepairPointBuild entity) -> entity.target != null);
updateClipRadius(repairRadius);
updateClipRadius(repairRadius + tilesize);
super.init();
}
@@ -142,7 +142,7 @@ public class UnitAssembler extends PayloadBlock{
@Override
public void init(){
updateClipRadius(areaSize * tilesize);
updateClipRadius((areaSize + 1) * tilesize);
consume(consPayload = new ConsumePayloadDynamic((UnitAssemblerBuild build) -> build.plan().requirements));
consume(consItem = new ConsumeItemDynamic((UnitAssemblerBuild build) -> build.plan().itemReq != null ? build.plan().itemReq : ItemStack.empty));
@@ -53,13 +53,13 @@ public class UnitAssemblerModule extends PayloadBlock{
@Override
public void drawPlanRegion(BuildPlan plan, Eachable<BuildPlan> list){
Draw.rect(region, plan.drawx(), plan.drawy());
Draw.rect(plan.rotation >= 2 ? sideRegion2 : sideRegion1, plan.drawx(), plan.drawy(), plan.rotation * 90);
drawSideRegion(plan.rotation >= 2 ? sideRegion2 : sideRegion1, plan.drawx(), plan.drawy(), plan.rotation);
Draw.rect(topRegion, plan.drawx(), plan.drawy());
}
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, sideRegion1, topRegion};
return new TextureRegion[]{region, topRegion};
}
public @Nullable UnitAssemblerBuild getLink(Team team, int x, int y, int rotation){
@@ -93,11 +93,11 @@ public class UnitAssemblerModule extends PayloadBlock{
//draw input conveyors
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation){
Draw.rect(inRegion, x, y, (i * 90) - 180);
drawSideRegion(inRegion, x, y, i - 2);
}
}
Draw.rect(rotation >= 2 ? sideRegion2 : sideRegion1, x, y, rotdeg());
drawSideRegion(rotation >= 2 ? sideRegion2 : sideRegion1, x, y, rotation);
Draw.z(Layer.blockOver);
payRotation = rotdeg();
@@ -142,11 +142,6 @@ public class UnitCargoLoader extends Block{
return unit == null;
}
@Override
public boolean shouldActiveSound(){
return shouldConsume() && warmup > 0.01f;
}
@Override
public void draw(){
Draw.rect(block.region, x, y);
@@ -236,11 +236,6 @@ public class UnitFactory extends UnitBlock{
return super.senseObject(sensor);
}
@Override
public boolean shouldActiveSound(){
return shouldConsume();
}
@Override
public double sense(LAccess sensor){
if(sensor == LAccess.progress) return Mathf.clamp(fraction());
+2 -1
View File
@@ -25,8 +25,9 @@ public class DrawFlame extends DrawBlock{
@Override
public void load(Block block){
block.emitLight = true;
top = Core.atlas.find(block.name + "-top");
block.clipSize = Math.max(block.clipSize, (lightRadius + lightSinMag) * 2f * block.size);
block.lightClipSize = Math.max(block.lightClipSize, (lightRadius + lightSinMag) * 2f * block.size);
}
@Override
@@ -18,6 +18,8 @@ public class DrawPlasma extends DrawFlame{
@Override
public void load(Block block){
block.emitLight = true;
regions = new TextureRegion[plasmas];
for(int i = 0; i < regions.length; i++){
regions[i] = Core.atlas.find(block.name + suffix + i);
+3 -1
View File
@@ -29,7 +29,9 @@ public enum BlockFlag{
launchPad,
unitCargoUnloadPoint,
unitAssembler,
hasFogRadius;
hasFogRadius,
steamVent,
blockRepair;
public final static BlockFlag[] all = values();
@@ -581,18 +581,14 @@ public class StatValues{
int count = 0;
for(Ability ability : abilities){
if(ability.display){
t.table(Styles.grayPanel, a -> {
a.add("[accent]" + ability.localized()).padBottom(4).center().top().expandX();
a.row();
a.left().top().defaults().left();
ability.addStats(a);
}).pad(5).margin(10).growX().top().uniformX();
ability.display(t);
if((++count) == 2){
count = 0;
t.row();
}
}
};
}
});
};
}