Merge branch 'master' into ThePythonGuy3-patch-1

This commit is contained in:
Anuken
2020-12-23 10:51:56 -05:00
97 changed files with 329 additions and 141 deletions

View File

@@ -876,7 +876,7 @@ public class Blocks implements ContentList{
size = 4;
}};
thruster = new Wall("thruster"){{
thruster = new Thruster("thruster"){{
health = 55 * 16 * wallHealthMultiplier;
size = 4;
}};
@@ -989,9 +989,9 @@ public class Blocks implements ContentList{
}};
itemBridge = new BufferedItemBridge("bridge-conveyor"){{
requirements(Category.distribution, with(Items.lead, 4, Items.copper, 4));
requirements(Category.distribution, with(Items.lead, 6, Items.copper, 6));
range = 4;
speed = 70f;
speed = 74f;
bufferCapacity = 14;
}};
@@ -1265,7 +1265,7 @@ public class Blocks implements ContentList{
tier = 2;
drillTime = 600;
size = 2;
drawMineItem = true;
consumes.liquid(Liquids.water, 0.05f).boost();
}};
@@ -1274,7 +1274,7 @@ public class Blocks implements ContentList{
tier = 3;
drillTime = 400;
size = 2;
drawMineItem = true;
consumes.liquid(Liquids.water, 0.06f).boost();
}};
@@ -1763,7 +1763,7 @@ public class Blocks implements ContentList{
despawnEffect = Fx.instBomb;
trailSpacing = 20f;
damage = 1350;
tileDamageMultiplier = 0.3f;
buildingDamageMultiplier = 0.3f;
speed = brange;
hitShake = 6f;
ammoMultiplier = 1f;
@@ -1992,6 +1992,7 @@ public class Blocks implements ContentList{
powerSource = new PowerSource("power-source"){{
requirements(Category.power, BuildVisibility.sandboxOnly, with());
powerProduction = 10000f / 60f;
alwaysUnlocked = true;
}};

View File

@@ -465,6 +465,7 @@ public class Bullets implements ContentList{
speed = 4f;
knockback = 1.7f;
puddleSize = 8f;
orbSize = 4f;
drag = 0.001f;
ammoMultiplier = 0.4f;
statusDuration = 60f * 4f;
@@ -476,6 +477,7 @@ public class Bullets implements ContentList{
speed = 4f;
knockback = 1.3f;
puddleSize = 8f;
orbSize = 4f;
drag = 0.001f;
ammoMultiplier = 0.4f;
statusDuration = 60f * 4f;
@@ -487,6 +489,7 @@ public class Bullets implements ContentList{
speed = 4f;
knockback = 1.3f;
puddleSize = 8f;
orbSize = 4f;
damage = 4.75f;
drag = 0.001f;
ammoMultiplier = 0.4f;
@@ -498,6 +501,7 @@ public class Bullets implements ContentList{
speed = 4f;
knockback = 1.3f;
puddleSize = 8f;
orbSize = 4f;
drag = 0.001f;
ammoMultiplier = 0.4f;
statusDuration = 60f * 4f;

View File

@@ -182,7 +182,7 @@ public class UnitTypes implements ContentList{
lightningLength = 6;
lightningColor = Pal.surge;
//standard bullet damage is far too much for lightning
lightningDamage = 30;
lightningDamage = 20;
}};
}},
@@ -336,7 +336,7 @@ public class UnitTypes implements ContentList{
bullet = new LightningBulletType(){{
lightningColor = hitColor = Pal.heal;
damage = 15f;
damage = 12f;
lightningLength = 7;
lightningLengthRand = 7;
shootEffect = Fx.shootHeal;
@@ -1759,7 +1759,7 @@ public class UnitTypes implements ContentList{
lifetime = 60f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
tileDamageMultiplier = 0.01f;
buildingDamageMultiplier = 0.01f;
}};
}});
}};
@@ -1801,7 +1801,7 @@ public class UnitTypes implements ContentList{
lifetime = 60f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
tileDamageMultiplier = 0.01f;
buildingDamageMultiplier = 0.01f;
}};
}});
}};
@@ -1841,7 +1841,7 @@ public class UnitTypes implements ContentList{
lifetime = 70f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
tileDamageMultiplier = 0.01f;
buildingDamageMultiplier = 0.01f;
homingPower = 0.04f;
}};
}});

View File

@@ -351,7 +351,7 @@ public class Control implements ApplicationListener, Loadable{
if(tile != null){
tile.setBlock(content.block(plan.block), state.rules.waveTeam, plan.rotation);
if(plan.config != null && tile.build != null){
tile.build.configure(plan.config);
tile.build.configureAny(plan.config);
}
}
}

View File

@@ -258,13 +258,12 @@ public class Logic implements ApplicationListener{
state.rules.weather.removeAll(w -> w.weather == null);
for(WeatherEntry entry : state.rules.weather){
if(entry.weather == null) continue;
//update cooldown
entry.cooldown -= Time.delta;
//create new event when not active
if(entry.cooldown < 0 && !entry.weather.isActive()){
float duration = Mathf.random(entry.minDuration, entry.maxDuration);
if((entry.cooldown < 0 || entry.always) && !entry.weather.isActive()){
float duration = entry.always ? Float.POSITIVE_INFINITY : Mathf.random(entry.minDuration, entry.maxDuration);
entry.cooldown = duration + Mathf.random(entry.minFrequency, entry.maxFrequency);
Tmp.v1.setToRandomDirection();
Call.createWeather(entry.weather, entry.intensity, duration, Tmp.v1.x, Tmp.v1.y);

View File

@@ -700,6 +700,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
if(core != 0) return core;
int synth = Boolean.compare(b1.synthetic(), b2.synthetic());
if(synth != 0) return synth;
int editorVis = Boolean.compare(b1.buildVisibility == BuildVisibility.editorOnly, b2.buildVisibility == BuildVisibility.editorOnly);
if(editorVis != 0) return editorVis;
int ore = Boolean.compare(b1 instanceof OverlayFloor, b2 instanceof OverlayFloor);
if(ore != 0) return ore;
return Integer.compare(b1.id, b2.id);

View File

@@ -126,6 +126,8 @@ public class Damage{
boolean collide = tile != null && collidedBlocks.add(tile.pos());
if(hitter.damage > 0){
float health = !collide ? 0 : tile.health;
if(collide && tile.team != team && tile.collide(hitter)){
tile.collision(hitter);
hitter.type.hit(hitter, tile.x, tile.y);
@@ -133,7 +135,7 @@ public class Damage{
//try to heal the tile
if(collide && hitter.type.testCollision(hitter, tile)){
hitter.type.hitTile(hitter, tile, tile.health, false);
hitter.type.hitTile(hitter, tile, health, false);
}
}
};
@@ -389,9 +391,9 @@ public class Damage{
if(scaledDamage <= 0 || tile == null) continue;
//apply damage to entity if needed
if(tile.build != null && tile.team() != team){
int health = (int)tile.build.health();
if(tile.build.health() > 0){
if(tile.build != null && tile.build.team != team){
int health = (int)(tile.build.health / (tile.block().size * tile.block().size));
if(tile.build.health > 0){
tile.build.damage(scaledDamage);
scaledDamage -= health;

View File

@@ -41,7 +41,7 @@ public abstract class BulletType extends Content{
/** Multiplied by turret reload speed to get final shoot speed. */
public float reloadMultiplier = 1f;
/** Multiplier of how much base damage is done to tiles. */
public float tileDamageMultiplier = 1f;
public float buildingDamageMultiplier = 1f;
/** Recoil from shooter entities. */
public float recoil;
/** Whether to kill the shooter when this is shot. For suicide bombers. */

View File

@@ -15,6 +15,7 @@ import static mindustry.Vars.*;
public class LiquidBulletType extends BulletType{
public Liquid liquid;
public float puddleSize = 6f;
public float orbSize = 3f;
public LiquidBulletType(@Nullable Liquid liquid){
super(3.5f, 0);
@@ -64,7 +65,7 @@ public class LiquidBulletType extends BulletType{
public void draw(Bullet b){
Draw.color(liquid.color, Color.white, b.fout() / 100f);
Fill.circle(b.x, b.y, puddleSize / 2);
Fill.circle(b.x, b.y, orbSize);
}
@Override

View File

@@ -6,12 +6,6 @@ import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
//TODO this class is bad for multiple reasons, remove/replace it.
//- effects unreliable
//- not really hitscan but works like it
//- buggy trails
//- looks bad
//- generally unreliable
public class RailBulletType extends BulletType{
public Effect pierceEffect = Fx.hitBulletSmall, updateEffect = Fx.none;
/** Multiplier of damage decreased per health pierced. */
@@ -29,6 +23,7 @@ public class RailBulletType extends BulletType{
despawnEffect = Fx.none;
collides = false;
lifetime = 1f;
speed = 0.01f;
}
@Override
@@ -37,7 +32,7 @@ public class RailBulletType extends BulletType{
}
void handle(Bullet b, Posc pos, float initialHealth){
float sub = initialHealth*pierceDamageFactor;
float sub = Math.max(initialHealth*pierceDamageFactor, 0);
if(b.damage <= 0){
b.fdata = Math.min(b.fdata, b.dst(pos));

View File

@@ -33,7 +33,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
@Import Team team;
@SyncLocal Queue<BuildPlan> plans = new Queue<>(1);
@SyncLocal transient boolean updateBuilding = true;
@SyncLocal boolean updateBuilding = true;
public boolean canBuild(){
return type.buildSpeed > 0;
@@ -77,7 +77,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
Tile tile = world.tile(current.x, current.y);
if(!(tile.block() instanceof ConstructBlock)){
if(!(tile.build instanceof ConstructBuild cb)){
if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){
boolean hasAll = infinite || current.isRotation(team) || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item));
@@ -92,7 +92,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
plans.removeFirst();
return;
}
}else if(tile.team() != team && tile.team() != Team.derelict){
}else if((tile.team() != team && tile.team() != Team.derelict) || (!current.breaking && cb.cblock != current.block)){
plans.removeFirst();
return;
}

View File

@@ -1165,7 +1165,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Handle a bullet collision.
* @return whether the bullet should be removed. */
public boolean collision(Bullet other){
damage(other.damage() * other.type().tileDamageMultiplier);
damage(other.damage() * other.type().buildingDamageMultiplier);
return true;
}

View File

@@ -51,8 +51,8 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
}
void moveAt(Vec2 vector, float acceleration){
Vec2 t = tmp1.set(vector).scl(floorSpeedMultiplier()); //target vector
tmp2.set(t).sub(vel).limit(acceleration * vector.len() * Time.delta); //delta vector
Vec2 t = tmp1.set(vector); //target vector
tmp2.set(t).sub(vel).limit(acceleration * vector.len() * Time.delta * floorSpeedMultiplier()); //delta vector
vel.add(tmp2);
}

View File

@@ -51,11 +51,7 @@ abstract class HealthComp implements Entityc, Posc{
/** Damage and pierce armor. */
void damagePierce(float amount, boolean withEffect){
if(this instanceof Shieldc){
damage(amount + ((Shieldc)this).armor(), withEffect);
}else{
damage(amount, withEffect);
}
damage(amount, withEffect);
}
/** Damage and pierce armor. */

View File

@@ -14,7 +14,7 @@ abstract class ShieldComp implements Healthc, Posc{
/** Absorbs health damage. */
float shield;
/** Absorbs percentage of damage. */
/** Substracts an amount from damage. */
float armor;
/** Shield opacity. */
transient float shieldAlpha = 0f;
@@ -26,8 +26,22 @@ abstract class ShieldComp implements Healthc, Posc{
amount = Math.max(amount - armor, minArmorDamage * amount);
amount /= healthMultiplier;
hitTime = 1f;
rawDamage(amount);
}
@Replace
@Override
public void damagePierce(float amount, boolean withEffect){
float pre = hitTime;
rawDamage(amount);
if(!withEffect){
hitTime = pre;
}
}
private void rawDamage(float amount){
boolean hadShields = shield > 0.0001f;
if(hadShields){

View File

@@ -139,7 +139,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
//flip weapon shoot side for alternating weapons at half reload
if(weapon.otherSide != -1 && weapon.alternate && mount.side == weapon.flipSprite &&
mount.reload + Time.delta > weapon.reload/2f && mount.reload <= weapon.reload/2f){
mount.reload + Time.delta * reloadMultiplier > weapon.reload/2f && mount.reload <= weapon.reload/2f){
mounts[weapon.otherSide].side = !mounts[weapon.otherSide].side;
mount.side = !mount.side;
}

View File

@@ -154,6 +154,7 @@ public class DesktopInput extends InputHandler{
}
drawRequest(lineRequests.get(i));
}
lineRequests.each(this::drawOverRequest);
}else if(isPlacing()){
if(block.rotate){
drawArrow(block, cursorX, cursorY, rotation);
@@ -603,7 +604,6 @@ public class DesktopInput extends InputHandler{
protected void updateMovement(Unit unit){
boolean omni = unit.type.omniMovement;
boolean ground = unit.isGrounded();
float speed = unit.realSpeed();
float xa = Core.input.axis(Binding.move_x);

View File

@@ -48,7 +48,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Maximum line length. */
final static int maxLength = 100;
final static Rect r1 = new Rect(), r2 = new Rect();
final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
public final OverlayFragment frag = new OverlayFragment();
@@ -1144,7 +1143,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
diagonal = !diagonal;
}
if(block instanceof PowerNode){
if(block != null && block.swapDiagonalPlacement){
diagonal = !diagonal;
}
@@ -1161,39 +1160,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
points = Placement.normalizeLine(startX, startY, endX, endY);
}
if(block instanceof PowerNode node){
var base = tmpPoints2;
var result = tmpPoints.clear();
base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation, false));
boolean addedLast = false;
outer:
for(int i = 0; i < base.size;){
var point = base.get(i);
result.add(point);
if(i == base.size - 1) addedLast = true;
//find the furthest node that overlaps this one
for(int j = base.size - 1; j > i; j--){
var other = base.get(j);
boolean over = node.overlaps(world.tile(point.x, point.y), world.tile(other.x, other.y));
if(over){
//add node to list and start searching for node that overlaps the next one
i = j;
continue outer;
}
}
//if it got here, that means nothing was found. try to proceed to the next node anyway
i ++;
}
if(!addedLast) result.add(base.peek());
points.clear();
points.addAll(result);
if(block != null){
block.changePlacementPath(points, rotation);
}
float angle = Angles.angle(startX, startY, endX, endY);

View File

@@ -1,6 +1,7 @@
package mindustry.input;
import arc.*;
import arc.func.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
@@ -11,6 +12,7 @@ import mindustry.world.blocks.distribution.*;
import static mindustry.Vars.*;
public class Placement{
private final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
private static final NormalizeResult result = new NormalizeResult();
private static final NormalizeDrawResult drawResult = new NormalizeDrawResult();
private static Bresenham2 bres = new Bresenham2();
@@ -68,6 +70,42 @@ public class Placement{
return points;
}
/** Calculates optimal node placement for nodes with spacing. Used for bridges and power nodes. */
public static void calculateNodes(Seq<Point2> points, Block block, int rotation, Boolf2<Point2, Point2> overlapper){
var base = tmpPoints2;
var result = tmpPoints.clear();
base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation, false));
boolean addedLast = false;
outer:
for(int i = 0; i < base.size;){
var point = base.get(i);
result.add(point);
if(i == base.size - 1) addedLast = true;
//find the furthest node that overlaps this one
for(int j = base.size - 1; j > i; j--){
var other = base.get(j);
boolean over = overlapper.get(point, other);
if(over){
//add node to list and start searching for node that overlaps the next one
i = j;
continue outer;
}
}
//if it got here, that means nothing was found. try to proceed to the next node anyway
i ++;
}
if(!addedLast) result.add(base.peek());
points.clear();
points.addAll(result);
}
private static float tileHeuristic(Tile tile, Tile other){
Block block = control.input.block;

View File

@@ -52,7 +52,7 @@ public class StatusEffect extends MappableContent{
if(damage > 0){
unit.damageContinuousPierce(damage);
}else if(damage < 0){ //heal unit
unit.heal(damage * Time.delta);
unit.heal(-1f * damage * Time.delta);
}
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){

View File

@@ -61,12 +61,17 @@ public class Weather extends UnlockableContent{
return entity;
}
@Nullable
public WeatherState instance(){
return Groups.weather.find(w -> w.weather() == this);
}
public boolean isActive(){
return Groups.weather.find(w -> w.weather() == this) != null;
return instance() != null;
}
public void remove(){
Entityc e = Groups.weather.find(w -> w.weather() == this);
var e = instance();
if(e != null) e.remove();
}
@@ -259,6 +264,8 @@ public class Weather extends UnlockableContent{
public float cooldown;
/** Intensity of the weather produced. */
public float intensity = 1f;
/** If true, this weather is always active. */
public boolean always = false;
/** Creates a weather entry with some approximate weather values. */
public WeatherEntry(Weather weather){

View File

@@ -284,19 +284,23 @@ public class CustomRulesDialog extends BaseDialog{
f.defaults().padRight(4).left();
f.add("@rules.weather.duration");
field(f, entry.minDuration / toMinutes, v -> entry.minDuration = v * toMinutes);
field(f, entry.minDuration / toMinutes, v -> entry.minDuration = v * toMinutes).disabled(v -> entry.always);
f.add("@waves.to");
field(f, entry.maxDuration / toMinutes, v -> entry.maxDuration = v * toMinutes);
field(f, entry.maxDuration / toMinutes, v -> entry.maxDuration = v * toMinutes).disabled(v -> entry.always);
f.add("@unit.minutes");
f.row();
f.add("@rules.weather.frequency");
field(f, entry.minFrequency / toMinutes, v -> entry.minFrequency = v * toMinutes);
field(f, entry.minFrequency / toMinutes, v -> entry.minFrequency = v * toMinutes).disabled(v -> entry.always);
f.add("@waves.to");
field(f, entry.maxFrequency / toMinutes, v -> entry.maxFrequency = v * toMinutes);
field(f, entry.maxFrequency / toMinutes, v -> entry.maxFrequency = v * toMinutes).disabled(v -> entry.always);
f.add("@unit.minutes");
f.row();
f.check("@rules.weather.always", val -> entry.always = val).checked(cc -> entry.always).padBottom(4);
//intensity can't currently be customized
}).grow().left().pad(6).top();
@@ -314,8 +318,8 @@ public class CustomRulesDialog extends BaseDialog{
dialog.addCloseButton();
dialog.buttons.button("@add", Icon.add, () -> {
BaseDialog addd = new BaseDialog("@add");
addd.cont.pane(t -> {
BaseDialog add = new BaseDialog("@add");
add.cont.pane(t -> {
t.background(Tex.button);
int i = 0;
for(Weather weather : content.<Weather>getBy(ContentType.weather)){
@@ -324,13 +328,13 @@ public class CustomRulesDialog extends BaseDialog{
rules.weather.add(new WeatherEntry(weather));
rebuild[0].run();
addd.hide();
add.hide();
}).size(140f, 50f);
if(++i % 2 == 0) t.row();
}
});
addd.addCloseButton();
addd.show();
add.addCloseButton();
add.show();
}).width(170f);
//reset cooldown to random number

View File

@@ -67,10 +67,15 @@ public class HostDialog extends BaseDialog{
player.admin(true);
if(steam){
Core.app.post(() -> Core.settings.getBoolOnce("steampublic2", () -> {
Core.app.post(() -> Core.settings.getBoolOnce("steampublic3", () -> {
ui.showCustomConfirm("@setting.publichost.name", "@public.confirm", "@yes", "@no", () -> {
Core.settings.put("publichost", true);
platform.updateLobby();
ui.showCustomConfirm("@setting.publichost.name", "@public.confirm.really", "@no", "@yes", () -> {
Core.settings.put("publichost", true);
platform.updateLobby();
}, () -> {
Core.settings.put("publichost", false);
platform.updateLobby();
});
}, () -> {
Core.settings.put("publichost", false);
platform.updateLobby();

View File

@@ -399,6 +399,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
void setup(){
zoom = planets.zoom = 1f;
selectAlpha = 1f;
ui.minimapfrag.hide();
clearChildren();

View File

@@ -32,9 +32,9 @@ import static mindustry.Vars.net;
import static mindustry.Vars.*;
public class SettingsMenuDialog extends SettingsDialog{
private SettingsTable graphics;
private SettingsTable game;
private SettingsTable sound;
public SettingsTable graphics;
public SettingsTable game;
public SettingsTable sound;
private Table prefs;
private Table menu;

View File

@@ -110,6 +110,10 @@ public class MinimapFragment extends Fragment{
return shown;
}
public void hide(){
shown = false;
}
public void toggle(){
float size = baseSize * zoom * world.width();
float ratio = (float)renderer.minimap.getTexture().height / renderer.minimap.getTexture().width;

View File

@@ -143,6 +143,8 @@ public class Block extends UnlockableContent{
public boolean sync;
/** Whether this block uses conveyor-type placement mode. */
public boolean conveyorPlacement;
/** Whether to swap the diagonal placement modes. */
public boolean swapDiagonalPlacement;
/**
* The color of this block when displayed on the minimap or map preview.
* Do not set manually! This is overridden when loading for most blocks.
@@ -386,6 +388,11 @@ public class Block extends UnlockableContent{
return this;
}
/** Mutates the given list of points used during line placement. */
public void changePlacementPath(Seq<Point2> points, int rotation){
}
public Object nextConfig(){
if(saveConfig && lastConfig != null){
return lastConfig;

View File

@@ -50,37 +50,48 @@ public class Accelerator extends Block{
}
public class AcceleratorBuild extends Building{
public float heat, statusLerp;
@Override
public void updateTile(){
super.updateTile();
heat = Mathf.lerpDelta(heat, consValid() ? 1f : 0f, 0.05f);
statusLerp = Mathf.lerpDelta(statusLerp, power.status, 0.05f);
}
@Override
public void draw(){
super.draw();
for(int l = 0; l < 4; l++){
float length = 7f + l * 5f;
Draw.color(team.color, Pal.darkMetal, Mathf.absin(Time.time + l*50f, 10f, 1f));
Draw.color(Tmp.c1.set(Pal.darkMetal).lerp(team.color, statusLerp), Pal.darkMetal, Mathf.absin(Time.time + l*50f, 10f, 1f));
for(int i = 0; i < 4; i++){
float rot = i*90f + 45f;
Draw.rect(arrowRegion, x + Angles.trnsx(rot, length), y + Angles.trnsy(rot, length), rot + 180f);
}
}
if(heat < 0.0001f) return;
float rad = size * tilesize / 2f * 0.74f;
float scl = 2f;
Draw.z(Layer.bullet - 0.0001f);
Lines.stroke(1.75f, Pal.accent);
Lines.stroke(1.75f * heat, Pal.accent);
Lines.square(x, y, rad * 1.22f, 45f);
Lines.stroke(3f, Pal.accent);
Lines.stroke(3f * heat, Pal.accent);
Lines.square(x, y, rad, Time.time / scl);
Lines.square(x, y, rad, -Time.time / scl);
Draw.color(team.color);
Draw.alpha(Mathf.clamp(heat * 3f));
for(int i = 0; i < 4; i++){
float rot = i*90f + 45f + (-Time.time /3f)%360f;
float length = 26f;
float length = 26f * heat;
Draw.rect(arrowRegion, x + Angles.trnsx(rot, length), y + Angles.trnsy(rot, length), rot + 180f);
}

View File

@@ -0,0 +1,37 @@
package mindustry.world.blocks.defense;
import arc.graphics.g2d.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.units.*;
public class Thruster extends Wall{
public @Load("@-top") TextureRegion topRegion;
public Thruster(String name){
super(name);
rotate = true;
quickRotate = false;
}
@Override
public void drawRequestRegion(BuildPlan req, Eachable<BuildPlan> list){
Draw.rect(region, req.drawx(), req.drawy());
Draw.rect(topRegion, req.drawx(), req.drawy(), req.rotation * 90);
}
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, topRegion};
}
public class ThrusterBuild extends WallBuild{
@Override
public void draw(){
super.draw();
Draw.rect(topRegion, x, y, rotdeg());
}
}
}

View File

@@ -62,7 +62,7 @@ public class PointDefenseTurret extends ReloadTurret{
//retarget
if(timer(timerTarget, retargetTime)){
target = Groups.bullet.intersect(x - range, y - range, range*2, range*2).min(b -> b.team == team || !b.type().hittable ? Float.MAX_VALUE : b.dst2(this));
target = Groups.bullet.intersect(x - range, y - range, range*2, range*2).min(b -> b.team != team && b.type().hittable, b -> b.dst2(this));
}
//pooled bullets

View File

@@ -118,7 +118,7 @@ public class TractorBeamTurret extends BaseTurret{
}
any = true;
target.impulseNet(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * efficiency() * timeScale));
target.impulseNet(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * edelta() * timeScale));
}
}else{
strength = Mathf.lerpDelta(strength, 0, 0.1f);

View File

@@ -113,6 +113,7 @@ public class Turret extends ReloadTurret{
stats.add(Stat.reload, 60f / reloadTime * (alternate ? 1 : shots), StatUnit.none);
stats.add(Stat.targetsAir, targetAir);
stats.add(Stat.targetsGround, targetGround);
if(ammoPerShot != 1) stats.add(Stat.ammoUse, ammoPerShot, StatUnit.perShot);
}
@Override

View File

@@ -13,6 +13,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.meta.*;
@@ -152,6 +153,11 @@ public class ItemBridge extends Block{
lastPlan = plan;
}
@Override
public void changePlacementPath(Seq<Point2> points, int rotation){
Placement.calculateNodes(points, this, rotation, (point, other) -> Math.max(Math.abs(point.x - other.x), Math.abs(point.y - other.y)) <= range);
}
public class ItemBridgeBuild extends Building{
public int link = -1;
public IntSet incoming = new IntSet();

View File

@@ -29,7 +29,7 @@ public class StackConveyor extends Block implements Autotiler{
public float speed = 0f;
public boolean splitOut = true;
/** (minimum) amount of loading docks needed to fill a line */
/** (minimum) amount of loading docks needed to fill a line. */
public float recharge = 2f;
public Effect loadEffect = Fx.plasticburn;
public Effect unloadEffect = Fx.plasticburn;
@@ -46,7 +46,6 @@ public class StackConveyor extends Block implements Autotiler{
ambientSound = Sounds.conveyor;
ambientSoundVolume = 0.004f;
unloadable = false;
}
@Override
@@ -269,6 +268,11 @@ public class StackConveyor extends Block implements Autotiler{
}
}
@Override
public void itemTaken(Item item){
if(items.empty()) poofOut();
}
@Override
public boolean acceptItem(Building source, Item item){
if(this == source) return true; // player threw items

View File

@@ -37,6 +37,11 @@ public class BlockForge extends PayloadAcceptor{
consumes.add(new ConsumeItemDynamic((BlockForgeBuild e) -> e.recipe != null ? e.recipe.requirements : ItemStack.empty));
}
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, outRegion};
}
@Override
public void setBars(){
super.setBars();

View File

@@ -31,6 +31,11 @@ public class BlockLoader extends PayloadAcceptor{
rotate = true;
}
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, inRegion, outRegion, topRegion};
}
@Override
public boolean outputsItems(){
return false;
@@ -72,7 +77,7 @@ public class BlockLoader extends PayloadAcceptor{
//draw input
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation){
Draw.rect(inRegion, x, y, i * 90);
Draw.rect(inRegion, x, y, (i * 90) - 180);
}
}

View File

@@ -194,6 +194,7 @@ public class LogicBlock extends Block{
public LExecutor executor = new LExecutor();
public float accumulator = 0;
public Seq<LogicLink> links = new Seq<>();
public boolean checkedDuplicates = false;
public void readCompressed(byte[] data, boolean relative){
DataInputStream stream = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data)));
@@ -362,6 +363,21 @@ public class LogicBlock extends Block{
public void updateTile(){
executor.team = team;
if(!checkedDuplicates){
checkedDuplicates = true;
var removal = new IntSet();
var removeLinks = new Seq<LogicLink>();
for(var link : links){
var build = world.build(link.x, link.y);
if(build != null){
if(!removal.add(build.id)){
removeLinks.add(link);
}
}
}
links.removeAll(removeLinks);
}
//check for previously invalid links to add after configuration
boolean changed = false;
@@ -371,7 +387,7 @@ public class LogicBlock extends Block{
if(!l.active) continue;
boolean valid = validLink(world.build(l.x, l.y));
if(valid != l.valid ){
if(valid != l.valid){
changed = true;
l.valid = valid;
if(valid){

View File

@@ -92,11 +92,6 @@ public class ItemLiquidGenerator extends PowerGenerator{
return generateTime > 0;
}
@Override
public float ambientVolume(){
return Mathf.clamp(productionEfficiency);
}
@Override
public void updateTile(){
//Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.

View File

@@ -1,6 +1,7 @@
package mindustry.world.blocks.power;
import arc.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
@@ -50,6 +51,11 @@ public class PowerGenerator extends PowerDistributor{
/** The efficiency of the producer. An efficiency of 1.0 means 100% */
public float productionEfficiency = 0.0f;
@Override
public float ambientVolume(){
return Mathf.clamp(productionEfficiency);
}
@Override
public float getPowerProduction(){
return powerProduction * productionEfficiency;

View File

@@ -14,6 +14,7 @@ import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.meta.*;
@@ -25,7 +26,8 @@ public class PowerNode extends PowerBlock{
protected static boolean returnValue = false;
protected static BuildPlan otherReq;
protected final ObjectSet<PowerGraph> graphs = new ObjectSet<>();
protected final static ObjectSet<PowerGraph> graphs = new ObjectSet<>();
protected final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
public @Load("laser") TextureRegion laser;
public @Load("laser-end") TextureRegion laserEnd;
@@ -40,6 +42,7 @@ public class PowerNode extends PowerBlock{
consumesPower = false;
outputsPower = false;
canOverdrive = false;
swapDiagonalPlacement = true;
config(Integer.class, (entity, value) -> {
PowerModule power = entity.power;
@@ -149,17 +152,20 @@ public class PowerNode extends PowerBlock{
Draw.reset();
}
protected void setupColor(float satisfaction){
float fract = 1f - satisfaction;
@Override
public void changePlacementPath(Seq<Point2> points, int rotation){
Placement.calculateNodes(points, this, rotation, (point, other) -> overlaps(world.tile(point.x, point.y), world.tile(other.x, other.y)));
}
Draw.color(laserColor1, laserColor2, fract * 0.86f + Mathf.absin(3f, 0.1f));
protected void setupColor(float satisfaction){
Draw.color(laserColor1, laserColor2, (1f - satisfaction) * 0.86f + Mathf.absin(3f, 0.1f));
Draw.alpha(renderer == null ? 0.5f : renderer.laserOpacity);
}
protected void drawLaser(Team team, float x1, float y1, float x2, float y2, int size1, int size2){
float angle1 = Angles.angle(x1, y1, x2, y2);
float vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1);
float len1 = size1 * tilesize / 2f - 1.5f, len2 = size2 * tilesize / 2f - 1.5f;
float angle1 = Angles.angle(x1, y1, x2, y2),
vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1),
len1 = size1 * tilesize / 2f - 1.5f, len2 = size2 * tilesize / 2f - 1.5f;
Drawf.laser(team, laser, laserEnd, x1 + vx*len1, y1 + vy*len1, x2 - vx*len2, y2 - vy*len2, 0.25f);
}

View File

@@ -42,7 +42,7 @@ public class Drill extends Block{
protected int returnCount;
/** Whether to draw the item this drill is mining. */
public boolean drawMineItem = false;
public boolean drawMineItem = true;
/** Effect played when an item is produced. This is colored. */
public Effect drillEffect = Fx.mine;
/** Speed the drill bit rotates at. */
@@ -57,6 +57,7 @@ public class Drill extends Block{
public @Load("@-rim") TextureRegion rimRegion;
public @Load("@-rotator") TextureRegion rotatorRegion;
public @Load("@-top") TextureRegion topRegion;
public @Load(value = "@-item", fallback = "drill-item-@size") TextureRegion itemRegion;
public Drill(String name){
super(name);
@@ -76,11 +77,11 @@ public class Drill extends Block{
Tile tile = req.tile();
if(tile == null) return;
countOre(req.tile());
if(returnItem == null) return;
countOre(tile);
if(returnItem == null || !drawMineItem) return;
Draw.color(returnItem.color);
Draw.rect("drill-top", req.drawx(), req.drawy());
Draw.rect(itemRegion, req.drawx(), req.drawy());
Draw.color();
}
@@ -124,6 +125,12 @@ public class Drill extends Block{
Draw.rect(returnItem.icon(Cicon.small), dx, dy - 1);
Draw.reset();
Draw.rect(returnItem.icon(Cicon.small), dx, dy);
if(drawMineItem){
Draw.color(returnItem.color);
Draw.rect(itemRegion, tile.worldx() + offset, tile.worldy() + offset);
Draw.color();
}
}else{
Tile to = tile.getLinkedTilesAs(this, tempTiles).find(t -> t.drop() != null && t.drop().hardness > tier);
Item item = to == null ? null : to.drop();
@@ -304,7 +311,7 @@ public class Drill extends Block{
if(dominantItem != null && drawMineItem){
Draw.color(dominantItem.color);
Draw.rect("drill-top", x, y);
Draw.rect(itemRegion, x, y);
Draw.color();
}
}

View File

@@ -56,7 +56,7 @@ public class SolidPump extends Pump{
stats.remove(Stat.output);
stats.add(Stat.output, result, 60f * pumpAmount, true);
if(attribute != null){
stats.add(baseEfficiency > 0.0001f ? Stat.affinities : Stat.tiles, attribute);
stats.add(baseEfficiency > 0.0001f ? Stat.affinities : Stat.tiles, attribute, floating, 1f, baseEfficiency <= 0.001f);
}
}

View File

@@ -4,6 +4,8 @@ import mindustry.world.blocks.power.*;
public class PowerSource extends PowerNode{
public float powerProduction = 10000f;
public PowerSource(String name){
super(name);
maxNodes = 100;
@@ -14,7 +16,7 @@ public class PowerSource extends PowerNode{
public class PowerSourceBuild extends PowerNodeBuild{
@Override
public float getPowerProduction(){
return enabled ? 10000f : 0f;
return enabled ? powerProduction : 0f;
}
}

View File

@@ -386,6 +386,13 @@ public class CoreBlock extends StorageBlock{
}else{
super.handleItem(source, item);
}
}else if(incinerate()){
if(items.get(item) >= storageCapacity){
//create item incineration effect at random intervals
if(!noEffect){
incinerateEffect(this, source);
}
}
}
}
}

View File

@@ -39,7 +39,7 @@ public class Reconstructor extends UnitBlock{
@Override
public TextureRegion[] icons(){
return new TextureRegion[]{region, outRegion, topRegion};
return new TextureRegion[]{region, inRegion, outRegion, topRegion};
}
@Override
@@ -129,7 +129,7 @@ public class Reconstructor extends UnitBlock{
//draw input
for(int i = 0; i < 4; i++){
if(blends(i) && i != rotation){
Draw.rect(inRegion, x, y, i * 90);
Draw.rect(inRegion, x, y, (i * 90) - 180);
}
}

View File

@@ -70,6 +70,7 @@ public enum Stat{
targetsGround(StatCat.function),
damage(StatCat.function),
ammo(StatCat.function),
ammoUse(StatCat.function),
shieldHealth(StatCat.function),
cooldownTime(StatCat.function),

View File

@@ -20,6 +20,7 @@ public enum StatUnit{
minutes,
perSecond,
perMinute,
perShot,
timesSpeed(false),
percent(false),
shieldHealth,

View File

@@ -55,22 +55,22 @@ public class Stats{
}
public void add(Stat stat, Attribute attr){
add(stat, attr, false, 1f);
add(stat, attr, false, 1f, false);
}
public void add(Stat stat, Attribute attr, float scale){
add(stat, attr, false, scale);
add(stat, attr, false, scale, false);
}
public void add(Stat stat, Attribute attr, boolean floating){
add(stat, attr, floating, 1f);
add(stat, attr, floating, 1f, false);
}
public void add(Stat stat, Attribute attr, boolean floating, float scale){
public void add(Stat stat, Attribute attr, boolean floating, float scale, boolean startZero){
for(var block : Vars.content.blocks()
.select(block -> block instanceof Floor f && f.attributes.get(attr) != 0 && !(f.isLiquid && !floating))
.<Floor>as().with(s -> s.sort(f -> f.attributes.get(attr)))){
add(stat, new FloorEfficiencyValue(block, block.attributes.get(attr) * scale));
add(stat, new FloorEfficiencyValue(block, block.attributes.get(attr) * scale, startZero));
}
}

View File

@@ -46,6 +46,10 @@ public class AmmoListValue<T extends UnlockableContent> implements StatValue{
bt.add(Core.bundle.format("bullet.damage", type.damage));
}
if(type.buildingDamageMultiplier != 1){
sep(bt, Core.bundle.format("bullet.buildingdamage", type.buildingDamageMultiplier * 100));
}
if(type.splashDamage > 0){
sep(bt, Core.bundle.format("bullet.splashdamage", (int)type.splashDamage, Strings.fixed(type.splashDamageRadius / tilesize, 1)));
}

View File

@@ -10,16 +10,18 @@ import mindustry.world.meta.*;
public class FloorEfficiencyValue implements StatValue{
private final Floor floor;
private final float multiplier;
private final boolean startZero;
public FloorEfficiencyValue(Floor floor, float multiplier){
public FloorEfficiencyValue(Floor floor, float multiplier, boolean startZero){
this.floor = floor;
this.multiplier = multiplier;
this.startZero = startZero;
}
@Override
public void display(Table table){
table.stack(new Image(floor.icon(Cicon.medium)).setScaling(Scaling.fit), new Table(t -> {
t.top().right().add((multiplier < 0 ? "[scarlet]" : "[accent]+") + (int)((multiplier) * 100) + "%").style(Styles.outlineLabel);
t.top().right().add((multiplier < 0 ? "[scarlet]" : startZero ? "[accent]" : "[accent]+") + (int)((multiplier) * 100) + "%").style(Styles.outlineLabel);
}));
}
}