diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index d46ab5729b..4792bd6d89 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -34,6 +34,7 @@ public class AndroidLauncher extends AndroidApplication{ public static final int PERMISSION_REQUEST_CODE = 1; boolean doubleScaleTablets = true; FileChooser chooser; + Runnable permCallback; @Override protected void onCreate(Bundle savedInstanceState){ @@ -66,6 +67,24 @@ public class AndroidLauncher extends AndroidApplication{ } } + @Override + public void requestExternalPerms(Runnable callback){ + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ + callback.run(); + }else{ + permCallback = callback; + ArrayList perms = new ArrayList<>(); + if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ + perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } + requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE); + } + } + @Override public void shareFile(FileHandle file){ } @@ -123,7 +142,11 @@ public class AndroidLauncher extends AndroidApplication{ if(i != PackageManager.PERMISSION_GRANTED) return; } if(chooser != null){ - chooser.show(); + Core.app.post(chooser::show); + } + if(permCallback != null){ + Core.app.post(permCallback); + permCallback = null; } } } diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index ef34a0b15c..77e5eb7971 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -157,6 +157,8 @@ cancel = Cancel openlink = Open Link copylink = Copy Link back = Back +classic.export = Export Classic Data +classic.export.text = Classic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Are you sure you want to quit? quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] loading = [accent]Loading... @@ -435,7 +437,7 @@ blocks.shots = Shots blocks.reload = Shots/Second blocks.ammo = Ammo - +bar.drilltierreq = Better Drill Required bar.drillspeed = Drill Speed: {0}/s bar.efficiency = Efficiency: {0}% bar.powerbalance = Power: {0}/s diff --git a/core/assets/sounds/build.ogg b/core/assets/sounds/build.ogg new file mode 100644 index 0000000000..97155ae9e0 Binary files /dev/null and b/core/assets/sounds/build.ogg differ diff --git a/core/assets/sounds/explosionbig.ogg b/core/assets/sounds/explosionbig.ogg new file mode 100644 index 0000000000..b521732f79 Binary files /dev/null and b/core/assets/sounds/explosionbig.ogg differ diff --git a/core/assets/sounds/splash.ogg b/core/assets/sounds/splash.ogg index 2b7b68cccb..0ca516e674 100644 Binary files a/core/assets/sounds/splash.ogg and b/core/assets/sounds/splash.ogg differ diff --git a/core/assets/sounds/wave.ogg b/core/assets/sounds/wave.ogg new file mode 100644 index 0000000000..f5af16677e Binary files /dev/null and b/core/assets/sounds/wave.ogg differ diff --git a/core/src/io/anuke/mindustry/content/UnitTypes.java b/core/src/io/anuke/mindustry/content/UnitTypes.java index 06e90d4606..367786db79 100644 --- a/core/src/io/anuke/mindustry/content/UnitTypes.java +++ b/core/src/io/anuke/mindustry/content/UnitTypes.java @@ -102,6 +102,7 @@ public class UnitTypes implements ContentList{ weapon = new Weapon("bomber"){{ reload = 12f; ejectEffect = Fx.none; + shootSound = Sounds.explosion; bullet = new BombBulletType(2f, 3f, "clear"){ { hitEffect = Fx.pulverize; @@ -233,6 +234,7 @@ public class UnitTypes implements ContentList{ shotDelay = 3; ejectEffect = Fx.shellEjectMedium; bullet = Bullets.standardThoriumBig; + shootSound = Sounds.shootBig; }}; }}; @@ -251,6 +253,7 @@ public class UnitTypes implements ContentList{ roundrobin = true; ejectEffect = Fx.shellEjectSmall; bullet = Bullets.standardCopper; + shootSound = Sounds.shoot; }}; }}; @@ -274,7 +277,7 @@ public class UnitTypes implements ContentList{ inaccuracy = 40f; ignoreRotation = true; bullet = Bullets.bombExplosive; - shootSound = Sounds.release; + shootSound = Sounds.none; }}; }}; diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 0e7758b361..3e95afb413 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.core; -import io.anuke.arc.Application.*; import io.anuke.arc.*; +import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; @@ -39,11 +39,11 @@ public class Control implements ApplicationListener{ public final Saves saves; public final MusicControl music; public final Tutorial tutorial; + public InputHandler input; private Interval timer = new Interval(2); private boolean hiscore = false; private boolean wasPaused = false; - private InputHandler input; public Control(){ batch = new SpriteBatch(); @@ -117,6 +117,7 @@ public class Control implements ApplicationListener{ hiscore = true; world.getMap().setHighScore(state.wave); } + Sounds.wave.play(); }); Events.on(GameOverEvent.class, event -> { @@ -177,8 +178,39 @@ public class Control implements ApplicationListener{ ui.hudfrag.showToast(Core.bundle.format("zone.config.complete", e.zone.configureWave)); }); - if(Core.app.getType() == ApplicationType.Android){ + if(android){ Sounds.empty.loop(0f, 1f, 0f); + + checkClassicData(); + } + } + + //checks for existing 3.5 app data, android only + public void checkClassicData(){ + try{ + if(files.local("mindustry-maps").exists() || files.local("mindustry-saves").exists()){ + settings.getBoolOnce("classic-backup-check", () -> { + app.post(() -> app.post(() -> ui.showConfirm("$classic.export", "$classic.export.text", () -> { + try{ + Platform.instance.requestExternalPerms(() -> { + FileHandle external = files.external("MindustryClassic"); + if(files.local("mindustry-maps").exists()){ + files.local("mindustry-maps").copyTo(external); + } + + if(files.local("mindustry-saves").exists()){ + files.local("mindustry-saves").copyTo(external); + } + }); + }catch(Exception e){ + e.printStackTrace(); + ui.showError(Strings.parseException(e, true)); + } + }))); + }); + } + }catch(Throwable t){ + t.printStackTrace(); } } @@ -202,10 +234,6 @@ public class Control implements ApplicationListener{ Core.input.addProcessor(input); } - public InputHandler input(){ - return input; - } - public void playMap(Map map, Rules rules){ ui.loadAnd(() -> { logic.reset(); diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 85026c9335..d66697c25e 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -39,6 +39,11 @@ public abstract class Platform{ }); } + /** Request external read/write perms. Run callback when complete.*/ + public void requestExternalPerms(Runnable callback){ + callback.run(); + } + /** Update discord RPC. */ public void updateRPC(){ } diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index aa1b80021c..ee10191570 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -214,7 +214,7 @@ public class UI implements ApplicationListener{ Core.scene.add(menuGroup); Core.scene.add(hudGroup); - control.input().getFrag().build(hudGroup); + control.input.getFrag().build(hudGroup); hudfrag.build(hudGroup); menufrag.build(menuGroup); chatfrag.container().build(hudGroup); diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 595a094097..7734838d3d 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.entities.traits; +import io.anuke.annotations.Annotations.*; import io.anuke.arc.Core; import io.anuke.arc.Events; import io.anuke.arc.collection.Array; @@ -206,7 +207,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ * Return the build requests currently active, or the one at the top of the queue. * May return null. */ - default BuildRequest buildRequest(){ + default @Nullable BuildRequest buildRequest(){ return buildQueue().size == 0 ? null : buildQueue().first(); } diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 4b13713aa7..e1b7b94b19 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -19,7 +19,7 @@ import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.input.Binding; +import io.anuke.mindustry.input.*; import io.anuke.mindustry.input.InputHandler.PlaceDraw; import io.anuke.mindustry.io.TypeIO; import io.anuke.mindustry.net.Net; @@ -70,7 +70,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ private Tile mining; private Vector2 movement = new Vector2(); private boolean moved; - private SoundLoop sound = new SoundLoop(Sounds.thruster, 2f); + private SoundLoop boostSound = new SoundLoop(Sounds.thruster, 2f), buildSound = new SoundLoop(Sounds.build, 0.75f); //endregion @@ -133,7 +133,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ @Override public void removed(){ - sound.stop(); + boostSound.stop(); + buildSound.stop(); } @Override @@ -513,7 +514,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ destructTime = 0f; } - sound.update(x, y, isBoosting && !isDead() && !mech.flying); + boostSound.update(x, y, isBoosting && !isDead() && !mech.flying); + BuildRequest request = buildRequest(); + buildSound.update(request == null ? x : request.x * tilesize, request == null ? y : request.y * tilesize, isBuilding() && (Mathf.within(request.x * tilesize, request.y * tilesize, x, y, placeDistance) || state.isEditor())); if(isDead()){ isBoosting = false; @@ -606,7 +609,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ movement.x += xa * speed; } - Vector2 vec = Core.input.mouseWorld(control.input().getMouseX(), control.input().getMouseY()); + Vector2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY()); pointerX = vec.x; pointerY = vec.y; updateShooting(); @@ -629,7 +632,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp); } }else{ - float angle = control.input().mouseAngle(x, y); + float angle = control.input.mouseAngle(x, y); this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp); } } @@ -758,8 +761,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } }else if(isShooting()){ - Vector2 vec = Core.input.mouseWorld(control.input().getMouseX(), - control.input().getMouseY()); + Vector2 vec = Core.input.mouseWorld(control.input.getMouseX(), + control.input.getMouseY()); pointerX = vec.x; pointerY = vec.y; diff --git a/core/src/io/anuke/mindustry/game/SoundLoop.java b/core/src/io/anuke/mindustry/game/SoundLoop.java index b470713ead..6dc6f2cae8 100644 --- a/core/src/io/anuke/mindustry/game/SoundLoop.java +++ b/core/src/io/anuke/mindustry/game/SoundLoop.java @@ -33,6 +33,7 @@ public class SoundLoop{ if(volume <= 0.001f){ sound.stop(id); id = -1; + return; } } sound.setPan(id, sound.calcPan(x, y), sound.calcVolume(x, y) * volume * baseVolume); diff --git a/core/src/io/anuke/mindustry/game/Tutorial.java b/core/src/io/anuke/mindustry/game/Tutorial.java index 41229723e8..d8dd13c664 100644 --- a/core/src/io/anuke/mindustry/game/Tutorial.java +++ b/core/src/io/anuke/mindustry/game/Tutorial.java @@ -105,6 +105,7 @@ public class Tutorial{ void draw(){ outline("category-production"); outline("block-mechanical-drill"); + outline("confirmplace"); } }, blockinfo(() -> event("blockinfo")){ diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index ef137acc60..fda9f63e52 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -27,7 +27,7 @@ public class OverlayRenderer{ private float buildFadeTime; public void drawBottom(){ - InputHandler input = control.input(); + InputHandler input = control.input; if(!input.isDrawing() || player.isDead()) return; @@ -64,7 +64,7 @@ public class OverlayRenderer{ if(player.isDead()) return; //dead players don't draw - InputHandler input = control.input(); + InputHandler input = control.input; //draw config selected block if(input.frag.config.isShown()){ diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 3d982065e9..1fbb707451 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -289,7 +289,7 @@ public class MobileInput extends InputHandler implements GestureListener{ removals.addAll(selection); selection.clear(); selecting = false; - }).visible(() -> !selection.isEmpty()); + }).visible(() -> !selection.isEmpty()).name("confirmplace"); Core.scene.table(t -> { t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu)); diff --git a/core/src/io/anuke/mindustry/type/Weapon.java b/core/src/io/anuke/mindustry/type/Weapon.java index 5ed8ff79ac..180bb2fad5 100644 --- a/core/src/io/anuke/mindustry/type/Weapon.java +++ b/core/src/io/anuke/mindustry/type/Weapon.java @@ -54,7 +54,7 @@ public class Weapon{ /** whether shooter rotation is ignored when shooting. */ public boolean ignoreRotation = false; - public Sound shootSound = Sounds.shoot; + public Sound shootSound = Sounds.pew; public TextureRegion region; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 45e107ca24..95fdf6e4cf 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -193,6 +193,20 @@ public class SettingsMenuDialog extends SettingsDialog{ } }); + if(android && (Core.files.local("mindustry-maps").exists() || Core.files.local("mindustry-saves").exists())){ + game.pref(new Setting(){ + @Override + public void add(SettingsTable table){ + table.addButton("$classic.export", () -> { + control.checkClassicData(); + }).size(220f, 60f).pad(6).left(); + table.add(); + table.row(); + hide(); + } + }); + } + graphics.sliderPref("uiscale", 100, 25, 400, 25, s -> { if(Core.graphics.getFrameId() > 10){ Log.info("changed"); diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java index ae759f010f..cdf0921d68 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java @@ -53,7 +53,7 @@ public class PlacementFragment extends Fragment{ public PlacementFragment(){ Events.on(WorldLoadEvent.class, event -> { Core.app.post(() -> { - control.input().block = null; + control.input.block = null; rebuild(); }); }); @@ -119,7 +119,7 @@ public class PlacementFragment extends Fragment{ full.bottom().right().visible(() -> ui.hudfrag.shown()); full.table(frame -> { - InputHandler input = control.input(); + InputHandler input = control.input; //rebuilds the category table with the correct recipes Runnable rebuildCategory = () -> { @@ -336,8 +336,8 @@ public class PlacementFragment extends Fragment{ } //block currently selected - if(control.input().block != null){ - toDisplay = control.input().block; + if(control.input.block != null){ + toDisplay = control.input.block; } //block hovered on in build menu diff --git a/core/src/io/anuke/mindustry/world/blocks/ItemSelection.java b/core/src/io/anuke/mindustry/world/blocks/ItemSelection.java index 4c9fbeab91..2f42b7ab68 100644 --- a/core/src/io/anuke/mindustry/world/blocks/ItemSelection.java +++ b/core/src/io/anuke/mindustry/world/blocks/ItemSelection.java @@ -28,7 +28,7 @@ public class ItemSelection{ for(Item item : items){ if(!data.isUnlocked(item) && world.isZone()) continue; - ImageButton button = cont.addImageButton("whiteui", "clear-toggle-trans", 24, () -> control.input().frag.config.hideConfig()).group(group).get(); + ImageButton button = cont.addImageButton("whiteui", "clear-toggle-trans", 24, () -> control.input.frag.config.hideConfig()).group(group).get(); button.changed(() -> consumer.accept(button.isChecked() ? item : null)); button.getStyle().imageUp = new TextureRegionDrawable(item.icon(Icon.medium)); button.update(() -> button.setChecked(holder.get() == item)); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java index 95881ec265..a910a20920 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java @@ -1,21 +1,18 @@ package io.anuke.mindustry.world.blocks.power; -import io.anuke.arc.Core; -import io.anuke.arc.graphics.Blending; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.graphics.g2d.Draw; -import io.anuke.arc.graphics.g2d.TextureRegion; -import io.anuke.arc.math.Mathf; +import io.anuke.arc.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.math.*; import io.anuke.arc.util.*; -import io.anuke.mindustry.content.Fx; -import io.anuke.mindustry.entities.Damage; -import io.anuke.mindustry.entities.Effects; -import io.anuke.mindustry.entities.type.TileEntity; -import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.ui.Bar; -import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockStat; -import io.anuke.mindustry.world.meta.StatUnit; +import io.anuke.mindustry.content.*; +import io.anuke.mindustry.entities.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.meta.*; import java.io.*; @@ -130,6 +127,8 @@ public class ImpactReactor extends PowerGenerator{ if(entity.warmup < 0.4f) return; + Sounds.explosionbig.at(tile); + Effects.shake(6f, 16f, tile.worldx(), tile.worldy()); Effects.effect(Fx.impactShockwave, tile.worldx(), tile.worldy()); for(int i = 0; i < 6; i++){ diff --git a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java index ae26382ea8..0fd084f9b9 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java @@ -10,6 +10,7 @@ import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Damage; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.type.TileEntity; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; @@ -118,6 +119,8 @@ public class NuclearReactor extends PowerGenerator{ public void onDestroyed(Tile tile){ super.onDestroyed(tile); + Sounds.explosionbig.at(tile); + NuclearReactorEntity entity = tile.entity(); int fuel = entity.items.get(consumes.get(ConsumeType.item).items[0].item); diff --git a/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java b/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java index 19c7bb2779..cc6c7b1a98 100644 --- a/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java +++ b/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java @@ -83,10 +83,10 @@ public class LiquidSource extends Block{ for(int i = 0; i < items.size; i++){ final int f = i; - ImageButton button = cont.addImageButton("clear", "clear-toggle-trans", 24, () -> control.input().frag.config.hideConfig()).size(38).group(group).get(); + ImageButton button = cont.addImageButton("clear", "clear-toggle-trans", 24, () -> control.input.frag.config.hideConfig()).size(38).group(group).get(); button.changed(() -> { Call.setLiquidSourceLiquid(null, tile, button.isChecked() ? items.get(f) : null); - control.input().frag.config.hideConfig(); + control.input.frag.config.hideConfig(); lastLiquid = items.get(f); }); button.getStyle().imageUp = new TextureRegionDrawable(items.get(i).iconRegion);