diff --git a/README.md b/README.md index 8c4a62083c..882d0b15ae 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![Logo](core/assets-raw/sprites/ui/logo.png) [![Build Status](https://travis-ci.org/Anuken/Mindustry.svg?branch=master)](https://travis-ci.org/Anuken/Mindustry) -[![Discord](https://img.shields.io/discord/391020510269669376.svg)](https://discord.gg/mindustry) +[![Discord](https://img.shields.io/discord/391020510269669376.svg?logo=discord&logoColor=white&logoWidth=20&labelColor=7289DA&label=Discord)](https://discord.gg/mindustry) A sandbox tower defense game written in Java. diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 501c255d2e..88bd457e05 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -98,6 +98,8 @@ public class Annotations{ boolean serialize() default true; /** Whether to generate IO code. This is for advanced usage only. */ boolean genio() default true; + /** Whether I made a massive mistake by merging two different class branches */ + boolean legacy() default false; } /** Indicates an internal interface for entity components. */ diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java index 1cd5f7c4e5..8eba0ec683 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java @@ -240,7 +240,6 @@ public class EntityProcess extends BaseProcessor{ //look at each definition for(Selement type : allDefs){ EntityDef ann = type.annotation(EntityDef.class); - boolean isFinal = ann.isFinal(); //all component classes (not interfaces) Seq components = allComponents(type); @@ -274,6 +273,10 @@ public class EntityProcess extends BaseProcessor{ name += "Entity"; } + if(ann.legacy()){ + name += "Legacy" + Strings.capitalize(type.name()); + } + //skip double classes if(usedNames.containsKey(name)){ extraNames.get(usedNames.get(name), ObjectSet::new).add(type.name()); diff --git a/annotations/src/main/resources/revisions/block/3.json b/annotations/src/main/resources/revisions/block/3.json new file mode 100644 index 0000000000..75c7a4a245 --- /dev/null +++ b/annotations/src/main/resources/revisions/block/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/corvus/3.json b/annotations/src/main/resources/revisions/corvus/3.json new file mode 100644 index 0000000000..75c7a4a245 --- /dev/null +++ b/annotations/src/main/resources/revisions/corvus/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/flare/3.json b/annotations/src/main/resources/revisions/flare/3.json new file mode 100644 index 0000000000..75c7a4a245 --- /dev/null +++ b/annotations/src/main/resources/revisions/flare/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/mace/3.json b/annotations/src/main/resources/revisions/mace/3.json new file mode 100644 index 0000000000..811f101bd5 --- /dev/null +++ b/annotations/src/main/resources/revisions/mace/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:baseRotation,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/oct/2.json b/annotations/src/main/resources/revisions/oct/2.json new file mode 100644 index 0000000000..87371c85dd --- /dev/null +++ b/annotations/src/main/resources/revisions/oct/2.json @@ -0,0 +1 @@ +{version:2,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/quad/3.json b/annotations/src/main/resources/revisions/quad/3.json new file mode 100644 index 0000000000..d091179927 --- /dev/null +++ b/annotations/src/main/resources/revisions/quad/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:payloads,type:arc.struct.Seq},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/risso/3.json b/annotations/src/main/resources/revisions/risso/3.json new file mode 100644 index 0000000000..75c7a4a245 --- /dev/null +++ b/annotations/src/main/resources/revisions/risso/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/spiroct/3.json b/annotations/src/main/resources/revisions/spiroct/3.json new file mode 100644 index 0000000000..364fdca813 --- /dev/null +++ b/annotations/src/main/resources/revisions/spiroct/3.json @@ -0,0 +1 @@ +{version:3,fields:[{name:ammo,type:float},{name:armor,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/assets/contributors b/core/assets/contributors index 9f1cf8c9f4..4d8c2faf6b 100644 --- a/core/assets/contributors +++ b/core/assets/contributors @@ -96,3 +96,7 @@ YellOw139 PetrGasparik LeoDog896 Summet +jalastram (freesound.org) +newlocknew (freesound.org) +dsmolenaers (freesound.org) +Headphaze (freesound.org) \ No newline at end of file diff --git a/core/assets/maps/fungalPass.msav b/core/assets/maps/fungalPass.msav index 99dae10492..b9a6f6575b 100644 Binary files a/core/assets/maps/fungalPass.msav and b/core/assets/maps/fungalPass.msav differ diff --git a/core/assets/sounds/artillery.ogg b/core/assets/sounds/artillery.ogg index e3651f5ce1..d9f8b74d75 100644 Binary files a/core/assets/sounds/artillery.ogg and b/core/assets/sounds/artillery.ogg differ diff --git a/core/assets/sounds/bang.ogg b/core/assets/sounds/bang.ogg index afbd099e6f..29cde62552 100644 Binary files a/core/assets/sounds/bang.ogg and b/core/assets/sounds/bang.ogg differ diff --git a/core/assets/sounds/boom.ogg b/core/assets/sounds/boom.ogg index 4cce577fe9..19f41d80b2 100644 Binary files a/core/assets/sounds/boom.ogg and b/core/assets/sounds/boom.ogg differ diff --git a/core/assets/sounds/combustion.ogg b/core/assets/sounds/combustion.ogg new file mode 100644 index 0000000000..6aab153a47 Binary files /dev/null and b/core/assets/sounds/combustion.ogg differ diff --git a/core/assets/sounds/conveyor.ogg b/core/assets/sounds/conveyor.ogg index 9f989d70d0..67576b44a4 100644 Binary files a/core/assets/sounds/conveyor.ogg and b/core/assets/sounds/conveyor.ogg differ diff --git a/core/assets/sounds/cutter.ogg b/core/assets/sounds/cutter.ogg new file mode 100644 index 0000000000..313159006e Binary files /dev/null and b/core/assets/sounds/cutter.ogg differ diff --git a/core/assets/sounds/drill.ogg b/core/assets/sounds/drill.ogg index 6aab153a47..f21898b646 100644 Binary files a/core/assets/sounds/drill.ogg and b/core/assets/sounds/drill.ogg differ diff --git a/core/assets/sounds/empty.ogg b/core/assets/sounds/empty.ogg deleted file mode 100644 index 6c7ecbe8e0..0000000000 Binary files a/core/assets/sounds/empty.ogg and /dev/null differ diff --git a/core/assets/sounds/grinding.ogg b/core/assets/sounds/grinding.ogg new file mode 100644 index 0000000000..f78d2c4e67 Binary files /dev/null and b/core/assets/sounds/grinding.ogg differ diff --git a/core/assets/sounds/hum.ogg b/core/assets/sounds/hum.ogg new file mode 100644 index 0000000000..184504f3dd Binary files /dev/null and b/core/assets/sounds/hum.ogg differ diff --git a/core/assets/sounds/laserblast.ogg b/core/assets/sounds/laserblast.ogg new file mode 100644 index 0000000000..6df3b14284 Binary files /dev/null and b/core/assets/sounds/laserblast.ogg differ diff --git a/core/assets/sounds/lasercharge.ogg b/core/assets/sounds/lasercharge.ogg new file mode 100644 index 0000000000..7e50df3661 Binary files /dev/null and b/core/assets/sounds/lasercharge.ogg differ diff --git a/core/assets/sounds/lasercharge2.ogg b/core/assets/sounds/lasercharge2.ogg new file mode 100644 index 0000000000..2a737e5f63 Binary files /dev/null and b/core/assets/sounds/lasercharge2.ogg differ diff --git a/core/assets/sounds/lasershoot.ogg b/core/assets/sounds/lasershoot.ogg new file mode 100644 index 0000000000..d25c17a4cb Binary files /dev/null and b/core/assets/sounds/lasershoot.ogg differ diff --git a/core/assets/sounds/minebeam.ogg b/core/assets/sounds/minebeam.ogg new file mode 100644 index 0000000000..27f75a8531 Binary files /dev/null and b/core/assets/sounds/minebeam.ogg differ diff --git a/core/assets/sounds/mud.ogg b/core/assets/sounds/mud.ogg new file mode 100644 index 0000000000..8eb75cb67e Binary files /dev/null and b/core/assets/sounds/mud.ogg differ diff --git a/core/assets/sounds/pew.ogg b/core/assets/sounds/pew.ogg index d4b1c791c6..6a15b963e3 100644 Binary files a/core/assets/sounds/pew.ogg and b/core/assets/sounds/pew.ogg differ diff --git a/core/assets/sounds/pew_.ogg b/core/assets/sounds/pew_.ogg new file mode 100644 index 0000000000..0c1df7f711 Binary files /dev/null and b/core/assets/sounds/pew_.ogg differ diff --git a/core/assets/sounds/pulse.ogg b/core/assets/sounds/pulse.ogg new file mode 100644 index 0000000000..6c135c8a07 Binary files /dev/null and b/core/assets/sounds/pulse.ogg differ diff --git a/core/assets/sounds/railgun.ogg b/core/assets/sounds/railgun.ogg new file mode 100644 index 0000000000..d8de298916 Binary files /dev/null and b/core/assets/sounds/railgun.ogg differ diff --git a/core/assets/sounds/rain.ogg b/core/assets/sounds/rain.ogg new file mode 100644 index 0000000000..ecf90ea73d Binary files /dev/null and b/core/assets/sounds/rain.ogg differ diff --git a/core/assets/sounds/sap.ogg b/core/assets/sounds/sap.ogg new file mode 100644 index 0000000000..d84c282d02 Binary files /dev/null and b/core/assets/sounds/sap.ogg differ diff --git a/core/assets/sounds/shield.ogg b/core/assets/sounds/shield.ogg new file mode 100644 index 0000000000..b427a07286 Binary files /dev/null and b/core/assets/sounds/shield.ogg differ diff --git a/core/assets/sounds/shootSnap.ogg b/core/assets/sounds/shootSnap.ogg index fc692486a0..17826bb5c0 100644 Binary files a/core/assets/sounds/shootSnap.ogg and b/core/assets/sounds/shootSnap.ogg differ diff --git a/core/assets/sounds/smelter.ogg b/core/assets/sounds/smelter.ogg new file mode 100644 index 0000000000..86bbaf63de Binary files /dev/null and b/core/assets/sounds/smelter.ogg differ diff --git a/core/assets/sounds/splash.ogg b/core/assets/sounds/splash.ogg index 4b6e5eec53..59a77836c4 100644 Binary files a/core/assets/sounds/splash.ogg and b/core/assets/sounds/splash.ogg differ diff --git a/core/assets/sounds/spray.ogg b/core/assets/sounds/spray.ogg index 7bddeb6685..b781d106db 100644 Binary files a/core/assets/sounds/spray.ogg and b/core/assets/sounds/spray.ogg differ diff --git a/core/assets/sounds/steam.ogg b/core/assets/sounds/steam.ogg new file mode 100644 index 0000000000..9b65bac938 Binary files /dev/null and b/core/assets/sounds/steam.ogg differ diff --git a/core/assets/sounds/swish.ogg b/core/assets/sounds/swish.ogg new file mode 100644 index 0000000000..4b6e5eec53 Binary files /dev/null and b/core/assets/sounds/swish.ogg differ diff --git a/core/assets/sounds/techloop.ogg b/core/assets/sounds/techloop.ogg new file mode 100644 index 0000000000..125ac36718 Binary files /dev/null and b/core/assets/sounds/techloop.ogg differ diff --git a/core/assets/sounds/tractorbeam.ogg b/core/assets/sounds/tractorbeam.ogg new file mode 100644 index 0000000000..4c307c4e08 Binary files /dev/null and b/core/assets/sounds/tractorbeam.ogg differ diff --git a/core/assets/sounds/wind.ogg b/core/assets/sounds/wind.ogg new file mode 100644 index 0000000000..aeabe4802b Binary files /dev/null and b/core/assets/sounds/wind.ogg differ diff --git a/core/assets/sounds/wind2.ogg b/core/assets/sounds/wind2.ogg new file mode 100644 index 0000000000..3900ba35a1 Binary files /dev/null and b/core/assets/sounds/wind2.ogg differ diff --git a/core/assets/sounds/windhowl.ogg b/core/assets/sounds/windhowl.ogg new file mode 100644 index 0000000000..de7526a616 Binary files /dev/null and b/core/assets/sounds/windhowl.ogg differ diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png index daa23a8efc..b390ccaa46 100644 Binary files a/core/assets/sprites/block_colors.png and b/core/assets/sprites/block_colors.png differ diff --git a/core/assets/sprites/fallback/sprites5.png b/core/assets/sprites/fallback/sprites5.png index 57c5ea660c..8579c89af2 100644 Binary files a/core/assets/sprites/fallback/sprites5.png and b/core/assets/sprites/fallback/sprites5.png differ diff --git a/core/assets/sprites/sprites2.png b/core/assets/sprites/sprites2.png index 4d36e2f434..738333c074 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index e7d4fdc469..76200981ac 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -79,7 +79,7 @@ public class BuilderAI extends AIController{ float dist = Math.min(cons.dst(unit) - buildingRange, 0); //make sure you can reach the request in time - if(dist / unit.type.speed < cons.buildCost * 0.9f){ + if(dist / unit.speed() < cons.buildCost * 0.9f){ following = b; found = true; } diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index 7262ae216a..bf7367731d 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -55,7 +55,7 @@ public class FlyingAI extends AIController{ vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f)); } - vec.setLength(unit.type.speed); + vec.setLength(unit.speed()); unit.moveAt(vec); } diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index 002c52a75c..98f4874779 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -2,17 +2,13 @@ package mindustry.ai.types; import arc.math.*; import arc.math.geom.*; -import arc.struct.*; import arc.util.*; import mindustry.ai.formations.*; import mindustry.entities.units.*; import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.*; import mindustry.world.blocks.storage.CoreBlock.*; public class FormationAI extends AIController implements FormationMember{ - private static Seq tiles = new Seq<>(); public Unit leader; private Vec3 target = new Vec3(); @@ -30,9 +26,8 @@ public class FormationAI extends AIController implements FormationMember{ @Override public void updateUnit(){ - UnitType type = unit.type; - if(leader.dead){ + if(leader == null || leader.dead){ unit.resetController(); return; } diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java index da86af9f59..20650efe53 100644 --- a/core/src/mindustry/ai/types/LogicAI.java +++ b/core/src/mindustry/ai/types/LogicAI.java @@ -104,9 +104,7 @@ public class LogicAI extends AIController{ //look where moving if there's nothing to aim at if(!shoot){ - if(unit.moving()){ - unit.lookAt(unit.vel().angle()); - } + unit.lookAt(unit.prefRotation()); }else if(unit.hasWeapons()){ //if there is, look at the object unit.lookAt(unit.mounts[0].aimX, unit.mounts[0].aimY); } diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index c006d3ac2f..1143f31675 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -65,7 +65,7 @@ public class SuicideAI extends GroundAI{ if(!blocked){ moveToTarget = true; //move towards target directly - unit.moveAt(vec.set(target).sub(unit).limit(unit.type.speed)); + unit.moveAt(vec.set(target).sub(unit).limit(unit.speed())); } } } diff --git a/core/src/mindustry/audio/LoopControl.java b/core/src/mindustry/audio/LoopControl.java index 65e3789463..56f06d9e1b 100644 --- a/core/src/mindustry/audio/LoopControl.java +++ b/core/src/mindustry/audio/LoopControl.java @@ -31,12 +31,12 @@ public class LoopControl{ boolean play = data.curVolume > 0.01f; float pan = Mathf.zero(data.total, 0.0001f) ? 0f : sound.calcPan(data.sum.x / data.total, data.sum.y / data.total); - if(data.soundID <= 0){ + if(data.soundID <= 0 || !sound.isPlaying(data.soundID)){ if(play){ data.soundID = sound.loop(data.curVolume, 1f, pan); } }else{ - if(data.curVolume <= 0.01f){ + if(data.curVolume <= 0.001f){ sound.stop(); data.soundID = -1; return; diff --git a/core/src/mindustry/audio/MusicControl.java b/core/src/mindustry/audio/MusicControl.java index 52358af758..85979e4f65 100644 --- a/core/src/mindustry/audio/MusicControl.java +++ b/core/src/mindustry/audio/MusicControl.java @@ -2,6 +2,7 @@ package mindustry.audio; import arc.*; import arc.audio.*; +import arc.audio.SoloudAudio.*; import arc.math.*; import arc.struct.*; import arc.util.*; @@ -25,6 +26,11 @@ public class MusicControl{ protected float fade; protected boolean silenced; + protected boolean wasPaused; + protected AudioFilter filter = new BiquadFilter(){{ + set(0, 500, 1); + }}; + public MusicControl(){ Events.on(ClientLoadEvent.class, e -> reload()); @@ -54,6 +60,13 @@ public class MusicControl{ /** Update and play the right music track.*/ public void update(){ + boolean paused = state.isGame() && Core.scene.hasDialog(); + + if(paused != wasPaused){ + Core.audio.setFilter(0, paused ? filter : null); + wasPaused = paused; + } + if(state.isMenu()){ silenced = false; if(ui.planet.isShown()){ diff --git a/core/src/mindustry/audio/SoundLoop.java b/core/src/mindustry/audio/SoundLoop.java index 99d6837251..4db5530cfd 100644 --- a/core/src/mindustry/audio/SoundLoop.java +++ b/core/src/mindustry/audio/SoundLoop.java @@ -18,7 +18,7 @@ public class SoundLoop{ } public void update(float x, float y, boolean play){ - if(baseVolume < 0) return; + if(baseVolume <= 0) return; if(id < 0){ if(play){ @@ -36,6 +36,7 @@ public class SoundLoop{ return; } } + sound.setPan(id, sound.calcPan(x, y), sound.calcVolume(x, y) * volume * baseVolume); } } diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 535b601db9..2146214553 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -288,6 +288,10 @@ public class Blocks implements ContentList{ attributes.set(Attribute.water, 1f); cacheLayer = CacheLayer.mud; albedo = 0.35f; + walkSound = Sounds.mud; + walkSoundVolume = 0.08f; + walkSoundPitchMin = 0.4f; + walkSoundPitchMax = 0.5f; }}; ((ShallowLiquid)darksandTaintedWater).set(Blocks.taintedWater, Blocks.darksand); @@ -592,6 +596,9 @@ public class Blocks implements ContentList{ hasPower = true; drawer = new DrawWeave(); + ambientSound = Sounds.techloop; + ambientSoundVolume = 0.02f; + consumes.items(with(Items.thorium, 4, Items.sand, 10)); consumes.power(5f); itemCapacity = 20; @@ -720,6 +727,8 @@ public class Blocks implements ContentList{ updateEffect = Fx.pulverizeSmall; hasItems = hasPower = true; drawer = new DrawRotator(); + ambientSound = Sounds.grinding; + ambientSoundVolume = 0.02f; consumes.item(Items.scrap, 1); consumes.power(0.50f); @@ -1158,6 +1167,9 @@ public class Blocks implements ContentList{ requirements(Category.power, with(Items.copper, 25, Items.lead, 15)); powerProduction = 1f; itemDuration = 120f; + + ambientSound = Sounds.smelter; + ambientSoundVolume = 0.03f; }}; thermalGenerator = new ThermalGenerator("thermal-generator"){{ @@ -1166,6 +1178,8 @@ public class Blocks implements ContentList{ generateEffect = Fx.redgeneratespark; size = 2; floating = true; + ambientSound = Sounds.hum; + ambientSoundVolume = 0.04f; }}; steamGenerator = new BurnerGenerator("steam-generator"){{ @@ -1175,6 +1189,9 @@ public class Blocks implements ContentList{ consumes.liquid(Liquids.water, 0.1f); hasLiquids = true; size = 2; + + ambientSound = Sounds.smelter; + ambientSoundVolume = 0.05f; }}; differentialGenerator = new SingleTypeGenerator("differential-generator"){{ @@ -1184,6 +1201,8 @@ public class Blocks implements ContentList{ hasLiquids = true; hasItems = true; size = 3; + ambientSound = Sounds.steam; + ambientSoundVolume = 0.03f; consumes.item(Items.pyratite).optional(true, false); consumes.liquid(Liquids.cryofluid, 0.1f); @@ -1209,6 +1228,8 @@ public class Blocks implements ContentList{ thoriumReactor = new NuclearReactor("thorium-reactor"){{ requirements(Category.power, with(Items.lead, 300, Items.silicon, 200, Items.graphite, 150, Items.thorium, 150, Items.metaglass, 50)); + ambientSound = Sounds.hum; + ambientSoundVolume = 0.2f; size = 3; health = 700; itemDuration = 360f; @@ -1224,6 +1245,9 @@ public class Blocks implements ContentList{ health = 900; powerProduction = 130f; itemDuration = 140f; + ambientSound = Sounds.pulse; + ambientSoundVolume = 0.2f; + consumes.power(25f); consumes.item(Items.blastCompound); consumes.liquid(Liquids.cryofluid, 0.25f); @@ -1464,7 +1488,7 @@ public class Blocks implements ContentList{ inaccuracy = 1f; shootCone = 10f; health = 260; - shootSound = Sounds.artillery; + shootSound = Sounds.bang; }}; wave = new LiquidTurret("wave"){{ @@ -1484,7 +1508,6 @@ public class Blocks implements ContentList{ shootEffect = Fx.shootLiquid; range = 110f; health = 250 * size * size; - shootSound = Sounds.splash; }}; lancer = new ChargeTurret("lancer"){{ @@ -1632,7 +1655,6 @@ public class Blocks implements ContentList{ shootEffect = Fx.shootLiquid; range = 190f; health = 250 * size * size; - shootSound = Sounds.splash; }}; fuse = new ItemTurret("fuse"){{ @@ -1752,13 +1774,13 @@ public class Blocks implements ContentList{ shots = 1; size = 4; shootCone = 2f; - shootSound = Sounds.shootBig; + shootSound = Sounds.railgun; unitSort = (u, x, y) -> -u.maxHealth; - coolantMultiplier = 0.09f; + coolantMultiplier = 0.11f; health = 150 * size * size; - consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true); + coolantUsage = 1f; consumes.powerCond(10f, TurretBuild::isActive); }}; @@ -1786,7 +1808,7 @@ public class Blocks implements ContentList{ shootSound = Sounds.shootBig; health = 160 * size * size; - consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 2f)).update(false).optional(true, true); + coolantUsage = 1f; }}; meltdown = new LaserTurret("meltdown"){{ @@ -1802,8 +1824,8 @@ public class Blocks implements ContentList{ shootDuration = 220f; powerUse = 17f; shootSound = Sounds.laserbig; - activeSound = Sounds.beam; - activeSoundVolume = 2f; + loopSound = Sounds.beam; + loopSoundVolume = 2f; shootType = new ContinuousLaserBulletType(70){{ length = 200f; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index c32d4113ed..53757ee04b 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -21,7 +21,7 @@ public class UnitTypes implements ContentList{ public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign; //mech + builder + miner - public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class}) UnitType nova, pulsar, quasar; + public static @EntityDef({Unitc.class, Mechc.class, Builderc.class}) UnitType nova, pulsar, quasar; //mech public static @EntityDef({Unitc.class, Mechc.class}) UnitType vela; @@ -35,23 +35,23 @@ public class UnitTypes implements ContentList{ //air (no special traits) public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra; - //air + mining - public static @EntityDef({Unitc.class, Minerc.class}) UnitType mono; + //air, legacy mining + public static @EntityDef(value = {Unitc.class}, legacy = true) UnitType mono; //air + building + mining - public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType poly; + public static @EntityDef({Unitc.class, Builderc.class}) UnitType poly; //air + building + mining + payload - public static @EntityDef({Unitc.class, Builderc.class, Minerc.class, Payloadc.class}) UnitType mega; + public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType mega; //air + building + payload - public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType quad; + public static @EntityDef(value = {Unitc.class, Builderc.class, Payloadc.class}, legacy = true) UnitType quad; //air + building + payload public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, AmmoDistributec.class}) UnitType oct; //air + building + mining - public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma; + public static @EntityDef({Unitc.class, Builderc.class}) UnitType alpha, beta, gamma; //water public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType risso, minke, bryde, sei, omura; @@ -166,7 +166,7 @@ public class UnitTypes implements ContentList{ recoil = 5f; shake = 2f; ejectEffect = Fx.casing3; - shootSound = Sounds.artillery; + shootSound = Sounds.bang; shots = 3; inaccuracy = 3f; shotDelay = 4f; @@ -226,7 +226,7 @@ public class UnitTypes implements ContentList{ recoil = 5f; shake = 2f; ejectEffect = Fx.casing4; - shootSound = Sounds.artillery; + shootSound = Sounds.bang; bullet = new BasicBulletType(13f, 60){{ pierce = true; @@ -287,6 +287,8 @@ public class UnitTypes implements ContentList{ alternate = false; ejectEffect = Fx.none; recoil = 2f; + shootSound = Sounds.lasershoot; + bullet = new LaserBoltBulletType(5.2f, 14){{ healPercent = 5f; collidesTeam = true; @@ -328,7 +330,7 @@ public class UnitTypes implements ContentList{ spacing = 0f; ejectEffect = Fx.none; recoil = 2.5f; - shootSound = Sounds.pew; + shootSound = Sounds.spark; bullet = new LightningBulletType(){{ lightningColor = hitColor = Pal.heal; @@ -430,7 +432,8 @@ public class UnitTypes implements ContentList{ reload = 320f; recoil = 0f; - shootSound = Sounds.laser; + chargeSound = Sounds.lasercharge2; + shootSound = Sounds.beam; continuous = true; cooldownTime = 200f; @@ -491,6 +494,9 @@ public class UnitTypes implements ContentList{ drawShields = false; weapons.add(new Weapon("corvus-weapon"){{ + shootSound = Sounds.laserblast; + chargeSound = Sounds.lasercharge; + soundPitchMin = 1f; top = false; mirror = false; shake = 14f; @@ -498,7 +504,6 @@ public class UnitTypes implements ContentList{ x = y = 0; reload = 350f; recoil = 0f; - shootSound = Sounds.laser; cooldownTime = 350f; @@ -634,7 +639,7 @@ public class UnitTypes implements ContentList{ ejectEffect = Fx.none; recoil = 2f; rotate = true; - shootSound = Sounds.flame; + shootSound = Sounds.sap; x = 8.5f; y = -1.5f; @@ -657,6 +662,7 @@ public class UnitTypes implements ContentList{ rotate = true; x = 4f; y = 3f; + shootSound = Sounds.sap; bullet = new SapBulletType(){{ sapStrength = 0.8f; @@ -721,6 +727,7 @@ public class UnitTypes implements ContentList{ y = 8f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("spiroct-weapon"){{ reload = 15f; @@ -728,6 +735,7 @@ public class UnitTypes implements ContentList{ y = 6f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("spiroct-weapon"){{ reload = 23f; @@ -735,6 +743,7 @@ public class UnitTypes implements ContentList{ y = 0f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("large-purple-mount"){{ y = -7f; @@ -744,7 +753,7 @@ public class UnitTypes implements ContentList{ shake = 3f; rotateSpeed = 2f; ejectEffect = Fx.casing1; - shootSound = Sounds.shootBig; + shootSound = Sounds.artillery; rotate = true; occlusion = 8f; recoil = 3f; @@ -842,7 +851,7 @@ public class UnitTypes implements ContentList{ recoil = 10f; rotateSpeed = 1f; ejectEffect = Fx.casing3; - shootSound = Sounds.shootBig; + shootSound = Sounds.artillery; rotate = true; occlusion = 30f; @@ -1205,7 +1214,7 @@ public class UnitTypes implements ContentList{ reload = 30f; ejectEffect = Fx.none; recoil = 2f; - shootSound = Sounds.pew; + shootSound = Sounds.missile; shots = 1; velocityRnd = 0.5f; inaccuracy = 15f; @@ -1221,6 +1230,7 @@ public class UnitTypes implements ContentList{ smokeEffect = Fx.hitLaser; hitEffect = despawnEffect = Fx.hitLaser; frontColor = Color.white; + hitSound = Sounds.none; healPercent = 5.5f; collidesTeam = true; @@ -1252,6 +1262,7 @@ public class UnitTypes implements ContentList{ weapons.add( new Weapon("heal-weapon-mount"){{ + shootSound = Sounds.lasershoot; reload = 25f; x = 8f; y = -6f; @@ -1259,6 +1270,7 @@ public class UnitTypes implements ContentList{ bullet = Bullets.healBulletBig; }}, new Weapon("heal-weapon-mount"){{ + shootSound = Sounds.lasershoot; reload = 15f; x = 4f; y = 5f; @@ -1578,7 +1590,7 @@ public class UnitTypes implements ContentList{ inaccuracy = 7f; ejectEffect = Fx.none; shake = 3f; - shootSound = Sounds.shootBig; + shootSound = Sounds.missile; xRand = 8f; shotDelay = 1f; @@ -1659,6 +1671,7 @@ public class UnitTypes implements ContentList{ shake = 6f; recoil = 10.5f; occlusion = 50f; + shootSound = Sounds.railgun; shots = 1; ejectEffect = Fx.none; diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java index 2984be1ac1..f719aa0cea 100644 --- a/core/src/mindustry/content/Weathers.java +++ b/core/src/mindustry/content/Weathers.java @@ -3,6 +3,7 @@ package mindustry.content; import arc.graphics.*; import arc.util.*; import mindustry.ctype.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.type.weather.*; import mindustry.world.meta.*; @@ -23,12 +24,20 @@ public class Weathers implements ContentList{ sizeMin = 2.6f; density = 1200f; attrs.set(Attribute.light, -0.15f); + + sound = Sounds.windhowl; + soundVol = 0f; + soundVolOscMag = 1.5f; + soundVolOscScl = 1100f; + soundVolMin = 0.02f; }}; rain = new RainWeather("rain"){{ attrs.set(Attribute.light, -0.2f); attrs.set(Attribute.water, 0.2f); status = StatusEffects.wet; + sound = Sounds.rain; + soundVol = 0.25f; }}; sandstorm = new ParticleWeather("sandstorm"){{ @@ -46,6 +55,8 @@ public class Weathers implements ContentList{ attrs.set(Attribute.water, -0.1f); opacityMultiplier = 0.8f; force = 0.1f; + sound = Sounds.wind; + soundVol = 0.3f; }}; sporestorm = new ParticleWeather("sporestorm"){{ @@ -65,6 +76,8 @@ public class Weathers implements ContentList{ status = StatusEffects.sporeSlowed; opacityMultiplier = 0.85f; force = 0.1f; + sound = Sounds.wind; + soundVol = 0.3f; }}; fog = new ParticleWeather("fog"){{ diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index cdb6738ebd..b492199be5 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -477,10 +477,6 @@ public class Control implements ApplicationListener, Loadable{ dialog.show(); })); } - - if(android){ - Sounds.empty.loop(0f, 1f, 0f); - } } @Override diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 5f26cebdb7..3f1de4d98a 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -640,7 +640,7 @@ public class NetServer implements ApplicationListener{ Unit unit = player.unit(); long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime); - float maxSpeed = ((player.unit().type.canBoost && player.unit().isFlying()) ? player.unit().type.boostMultiplier : 1f) * player.unit().type.speed; + float maxSpeed = ((player.unit().type.canBoost && player.unit().isFlying()) ? player.unit().type.boostMultiplier : 1f) * player.unit().speed(); if(unit.isGrounded()){ maxSpeed *= unit.floorSpeedMultiplier(); } diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index ab16eea106..57fcd76392 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -126,7 +126,7 @@ public abstract class UnlockableContent extends MappableContent{ } public boolean unlocked(){ - if(net != null && net.client()) return state.rules.researched.contains(name); + if(net != null && net.client()) return alwaysUnlocked || state.rules.researched.contains(name); return unlocked || alwaysUnlocked; } diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 720352a5a3..4d635ab2db 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -207,7 +207,7 @@ public abstract class BulletType extends Content{ Damage.createIncend(x, y, incendSpread, incendAmount); } - if(splashDamageRadius > 0){ + if(splashDamageRadius > 0 && !b.absorbed){ Damage.damage(b.team, x, y, splashDamageRadius, splashDamage * b.damageMultiplier(), collidesAir, collidesGround); if(status != StatusEffects.none){ diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 0ef4d8bed0..4d9f81fa65 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -27,7 +27,7 @@ abstract class BuilderComp implements Unitc{ @Import float x, y, rotation; - @SyncLocal Queue plans = new Queue<>(); + @SyncLocal Queue plans = new Queue<>(1); @SyncLocal transient boolean updateBuilding = true; @Override @@ -35,7 +35,6 @@ abstract class BuilderComp implements Unitc{ if(!updateBuilding) return; float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; - boolean infinite = state.rules.infiniteResources || team().rules().infiniteResources; Iterator it = plans.iterator(); @@ -69,10 +68,6 @@ abstract class BuilderComp implements Unitc{ Tile tile = world.tile(current.x, current.y); - if(within(tile, finalPlaceDst)){ - lookAt(angleTo(tile)); - } - if(!(tile.block() instanceof ConstructBlock)){ if(!current.initialized && !current.breaking && Build.validPlace(current.block, team(), current.x, current.y, current.rotation)){ boolean hasAll = infinite || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item)); @@ -188,6 +183,10 @@ abstract class BuilderComp implements Unitc{ } boolean activelyBuilding(){ + //not actively building when not near the build plan + if(isBuilding() && !within(buildPlan(), state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange)){ + return false; + } return isBuilding() && updateBuilding; } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 9f6add7af7..23f0175867 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -29,6 +29,7 @@ import mindustry.logic.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.world.*; +import mindustry.world.blocks.*; import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.environment.*; import mindustry.world.blocks.payloads.*; @@ -106,8 +107,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, this.block = block; this.team = team; - if(block.activeSound != Sounds.none){ - sound = new SoundLoop(block.activeSound, block.activeSoundVolume); + if(block.loopSound != Sounds.none){ + sound = new SoundLoop(block.loopSound, block.loopSoundVolume); } health = block.health; @@ -780,7 +781,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } /** @return whether this block should play its idle sound.*/ - public boolean shouldIdleSound(){ + public boolean shouldAmbientSound(){ return shouldConsume(); } @@ -1225,6 +1226,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } + /** @return ambient sound volume scale. */ + public float ambientVolume(){ + return efficiency(); + } + //endregion //region overrides @@ -1285,6 +1291,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored(); case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity(); case enabled -> enabled ? 1 : 0; + case controlled -> this instanceof ControlBlock c ? c.isControlled() ? 1 : 0 : 0; case payloadCount -> getPayload() != null ? 1 : 0; default -> 0; }; @@ -1365,8 +1372,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, sound.update(x, y, shouldActiveSound()); } - if(block.idleSound != Sounds.none && shouldIdleSound()){ - loops.play(block.idleSound, self(), block.idleSoundVolume); + if(block.ambientSound != Sounds.none && shouldAmbientSound()){ + loops.play(block.ambientSound, self(), block.ambientSoundVolume * ambientVolume()); } if(enabled || !block.noUpdateDisabled){ diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index fc8d8ff12b..ba6deb6f24 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -30,6 +30,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw Object data; BulletType type; float fdata; + transient boolean absorbed; @Override public void getCollisions(Cons consumer){ @@ -67,6 +68,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw @Override public void absorb(){ + absorbed = true; remove(); } diff --git a/core/src/mindustry/entities/comp/FlyingComp.java b/core/src/mindustry/entities/comp/FlyingComp.java index 0c8c2f0277..be7b003baa 100644 --- a/core/src/mindustry/entities/comp/FlyingComp.java +++ b/core/src/mindustry/entities/comp/FlyingComp.java @@ -75,10 +75,14 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ wasFlying = isFlying(); } - if(!hovering && isGrounded() && floor.isLiquid){ + if(!hovering && isGrounded()){ if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= (7f + hitSize()/8f)){ floor.walkEffect.at(x, y, hitSize() / 8f, floor.mapColor); splashTimer = 0f; + + if(!(this instanceof WaterMovec)){ + floor.walkSound.at(x, y, Mathf.random(floor.walkSoundPitchMin, floor.walkSoundPitchMax), floor.walkSoundVolume); + } } } diff --git a/core/src/mindustry/entities/comp/LegsComp.java b/core/src/mindustry/entities/comp/LegsComp.java index e6022ed91e..8ddb4793e4 100644 --- a/core/src/mindustry/entities/comp/LegsComp.java +++ b/core/src/mindustry/entities/comp/LegsComp.java @@ -112,6 +112,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ Floor floor = Vars.world.floorWorld(l.base.x, l.base.y); if(floor.isLiquid){ floor.walkEffect.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor); + floor.walkSound.at(x, y, 1f, floor.walkSoundVolume); }else{ Fx.unitLandSmall.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor); } diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java index bdeead4fe9..37a0fd2393 100644 --- a/core/src/mindustry/entities/comp/MinerComp.java +++ b/core/src/mindustry/entities/comp/MinerComp.java @@ -16,8 +16,8 @@ import mindustry.world.*; import static mindustry.Vars.*; @Component -abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ - @Import float x, y, rotation; +abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{ + @Import float x, y, rotation, hitSize; @Import UnitType type; transient float mineTimer; @@ -28,7 +28,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ } public boolean offloadImmediately(){ - return isPlayer(); + return this.self().isPlayer(); } boolean mining(){ @@ -63,7 +63,6 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ mineTimer = 0f; }else if(mining()){ Item item = mineTile.drop(); - lookAt(angleTo(mineTile.worldx(), mineTile.worldy())); mineTimer += Time.delta *type.mineSpeed; if(Mathf.chance(0.06 * Time.delta)){ @@ -88,13 +87,17 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ mineTimer = 0f; } } + + if(!headless){ + loops.play(type.mineSound, this, type.mineSoundVolume); + } } } @Override public void draw(){ if(!mining()) return; - float focusLen = hitSize() / 2f + Mathf.absin(Time.time(), 1.1f, 0.5f); + float focusLen = hitSize / 2f + Mathf.absin(Time.time(), 1.1f, 0.5f); float swingScl = 12f, swingMag = tilesize / 8f; float flashScl = 0.3f; diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 3cba913fbb..4c199542c3 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -9,6 +9,7 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import mindustry.ai.*; +import mindustry.ai.types.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.*; @@ -30,10 +31,10 @@ import mindustry.world.blocks.payloads.*; import static mindustry.Vars.*; @Component(base = true) -abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged{ +abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc{ @Import boolean hovering, dead; - @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo; + @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed; @Import Team team; @Import int id; @@ -67,9 +68,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I return type.hasWeapons(); } + public float speed(){ + //limit speed to minimum formation speed to preserve formation + return isCommanding() ? minFormationSpeed * 0.98f : type.speed; + } + /** @return speed with boost multipliers factored in. */ public float realSpeed(){ - return Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation) * type.speed; + return Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation) * speed(); } /** Iterates through this unit and everything it is controlling. */ @@ -78,6 +84,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I controlling().each(cons); } + /** @return where the unit wants to look at. */ + public float prefRotation(){ + if(this instanceof Builderc builder && builder.activelyBuilding()){ + return angleTo(builder.buildPlan()); + }else if(mineTile() != null){ + return angleTo(mineTile()); + }else if(moving()){ + return vel().angle(); + } + return rotation; + } + @Override public float range(){ return type.range; @@ -105,6 +123,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I case shootX -> World.conv(aimX()); case shootY -> World.conv(aimY()); case flag -> flag; + case controlled -> controller instanceof LogicAI || controller instanceof Player ? 1 : 0; case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0; default -> 0; }; diff --git a/core/src/mindustry/entities/comp/WeaponsComp.java b/core/src/mindustry/entities/comp/WeaponsComp.java index 00fc925a5e..ab4321393a 100644 --- a/core/src/mindustry/entities/comp/WeaponsComp.java +++ b/core/src/mindustry/entities/comp/WeaponsComp.java @@ -4,6 +4,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.audio.*; import mindustry.entities.*; import mindustry.entities.bullet.*; import mindustry.entities.units.*; @@ -117,10 +118,18 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ mount.bullet.rotation(weaponRotation + 90); mount.bullet.set(shootX, shootY); vel.add(Tmp.v1.trns(rotation + 180f, mount.bullet.type.recoil)); + if(weapon.shootSound != Sounds.none && !headless){ + if(mount.sound == null) mount.sound = new SoundLoop(weapon.shootSound, 1f); + mount.sound.update(x, y, true); + } } }else{ //heat decreases when not firing mount.heat = Math.max(mount.heat - Time.delta * reloadMultiplier / mount.weapon.cooldownTime, 0); + + if(mount.sound != null){ + mount.sound.update(x, y, false); + } } //flip weapon shoot side for alternating weapons at half reload @@ -168,7 +177,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ float baseX = this.x, baseY = this.y; boolean delay = weapon.firstShotDelay + weapon.shotDelay > 0f; - (delay ? weapon.chargeSound : weapon.shootSound).at(x, y, Mathf.random(0.8f, 1.0f)); + (delay ? weapon.chargeSound : weapon.continuous ? Sounds.none : weapon.shootSound).at(x, y, Mathf.random(weapon.soundPitchMin, weapon.soundPitchMax)); BulletType ammo = weapon.bullet; float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, aimX, aimY) / ammo.range()) : 1f; @@ -195,7 +204,9 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); Effect.shake(weapon.shake, weapon.shake, x, y); mount.heat = 1f; - weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); + if(!weapon.continuous){ + weapon.shootSound.at(x, y, Mathf.random(weapon.soundPitchMin, weapon.soundPitchMax)); + } }); }else{ vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index 27c1a9a942..78ee1c1d3c 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -64,9 +64,7 @@ public class AIController implements UnitController{ if(unit.isFlying()){ unit.wobble(); - if(unit.moving()){ - unit.lookAt(unit.vel.angle()); - } + unit.lookAt(unit.prefRotation()); } } @@ -94,7 +92,7 @@ public class AIController implements UnitController{ if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return; - unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type.speed)); + unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.speed())); } protected void updateWeapons(){ @@ -175,7 +173,7 @@ public class AIController implements UnitController{ } protected void circle(Position target, float circleLength){ - circle(target, circleLength, unit.type.speed); + circle(target, circleLength, unit.speed()); } protected void circle(Position target, float circleLength, float speed){ diff --git a/core/src/mindustry/entities/units/BuildPlan.java b/core/src/mindustry/entities/units/BuildPlan.java index 9d8e98a05f..16ec45cb07 100644 --- a/core/src/mindustry/entities/units/BuildPlan.java +++ b/core/src/mindustry/entities/units/BuildPlan.java @@ -9,7 +9,7 @@ import mindustry.world.*; import static mindustry.Vars.*; /** Class for storing build requests. Can be either a place or remove request. */ -public class BuildPlan{ +public class BuildPlan implements Position{ /** Position and rotation of this request. */ public int x, y, rotation; /** Block being placed. If null, this is a breaking request.*/ @@ -127,11 +127,11 @@ public class BuildPlan{ } public float drawx(){ - return x*tilesize + block.offset; + return x*tilesize + (block == null ? 0 : block.offset); } public float drawy(){ - return y*tilesize + block.offset; + return y*tilesize + (block == null ? 0 : block.offset); } public @Nullable Tile tile(){ @@ -142,6 +142,16 @@ public class BuildPlan{ return world.build(x, y); } + @Override + public float getX(){ + return drawx(); + } + + @Override + public float getY(){ + return drawy(); + } + @Override public String toString(){ return "BuildRequest{" + diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java index 80bf713f20..e5f61679c7 100644 --- a/core/src/mindustry/entities/units/WeaponMount.java +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -1,6 +1,7 @@ package mindustry.entities.units; import arc.util.*; +import mindustry.audio.*; import mindustry.gen.*; import mindustry.type.*; @@ -25,6 +26,8 @@ public class WeaponMount{ public boolean side; /** current bullet for continuous weapons */ public @Nullable Bullet bullet; + /** sound loop for continuous weapons */ + public @Nullable SoundLoop sound; public WeaponMount(Weapon weapon){ this.weapon = weapon; diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index d9ebe4bb69..d90efcee44 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -481,8 +481,8 @@ public class DesktopInput extends InputHandler{ deleting = true; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().plans().size == 0 || !player.builder().updateBuilding()) && !droppingItem && - !tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){ + if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.builder().activelyBuilding() && !droppingItem && + !tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){ player.shooting = shouldShoot; } }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine @@ -603,13 +603,6 @@ public class DesktopInput extends InputHandler{ boolean ground = unit.isGrounded(); float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type.strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f); - float baseSpeed = unit.type.speed; - - //limit speed to minimum formation speed to preserve formation - if(unit.isCommanding()){ - //add a tiny multiplier to let units catch up just in case - baseSpeed = unit.minFormationSpeed * 0.95f; - } float speed = unit.realSpeed() * strafePenalty; float xa = Core.input.axis(Binding.move_x); @@ -627,9 +620,7 @@ public class DesktopInput extends InputHandler{ if(aimCursor){ unit.lookAt(mouseAngle); }else{ - if(!movement.isZero()){ - unit.lookAt(unit.vel.isZero() ? movement.angle() : unit.vel.angle()); - } + unit.lookAt(unit.prefRotation()); } if(omni){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 4a4785b34a..cec0f53348 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -933,11 +933,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ boolean canMine(Tile tile){ return !Core.scene.hasMouse() - && tile.drop() != null - && player.miner().validMine(tile) - && !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null) - && player.unit().acceptsItem(tile.drop()) - && tile.block() == Blocks.air; + && tile.drop() != null + && player.miner().validMine(tile) + && !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null) + && player.unit().acceptsItem(tile.drop()) + && tile.block() == Blocks.air; } /** Returns the tile at the specified MOUSE coordinates. */ @@ -1044,7 +1044,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public boolean canShoot(){ - return block == null && !onConfigurable() && !isDroppingItem() && !(player.builder().updateBuilding() && player.builder().isBuilding()) && + return block == null && !onConfigurable() && !isDroppingItem() && !player.builder().activelyBuilding() && !(player.unit() instanceof Mechc && player.unit().isFlying()); } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 668cf95afe..11e7aa12f4 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -856,14 +856,6 @@ public class MobileInput extends InputHandler implements GestureListener{ float attractDst = 15f; float strafePenalty = legs ? 1f : Mathf.lerp(1f, type.strafePenalty, Angles.angleDist(unit.vel.angle(), unit.rotation) / 180f); - float baseSpeed = unit.type.speed; - - //limit speed to minimum formation speed to preserve formation - if(unit.isCommanding()){ - //add a tiny multiplier to let units catch up just in case - baseSpeed = unit.minFormationSpeed * 0.98f; - } - float speed = unit.realSpeed() * strafePenalty; float range = unit.hasWeapons() ? unit.range() : 0f; float bulletSpeed = unit.hasWeapons() ? type.weapons.first().bullet.speed : 0f; @@ -873,9 +865,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(aimCursor){ unit.lookAt(mouseAngle); }else{ - if(unit.moving()){ - unit.lookAt(unit.vel.angle()); - } + unit.lookAt(unit.prefRotation()); } if(payloadTarget != null && unit instanceof Payloadc pay){ @@ -905,7 +895,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(player.within(targetPos, attractDst)){ movement.setZero(); - unit.vel.approachDelta(Vec2.ZERO, type.speed * type.accel / 2f); + unit.vel.approachDelta(Vec2.ZERO, unit.speed() * type.accel / 2f); } float expansion = 3f; diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java index d8175053fa..acac5efdce 100644 --- a/core/src/mindustry/logic/LAccess.java +++ b/core/src/mindustry/logic/LAccess.java @@ -30,6 +30,7 @@ public enum LAccess{ team, type, flag, + controlled, name, config, payloadCount, diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index 23293d6b14..0e628e2333 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -96,11 +96,13 @@ public class LAssembler{ if(data == null || data.isEmpty()) return new Seq<>(); Seq statements = new Seq<>(); - String[] lines = data.split("[;\n]+"); + String[] lines = data.split("\n"); int index = 0; for(String line : lines){ //comments if(line.startsWith("#")) continue; + //remove trailing semicolons in case someone adds them in for no reason + if(line.endsWith(";")) line = line.substring(0, line.length() - 1); if(index++ > max) break; diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index c8bde0900d..c883cbd5ba 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -469,7 +469,7 @@ public class LExecutor{ Building build = exec.building(p1); int dropped = Math.min(unit.stack.amount, exec.numi(p2)); - if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ + if(build != null && build.isValid() && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ int accepted = build.acceptStack(unit.item(), dropped, unit); if(accepted > 0){ Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build); @@ -483,7 +483,7 @@ public class LExecutor{ Building build = exec.building(p1); int amount = exec.numi(p3); - if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ + if(build != null && build.isValid() && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item))); if(taken > 0){ diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index 0fccd2bc14..177807090d 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -12,8 +12,6 @@ import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; -import java.io.*; - import static mindustry.Vars.*; import static mindustry.game.EventType.*; @@ -449,111 +447,11 @@ public class Administration{ @SuppressWarnings("unchecked") private void load(){ - if(!loadLegacy()){ - //load default data - playerInfo = Core.settings.getJson("player-data", ObjectMap.class, ObjectMap::new); - bannedIPs = Core.settings.getJson("ip-bans", Seq.class, Seq::new); - whitelist = Core.settings.getJson("whitelist-ids", Seq.class, Seq::new); - subnetBans = Core.settings.getJson("banned-subnets", Seq.class, Seq::new); - }else{ - //save over loaded legacy data - save(); - Log.info("Loaded legacy (5.0) server data."); - } - } - - private boolean loadLegacy(){ - try{ - byte[] info = Core.settings.getBytes("player-info"); - byte[] ips = Core.settings.getBytes("banned-ips"); - byte[] whitelist = Core.settings.getBytes("whitelisted"); - byte[] subnet = Core.settings.getBytes("subnet-bans"); - - if(info != null){ - DataInputStream d = new DataInputStream(new ByteArrayInputStream(info)); - int size = d.readInt(); - if(size != 0){ - d.readUTF(); - d.readUTF(); - - for(int i = 0; i < size; i++){ - String mapKey = d.readUTF(); - - PlayerInfo data = new PlayerInfo(); - - data.id = d.readUTF(); - data.lastName = d.readUTF(); - data.lastIP = d.readUTF(); - int ipsize = d.readInt(); - if(ipsize != 0){ - d.readUTF(); - for(int j = 0; j < ipsize; j++){ - data.ips.add(d.readUTF()); - } - } - - int namesize = d.readInt(); - if(namesize != 0){ - d.readUTF(); - for(int j = 0; j < ipsize; j++){ - data.names.add(d.readUTF()); - } - } - //ips, names... - data.adminUsid = d.readUTF(); - data.timesKicked = d.readInt(); - data.timesJoined = d.readInt(); - data.banned = d.readBoolean(); - data.admin = d.readBoolean(); - data.lastKicked = d.readLong(); - - playerInfo.put(mapKey, data); - } - } - Core.settings.remove("player-info"); - } - - if(ips != null){ - DataInputStream d = new DataInputStream(new ByteArrayInputStream(ips)); - int size = d.readInt(); - if(size != 0){ - d.readUTF(); - for(int i = 0; i < size; i++){ - bannedIPs.add(d.readUTF()); - } - } - Core.settings.remove("banned-ips"); - } - - if(whitelist != null){ - DataInputStream d = new DataInputStream(new ByteArrayInputStream(whitelist)); - int size = d.readInt(); - if(size != 0){ - d.readUTF(); - for(int i = 0; i < size; i++){ - this.whitelist.add(d.readUTF()); - } - } - Core.settings.remove("whitelisted"); - } - - if(subnet != null){ - DataInputStream d = new DataInputStream(new ByteArrayInputStream(subnet)); - int size = d.readInt(); - if(size != 0){ - d.readUTF(); - for(int i = 0; i < size; i++){ - subnetBans.add(d.readUTF()); - } - } - Core.settings.remove("subnet-bans"); - } - - return info != null || ips != null || whitelist != null || subnet != null; - }catch(Throwable t){ - Log.err(t); - } - return false; + //load default data + playerInfo = Core.settings.getJson("player-data", ObjectMap.class, ObjectMap::new); + bannedIPs = Core.settings.getJson("ip-bans", Seq.class, Seq::new); + whitelist = Core.settings.getJson("whitelist-ids", Seq.class, Seq::new); + subnetBans = Core.settings.getJson("banned-subnets", Seq.class, Seq::new); } /** Server configuration definition. Each config value can be a string, boolean or number. */ @@ -584,8 +482,7 @@ public class Administration{ autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10), autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5), debug("Enable debug logging", false, () -> { - LogLevel level = debug() ? LogLevel.debug : LogLevel.info; - Log.level = level; + Log.level = debug() ? LogLevel.debug : LogLevel.info; }); public static final Config[] all = values(); diff --git a/core/src/mindustry/net/ServerGroup.java b/core/src/mindustry/net/ServerGroup.java new file mode 100644 index 0000000000..9f925089fb --- /dev/null +++ b/core/src/mindustry/net/ServerGroup.java @@ -0,0 +1,6 @@ +package mindustry.net; + +public class ServerGroup{ + public String[] addresses; + public String name; +} diff --git a/core/src/mindustry/type/ItemSeq.java b/core/src/mindustry/type/ItemSeq.java index 512033af23..64603d8a8d 100644 --- a/core/src/mindustry/type/ItemSeq.java +++ b/core/src/mindustry/type/ItemSeq.java @@ -55,6 +55,12 @@ public class ItemSeq implements Iterable, Serializable{ return out; } + public void min(int number){ + for(Item item : Vars.content.items()){ + set(item, Math.min(get(item), number)); + } + } + public boolean has(Item item){ return values[item.id] > 0; } diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 3c2cc4a1be..97902e48b2 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -81,6 +81,8 @@ public class UnitType extends UnlockableContent{ public AmmoType ammoType = AmmoTypes.copper; public int mineTier = -1; public float buildSpeed = 1f, mineSpeed = 1f; + public Sound mineSound = Sounds.minebeam; + public float mineSoundVolume = 0.6f; /** This is a VERY ROUGH estimate of unit DPS. */ public float dpsEstimate = -1; diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index d2b5a3bb8e..6d7434e51b 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -62,6 +62,8 @@ public class Weapon{ public float shootCone = 5f; /** ticks to cool down the heat region */ public float cooldownTime = 20f; + /** random sound pitch range */ + public float soundPitchMin = 0.8f, soundPitchMax = 1f; /** whether shooter rotation is ignored when shooting. */ public boolean ignoreRotation = false; /** min velocity required for this weapon to shoot */ diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java index 4d17ab7c0e..ed6145ceae 100644 --- a/core/src/mindustry/type/Weather.java +++ b/core/src/mindustry/type/Weather.java @@ -1,12 +1,14 @@ package mindustry.type; import arc.*; +import arc.audio.*; import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; +import arc.util.noise.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.ctype.*; @@ -22,6 +24,9 @@ public abstract class Weather extends UnlockableContent{ public float duration = 9f * Time.toMinutes; public float opacityMultiplier = 1f; public Attributes attrs = new Attributes(); + public Sound sound = Sounds.none; + public float soundVol = 0.1f, soundVolMin = 0f; + public float soundVolOscMag = 0f, soundVolOscScl = 20f; //internals public Rand rand = new Rand(); @@ -83,6 +88,11 @@ public abstract class Weather extends UnlockableContent{ state.effectTimer -= Time.delta; } } + + if(sound != Sounds.none){ + float noise = soundVolOscMag > 0 ? (float)Math.abs(Noise.rawNoise(Time.time() / soundVolOscScl)) * soundVolOscMag : 0; + loops.play(sound, Core.camera.position, Math.max((soundVol + noise) * state.opacity, soundVolMin)); + } } public void drawOver(WeatherState state){ diff --git a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java index 9f03ba3532..3ddd74e588 100644 --- a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java +++ b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java @@ -42,6 +42,13 @@ public class LaunchLoadoutDialog extends BaseDialog{ //updates sum requirements Runnable update = () -> { + int cap = selected.findCore().itemCapacity; + + //cap resources based on core type + ItemSeq resources = universe.getLaunchResources(); + resources.min(cap); + universe.updateLaunchResources(resources); + total.clear(); selected.requirements().each(total::add); universe.getLaunchResources().each(total::add); @@ -79,7 +86,7 @@ public class LaunchLoadoutDialog extends BaseDialog{ ItemSeq stacks = universe.getLaunchResources(); Seq out = stacks.toSeq(); - loadout.show(core.itemCapacity, out, UnlockableContent::unlocked, out::clear, () -> {}, () -> { + loadout.show(selected.findCore().itemCapacity, out, UnlockableContent::unlocked, out::clear, () -> {}, () -> { universe.updateLaunchResources(new ItemSeq(out)); update.run(); rebuildItems.run(); diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 0202750aaf..963e171272 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -174,14 +174,14 @@ public class Block extends UnlockableContent{ public float lightRadius = 60f; /** The sound that this block makes while active. One sound loop. Do not overuse.*/ - public Sound activeSound = Sounds.none; + public Sound loopSound = Sounds.none; /** Active sound base volume. */ - public float activeSoundVolume = 0.5f; + public float loopSoundVolume = 0.5f; /** The sound that this block makes while idle. Uses one sound loop for all blocks.*/ - public Sound idleSound = Sounds.none; + public Sound ambientSound = Sounds.none; /** Idle sound base volume. */ - public float idleSoundVolume = 0.5f; + public float ambientSoundVolume = 0.05f; /** Cost of constructing this block. */ public ItemStack[] requirements = {}; diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 1a9ed3112b..078bc02807 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -51,6 +51,8 @@ public class ForceProjector extends Block{ hasPower = true; hasLiquids = true; hasItems = true; + ambientSound = Sounds.shield; + ambientSoundVolume = 0.08f; consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).boost().update(false); } @@ -107,6 +109,11 @@ public class ForceProjector extends Block{ drawer.add(); } + @Override + public boolean shouldAmbientSound(){ + return !broken && realRadius() > 1f; + } + @Override public void onRemoved(){ super.onRemoved(); diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 8ab8b5cb41..80771f0001 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -25,7 +25,7 @@ public class LiquidTurret extends Turret{ super(name); acceptCoolant = false; hasLiquids = true; - activeSound = Sounds.spray; + loopSound = Sounds.spray; } /** Initializes accepted ammo map. Format: [liquid1, bullet1, liquid2, bullet2...] */ diff --git a/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java index 0184f9ff7a..6ee0f1ddba 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java @@ -1,5 +1,6 @@ package mindustry.world.blocks.defense.turrets; +import arc.audio.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; @@ -24,6 +25,8 @@ public class PointDefenseTurret extends ReloadTurret{ public Effect hitEffect = Fx.pointHit; public Effect shootEffect = Fx.sparkShoot; + public Sound shootSound = Sounds.lasershoot; + public float shootCone = 5f; public float bulletDamage = 10f; public float shootLength = 3f; @@ -90,6 +93,7 @@ public class PointDefenseTurret extends ReloadTurret{ beamEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color, new Vec2().set(target)); shootEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color); hitEffect.at(target.x, target.y, color); + shootSound.at(x + Tmp.v1.x, y + Tmp.v1.y, Mathf.random(0.9f, 1.1f)); reload = 0; } }else{ diff --git a/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java index 92856f6709..99ecdd9c13 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java @@ -1,5 +1,6 @@ package mindustry.world.blocks.defense.turrets; +import arc.audio.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; @@ -34,6 +35,9 @@ public class TractorBeamTurret extends BaseTurret{ public StatusEffect status = StatusEffects.none; public float statusDuration = 300; + public Sound shootSound = Sounds.tractorbeam; + public float shootSoundVolume = 0.9f; + public TractorBeamTurret(String name){ super(name); @@ -91,6 +95,8 @@ public class TractorBeamTurret extends BaseTurret{ //look at target if(target != null && target.within(this, range) && target.team() != team && target.type.flying && efficiency() > 0.01f){ + loops.play(shootSound, this, shootSoundVolume); + any = true; float dest = angleTo(target); rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta()); diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 4507ba345d..07f3b3ea8e 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -50,6 +50,7 @@ public abstract class Turret extends ReloadTurret{ public float recoilAmount = 1f; public float restitution = 0.02f; public float cooldown = 0.02f; + public float coolantUsage = 0.2f; public float shootCone = 8f; public float shootShake = 0f; public float xRand = 0f; @@ -109,7 +110,7 @@ public abstract class Turret extends ReloadTurret{ public void init(){ if(acceptCoolant && !consumes.has(ConsumeType.liquid)){ hasLiquids = true; - consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.2f)).update(false).boost(); + consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, coolantUsage)).update(false).boost(); } super.init(); diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index e4d2baa25c..4a0f88cd84 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -41,8 +41,8 @@ public class Conveyor extends Block implements Autotiler{ itemCapacity = 4; conveyorPlacement = true; - idleSound = Sounds.conveyor; - idleSoundVolume = 0.004f; + ambientSound = Sounds.conveyor; + ambientSoundVolume = 0.0015f; unloadable = false; noUpdateDisabled = false; } @@ -161,7 +161,7 @@ public class Conveyor extends Block implements Autotiler{ } @Override - public boolean shouldIdleSound(){ + public boolean shouldAmbientSound(){ return clogHeat <= 0.5f; } diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java index 6454cdb5bf..06d6f12068 100644 --- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java @@ -44,8 +44,8 @@ public class StackConveyor extends Block implements Autotiler{ itemCapacity = 10; conveyorPlacement = true; - idleSound = Sounds.conveyor; - idleSoundVolume = 0.004f; + ambientSound = Sounds.conveyor; + ambientSoundVolume = 0.004f; unloadable = false; } @@ -231,7 +231,7 @@ public class StackConveyor extends Block implements Autotiler{ } @Override - public boolean shouldIdleSound(){ + public boolean shouldAmbientSound(){ return false; // has no moving parts; } diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index 113617cc63..c6233c52d6 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -1,6 +1,7 @@ package mindustry.world.blocks.environment; import arc.*; +import arc.audio.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.graphics.g2d.TextureAtlas.*; @@ -10,6 +11,7 @@ import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.graphics.MultiPacker.*; import mindustry.type.*; @@ -33,7 +35,11 @@ public class Floor extends Block{ /** How many ticks it takes to drown on this. */ public float drownTime = 0f; /** Effect when walking on this floor. */ - public Effect walkEffect = Fx.ripple; + public Effect walkEffect = Fx.none; + /** Sound made when walking. */ + public Sound walkSound = Sounds.none; + /** Volume of sound made when walking. */ + public float walkSoundVolume = 0.1f, walkSoundPitchMin = 0.8f, walkSoundPitchMax = 1.2f; /** Effect displayed when drowning on this floor. */ public Effect drownUpdateEffect = Fx.bubble; /** Status effect applied when walking on. */ @@ -115,6 +121,14 @@ public class Floor extends Block{ if(decoration == Blocks.air){ decoration = content.blocks().min(b -> b instanceof Boulder && b.breakable ? mapColor.diff(b.mapColor) : Float.POSITIVE_INFINITY); } + + if(isLiquid && walkEffect == Fx.none){ + walkEffect = Fx.ripple; + } + + if(isLiquid && walkSound == Sounds.none){ + walkSound = Sounds.splash; + } } @Override diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index f5dc985d1e..dec8e52702 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -91,6 +91,11 @@ public class ImpactReactor extends PowerGenerator{ productionEfficiency = Mathf.pow(warmup, 5f); } + @Override + public float ambientVolume(){ + return warmup; + } + @Override public void draw(){ Draw.rect(bottomRegion, x, y); diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index ef4ab64b27..34d663b70f 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -66,8 +66,8 @@ public class Drill extends Block{ hasLiquids = true; liquidCapacity = 5f; hasItems = true; - idleSound = Sounds.drill; - idleSoundVolume = 0.003f; + ambientSound = Sounds.drill; + ambientSoundVolume = 0.016f; } @Override @@ -205,8 +205,8 @@ public class Drill extends Block{ } @Override - public boolean shouldIdleSound(){ - return efficiency() > 0.01f; + public boolean shouldAmbientSound(){ + return efficiency() > 0.01f && items.total() < itemCapacity; } @Override diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 051fbe9f25..39a2e2ac4f 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -9,7 +9,6 @@ import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.consumers.*; import mindustry.world.draw.*; import mindustry.world.meta.*; @@ -29,9 +28,9 @@ public class GenericCrafter extends Block{ update = true; solid = true; hasItems = true; - idleSound = Sounds.machine; + ambientSound = Sounds.machine; sync = true; - idleSoundVolume = 0.03f; + ambientSoundVolume = 0.03f; flags = EnumSet.of(BlockFlag.factory); } @@ -137,7 +136,7 @@ public class GenericCrafter extends Block{ } @Override - public boolean shouldIdleSound(){ + public boolean shouldAmbientSound(){ return cons.valid(); } diff --git a/core/src/mindustry/world/blocks/production/GenericSmelter.java b/core/src/mindustry/world/blocks/production/GenericSmelter.java index eb04cb43c7..aa61408d67 100644 --- a/core/src/mindustry/world/blocks/production/GenericSmelter.java +++ b/core/src/mindustry/world/blocks/production/GenericSmelter.java @@ -5,6 +5,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; import mindustry.annotations.Annotations.*; +import mindustry.gen.*; import mindustry.graphics.*; /** A GenericCrafter with a new glowing region drawn on top. */ @@ -14,6 +15,8 @@ public class GenericSmelter extends GenericCrafter{ public GenericSmelter(String name){ super(name); + ambientSound = Sounds.smelter; + ambientSoundVolume = 0.06f; } public class SmelterBuild extends GenericCrafterBuild{ diff --git a/core/src/mindustry/world/blocks/production/Separator.java b/core/src/mindustry/world/blocks/production/Separator.java index a44b854c13..494a2977d8 100644 --- a/core/src/mindustry/world/blocks/production/Separator.java +++ b/core/src/mindustry/world/blocks/production/Separator.java @@ -52,7 +52,7 @@ public class Separator extends Block{ public float warmup; @Override - public boolean shouldIdleSound(){ + public boolean shouldAmbientSound(){ return cons.valid(); } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index b89b1ec293..df3686baff 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -50,8 +50,8 @@ public class CoreBlock extends StorageBlock{ priority = TargetPriority.core; flags = EnumSet.of(BlockFlag.core, BlockFlag.unitModifier); unitCapModifier = 10; - activeSound = Sounds.respawning; - activeSoundVolume = 1f; + loopSound = Sounds.respawning; + loopSoundVolume = 1f; group = BlockGroup.none; } diff --git a/gradle.properties b/gradle.properties index 4347b70970..74f8398b48 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=c4f0336b9ce1bdd45fae5e9f8c3ae00afb4ad5cb +archash=3919455d82ac008743cf6794593b3379f9758a38 diff --git a/ios/src/mindustry/ios/IOSLauncher.java b/ios/src/mindustry/ios/IOSLauncher.java index 9f610e709a..e876eaa59d 100644 --- a/ios/src/mindustry/ios/IOSLauncher.java +++ b/ios/src/mindustry/ios/IOSLauncher.java @@ -16,6 +16,7 @@ import mindustry.net.*; import mindustry.ui.*; import org.robovm.apple.coregraphics.*; import org.robovm.apple.foundation.*; +import org.robovm.apple.glkit.*; import org.robovm.apple.uikit.*; import org.robovm.objc.block.*; @@ -173,7 +174,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ UINavigationController.attemptRotationToDeviceOrientation(); } }, new IOSApplicationConfiguration(){{ - + stencilFormat = GLKViewDrawableStencilFormat._8; }}); }