diff --git a/.gitignore b/.gitignore index b199017043..09bdd6ec4b 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ steam_appid.txt /annotations/src/main/resources/META-INF/services /core/assets/version.properties /core/assets/locales +/core/assets/cache/ /ios/src/mindustry/gen/ /core/src/mindustry/gen/ ios/robovm.properties 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/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/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/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 0c1df7f711..eb960f5537 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 c3558ca58a..abaffecd40 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/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index 0ef3ece228..1bda2c4b81 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..a4b229b147 100644 --- a/core/src/mindustry/audio/SoundLoop.java +++ b/core/src/mindustry/audio/SoundLoop.java @@ -18,11 +18,12 @@ 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){ id = sound.loop(sound.calcVolume(x, y) * volume * baseVolume, 1f, sound.calcPan(x, y)); + Log.info("playing, id = @", id); } }else{ //fade the sound in or out @@ -36,6 +37,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 11c45f097d..5e3de00a61 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -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; @@ -432,7 +434,8 @@ public class UnitTypes implements ContentList{ reload = 320f; recoil = 0f; - shootSound = Sounds.laser; + chargeSound = Sounds.lasercharge2; + shootSound = Sounds.beam; continuous = true; cooldownTime = 200f; @@ -493,6 +496,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; @@ -500,7 +506,6 @@ public class UnitTypes implements ContentList{ x = y = 0; reload = 350f; recoil = 0f; - shootSound = Sounds.laser; cooldownTime = 350f; @@ -636,7 +641,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; @@ -659,6 +664,7 @@ public class UnitTypes implements ContentList{ rotate = true; x = 4f; y = 3f; + shootSound = Sounds.sap; bullet = new SapBulletType(){{ sapStrength = 0.8f; @@ -723,6 +729,7 @@ public class UnitTypes implements ContentList{ y = 8f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("spiroct-weapon"){{ reload = 15f; @@ -730,6 +737,7 @@ public class UnitTypes implements ContentList{ y = 6f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("spiroct-weapon"){{ reload = 23f; @@ -737,6 +745,7 @@ public class UnitTypes implements ContentList{ y = 0f; rotate = true; bullet = sapper; + shootSound = Sounds.sap; }}, new Weapon("large-purple-mount"){{ y = -7f; @@ -746,7 +755,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; @@ -844,7 +853,7 @@ public class UnitTypes implements ContentList{ recoil = 10f; rotateSpeed = 1f; ejectEffect = Fx.casing3; - shootSound = Sounds.shootBig; + shootSound = Sounds.artillery; rotate = true; occlusion = 30f; @@ -1254,6 +1263,7 @@ public class UnitTypes implements ContentList{ weapons.add( new Weapon("heal-weapon-mount"){{ + shootSound = Sounds.lasershoot; reload = 25f; x = 8f; y = -6f; @@ -1261,6 +1271,7 @@ public class UnitTypes implements ContentList{ bullet = Bullets.healBulletBig; }}, new Weapon("heal-weapon-mount"){{ + shootSound = Sounds.lasershoot; reload = 15f; x = 4f; y = 5f; @@ -1580,7 +1591,7 @@ public class UnitTypes implements ContentList{ inaccuracy = 7f; ejectEffect = Fx.none; shake = 3f; - shootSound = Sounds.shootBig; + shootSound = Sounds.missile; xRand = 8f; shotDelay = 1f; @@ -1661,6 +1672,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 acadd51df7..6e6592e42f 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -476,10 +476,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 00f0bc78e8..c6709d2259 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/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 3f7db0e3ee..2d78be6229 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/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/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 3cba913fbb..814f2b72bf 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.*; @@ -33,7 +34,7 @@ import static mindustry.Vars.*; abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged{ @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. */ @@ -105,6 +111,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 5df9db4a60..a861c81060 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -95,7 +95,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(){ @@ -176,7 +176,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/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 9222072828..45dbfb6bea 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -604,15 +604,8 @@ 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 = baseSpeed * Mathf.lerp(1f, unit.type.canBoost ? unit.type.boostMultiplier : 1f, unit.elevation) * strafePenalty; + float speed = unit.realSpeed() * strafePenalty; float xa = Core.input.axis(Binding.move_x); float ya = Core.input.axis(Binding.move_y); boolean boosted = (unit instanceof Mechc && unit.isFlying()); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index ad57dc154a..3e1aadd2f7 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -857,15 +857,7 @@ 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 = baseSpeed * Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty; + float speed = unit.realSpeed() * strafePenalty; float range = unit.hasWeapons() ? unit.range() : 0f; float bulletSpeed = unit.hasWeapons() ? type.weapons.first().bullet.speed : 0f; float mouseAngle = unit.angleTo(unit.aimX(), unit.aimY()); @@ -906,7 +898,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 e207ae99dc..327eb9b609 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -468,7 +468,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); @@ -482,7 +482,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 32356ff838..dce9953e98 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.*; @@ -450,111 +448,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 e){ - e.printStackTrace(); - } - 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. */ @@ -585,8 +483,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/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/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 52e1f7a160..33bd49b0d7 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -199,17 +199,19 @@ public class SettingsMenuDialog extends SettingsDialog{ t.row(); t.button("@crash.export", Icon.upload, style, () -> { - if(settings.getDataDirectory().child("crashes").list().length == 0){ + if(settings.getDataDirectory().child("crashes").list().length == 0 && !settings.getDataDirectory().child("last_log.txt").exists()){ ui.showInfo("@crash.none"); }else{ - platform.showFileChooser(false, "txt", file -> { - StringBuilder out = new StringBuilder(); - for(Fi fi : settings.getDataDirectory().child("crashes").list()){ - out.append(fi.name()).append("\n\n").append(fi.readString()).append("\n"); - } - file.writeString(out.toString()); - app.post(() -> ui.showInfo("@crash.exported")); - }); + if(ios){ + Fi logs = tmpDirectory.child("logs.txt"); + logs.writeString(getLogs()); + platform.shareFile(logs); + }else{ + platform.showFileChooser(false, "txt", file -> { + file.writeString(getLogs()); + app.post(() -> ui.showInfo("@crash.exported")); + }); + } } }).marginLeft(4); }); @@ -243,6 +245,21 @@ public class SettingsMenuDialog extends SettingsDialog{ addSettings(); } + String getLogs(){ + Fi log = settings.getDataDirectory().child("last_log.txt"); + + StringBuilder out = new StringBuilder(); + for(Fi fi : settings.getDataDirectory().child("crashes").list()){ + out.append(fi.name()).append("\n\n").append(fi.readString()).append("\n"); + } + + if(log.exists()){ + out.append("\nlast log:\n").append(log.readString()); + } + + return out.toString(); + } + void rebuildMenu(){ menu.clearChildren(); 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/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index cefdfa6887..166063f828 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -88,6 +88,7 @@ public class ConstructBlock extends Block{ } Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size); + if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); } static boolean shouldPlay(){ @@ -121,7 +122,6 @@ public class ConstructBlock extends Block{ } Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); - if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); } @Override 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..fa7d52b918 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.002f; 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 0b7ade7752..74f8398b48 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=3bd087c3dac6e220c31e0d33067557af5f382d05 +archash=3919455d82ac008743cf6794593b3379f9758a38 diff --git a/ios/robovm.xml b/ios/robovm.xml index 29869ea7ef..e792b258a8 100644 --- a/ios/robovm.xml +++ b/ios/robovm.xml @@ -39,7 +39,6 @@ z - libs/libObjectAL.a libs/libarc.a libs/libarc-freetype.a @@ -48,7 +47,7 @@ OpenGLES QuartzCore CoreGraphics - OpenAL + CoreAudio AudioToolbox AVFoundation