diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 267f34cd09..b6daafd228 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1884,6 +1884,7 @@ public class Blocks{ requirements(Category.distribution, with(Items.beryllium, 1)); health = 90; speed = 4f; + underBullets = true; researchCost = with(Items.beryllium, 5); }}; @@ -1892,6 +1893,7 @@ public class Blocks{ health = 140; speed = 4f; armored = true; + underBullets = true; researchCost = with(Items.beryllium, 300, Items.tungsten, 100); }}; @@ -1900,6 +1902,8 @@ public class Blocks{ health = 90; speed = 4f; regionRotated1 = 1; + solid = false; + underBullets = true; researchCost = with(Items.beryllium, 30); }}; @@ -1907,6 +1911,8 @@ public class Blocks{ requirements(Category.distribution, with(Items.graphite, 8, Items.beryllium, 8)); health = 90; speed = 4f; + solid = false; + underBullets = true; researchCostMultiplier = 1.5f; }}; @@ -1914,6 +1920,8 @@ public class Blocks{ requirements(Category.distribution, with(Items.beryllium, 20)); health = 90; speed = 4f; + buildCostMultiplier = 2f; + underBullets = true; researchCostMultiplier = 0.3f; }}; @@ -1921,6 +1929,8 @@ public class Blocks{ requirements(Category.distribution, with(Items.graphite, 20, Items.silicon, 20, Items.tungsten, 10)); health = 120; speed = 4f; + solid = false; + underBullets = true; regionRotated1 = 1; }}; @@ -1935,6 +1945,7 @@ public class Blocks{ hasPower = true; consumesPower = true; conductivePower = true; + underBullets = true; baseEfficiency = 1f; consumePower(1f / 60f); }}; @@ -1949,6 +1960,8 @@ public class Blocks{ consumesPower = true; conductivePower = true; baseEfficiency = 1f; + underBullets = true; + solid = false; consumePower(3f / 60f); }}; @@ -2084,6 +2097,7 @@ public class Blocks{ liquidPressure = 1.03f; health = 250; researchCostMultiplier = 3; + underBullets = true; }}; //TODO is this necessary? junctions are not good design @@ -2094,13 +2108,16 @@ public class Blocks{ health = 260; ((Conduit)reinforcedConduit).junctionReplacement = this; researchCostMultiplier = 1; + solid = false; + underBullets = true; }}; reinforcedBridgeConduit = new DirectionLiquidBridge("reinforced-bridge-conduit"){{ - requirements(Category.liquid, with(Items.graphite, 6, Items.beryllium, 10)); + requirements(Category.liquid, with(Items.graphite, 8, Items.beryllium, 20)); range = 4; hasPower = false; researchCostMultiplier = 1; + underBullets = true; ((Conduit)reinforcedConduit).rotBridgeReplacement = this; }}; @@ -2111,9 +2128,9 @@ public class Blocks{ newDrawing = true; liquidPadding = 3f/4f; researchCostMultiplier = 3; + underBullets = true; }}; - //TODO is there a need for a container if unloaders can unload 3x3s? reinforcedLiquidContainer = new LiquidRouter("reinforced-liquid-container"){{ requirements(Category.liquid, with(Items.tungsten, 10, Items.beryllium, 16)); liquidCapacity = 1000f; @@ -2121,6 +2138,7 @@ public class Blocks{ newDrawing = true; liquidPadding = 6f/4f; researchCostMultiplier = 4; + underBullets = true; }}; reinforcedLiquidTank = new LiquidRouter("reinforced-liquid-tank"){{ @@ -2129,6 +2147,7 @@ public class Blocks{ liquidCapacity = 2700f; newDrawing = true; liquidPadding = 2f; + underBullets = true; }}; //endregion @@ -4116,7 +4135,7 @@ public class Blocks{ requirements(Category.units, with(Items.silicon, 200, Items.beryllium, 250)); size = 3; configurable = false; - plans.add(new UnitPlan(UnitTypes.stell, 60f * 60f * 1f, with(Items.beryllium, 50f, Items.silicon, 70f))); + plans.add(new UnitPlan(UnitTypes.stell, 60f * 60f * 1f, with(Items.beryllium, 50f, Items.silicon, 60f))); researchCost = with(Items.beryllium, 200, Items.graphite, 80, Items.silicon, 80); regionSuffix = "-dark"; fogRadius = 3; @@ -4251,6 +4270,7 @@ public class Blocks{ canOverdrive = false; health = 800; researchCostMultiplier = 4f; + underBullets = true; }}; reinforcedPayloadRouter = new PayloadRouter("reinforced-payload-router"){{ @@ -4259,6 +4279,7 @@ public class Blocks{ health = 800; canOverdrive = false; researchCostMultiplier = 4f; + underBullets = true; }}; payloadMassDriver = new PayloadMassDriver("payload-mass-driver"){{ diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 877dd72bc0..3ab4334749 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -531,6 +531,10 @@ public class BulletType extends Content implements Cloneable{ } public @Nullable Bullet create(@Nullable Entityc owner, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl, Object data, @Nullable Mover mover){ + return create(owner, team, x, y, angle, damage, velocityScl, lifetimeScl, data, mover, -1f, -1f); + } + + public @Nullable Bullet create(@Nullable Entityc owner, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl, Object data, @Nullable Mover mover, float aimX, float aimY){ if(spawnUnit != null){ //don't spawn units clientside! if(!net.client()){ @@ -555,6 +559,7 @@ public class BulletType extends Content implements Cloneable{ bullet.owner = owner; bullet.team = team; bullet.time = 0f; + bullet.aimTile = world.tileWorld(aimX, aimY); bullet.initVel(angle, speed * velocityScl); if(backMove){ bullet.set(x - bullet.vel.x * Time.delta, y - bullet.vel.y * Time.delta); diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index ed6501348a..828137e91b 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -50,7 +50,7 @@ import static mindustry.Vars.*; @Component(base = true) abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, QuadTreeObject, Displayable, Senseable, Controllable, Sized{ //region vars and initialization - static final float timeToSleep = 60f * 1, timeToUncontrol = 60f * 6; + static final float timeToSleep = 60f * 1, recentDamageTime = 60f * 5f; static final ObjectSet tmpTiles = new ObjectSet<>(); static final Seq tempBuilds = new Seq<>(); static final BuildTeamChangeEvent teamChangeEvent = new BuildTeamChangeEvent(); @@ -91,6 +91,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, transient float healSuppressionTime = -1f; transient float lastHealTime = -120f * 10f; + private transient float lastDamageTime = -recentDamageTime; private transient float timeScale = 1f, timeScaleDuration; private transient float dumpAccum; @@ -406,6 +407,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, return lastHealTime + duration >= Time.time; } + public boolean wasRecentlyDamaged(){ + return lastDamageTime + recentDamageTime >= Time.time; + } + public Building nearby(int dx, int dy){ return world.build(tile.x + dx, tile.y + dy); } @@ -1781,6 +1786,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, if(dead()) return; float dm = state.rules.blockHealth(team); + lastDamageTime = Time.time; if(Mathf.zero(dm)){ damage = health + 1; diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index 4873abfba4..3fd70d2ec0 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -37,6 +37,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw @ReadOnly private float rotation; + transient @Nullable Tile aimTile; transient @Nullable Mover mover; transient boolean absorbed, hit; transient @Nullable Trail trail; @@ -173,7 +174,11 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw } } - if(build != null && isAdded() && build.collide(self()) && type.testCollision(self(), build) + if(build != null && isAdded() && + //should underBullet detection be disabled for piercing bullets? + //|| type.pierceBuilding + (!build.block.underBullets || (aimTile != null && aimTile.build == build)) + && build.collide(self()) && type.testCollision(self(), build) && !build.dead() && (type.collidesTeam || build.team != team) && !(type.pierceBuilding && hasCollided(build.id))){ boolean remove = false; diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index a73144914d..4c6de9b94d 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -402,7 +402,7 @@ public class Weapon implements Cloneable{ lifeScl = bullet.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, mount.aimX, mount.aimY) / bullet.range) : 1f, angle = angleOffset + shootAngle + Mathf.range(inaccuracy); - mount.bullet = bullet.create(unit, unit.team, bulletX, bulletY, angle, (1f - velocityRnd) + Mathf.random(velocityRnd), lifeScl, mover); + mount.bullet = bullet.create(unit, unit.team, bulletX, bulletY, angle, -1f, (1f - velocityRnd) + Mathf.random(velocityRnd), lifeScl, null, mover, mount.aimX, mount.aimY); if(!continuous){ shootSound.at(bulletX, bulletY, Mathf.random(soundPitchMin, soundPitchMax)); diff --git a/core/src/mindustry/type/weapons/RepairBeamWeapon.java b/core/src/mindustry/type/weapons/RepairBeamWeapon.java index 9f98374be0..1a8b559904 100644 --- a/core/src/mindustry/type/weapons/RepairBeamWeapon.java +++ b/core/src/mindustry/type/weapons/RepairBeamWeapon.java @@ -33,6 +33,7 @@ public class RepairBeamWeapon extends Weapon{ public float pulseRadius = 6f; public float pulseStroke = 2f; public float widthSinMag = 0f, widthSinScl = 4f; + public float recentDamageMultiplier = 0.1f; public TextureRegion laser, laserEnd, laserTop, laserTopEnd; @@ -150,7 +151,8 @@ public class RepairBeamWeapon extends Weapon{ } if(canShoot && mount.target instanceof Healthc u){ - u.heal(repairSpeed * heal.strength * Time.delta + fractionRepairSpeed * heal.strength * Time.delta * u.maxHealth() / 100f); + float baseAmount = repairSpeed * heal.strength * Time.delta + fractionRepairSpeed * heal.strength * Time.delta * u.maxHealth() / 100f; + u.heal((u instanceof Building b && b.wasRecentlyDamaged() ? recentDamageMultiplier : 1f) * baseAmount); } } diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 5b035bffb6..17ddff9dc7 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -90,6 +90,8 @@ public class Block extends UnlockableContent implements Senseable{ public boolean solidifes; /** if true, this counts as a non-solid block to this team. */ public boolean teamPassable; + /** if true, this block cannot be hit by bullets unless explicitly targeted. */ + public boolean underBullets; /** whether this is rotatable */ public boolean rotate; /** if rotate is true and this is false, the region won't rotate when drawing */ diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 1686383977..da823fe764 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -38,7 +38,7 @@ public class ConstructBlock extends Block{ super("build" + size); this.size = size; update = true; - health = 20; + health = 10; consumesTap = true; solidifes = true; inEditor = false; diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index d6d61654f9..41f86defc1 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -501,7 +501,8 @@ public class Turret extends ReloadTurret{ float lifeScl = type.scaleVelocity ? Mathf.clamp(Mathf.dst(bulletX, bulletY, targetPos.x, targetPos.y) / type.range, minRange / type.range, range() / type.range) : 1f; - handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, 1f + Mathf.range(velocityInaccuracy), lifeScl, mover), xOffset, yOffset, angleOffset); + //TODO aimX / aimY for multi shot turrets? + handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, -1f, 1f + Mathf.range(velocityInaccuracy), lifeScl, null, mover, targetPos.x, targetPos.y), xOffset, yOffset, angleOffset); (shootEffect == Fx.none ? type.shootEffect : shootEffect).at(bulletX, bulletY, rotation, type.hitColor); (smokeEffect == Fx.none ? type.smokeEffect : smokeEffect).at(bulletX, bulletY, rotation, type.hitColor); diff --git a/core/src/mindustry/world/blocks/payloads/PayloadRouter.java b/core/src/mindustry/world/blocks/payloads/PayloadRouter.java index b16b024ba0..9f6c671985 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadRouter.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadRouter.java @@ -98,7 +98,7 @@ public class PayloadRouter extends PayloadConveyor{ if(type == LAccess.config){ rotation = (int)p1; //when manually controlled, routers do not turn automatically for a while, same as turrets - controlTime = Building.timeToUncontrol; + controlTime = 60f * 6f; } }