From e3de01b34a12f770b127ffa462371b9cac0f12b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Emir?= Date: Fri, 24 Jul 2020 00:14:38 +0200 Subject: [PATCH 1/4] Savegame, Enemy FAQ & Gamespeed checkbox Added functionality: - Save and load game - Enemy definition overview - Activate game speed via checkbox - Enable game speed from 2 to 128 in steps of [2, 4, 8, 16, 32, 64, 128] ("power of two") Feel free for review and comments --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 13 + .../logixisland/anuto/AnutoApplication.java | 7 + .../ch/logixisland/anuto/GameFactory.java | 2 +- .../anuto/business/game/GameLoader.java | 244 +++++++++++++++++- .../anuto/business/game/GameSpeed.java | 49 +++- .../anuto/business/game/SaveGameInfo.java | 71 +++++ .../business/game/SaveGameRepository.java | 31 +++ .../anuto/business/tower/TowerSelector.java | 5 + .../anuto/business/wave/WaveManager.java | 5 +- .../anuto/engine/logic/GameEngine.java | 4 + .../anuto/engine/logic/loop/GameLoop.java | 2 + .../anuto/engine/render/Renderer.java | 6 + .../logixisland/anuto/entity/enemy/Blob.java | 10 +- .../anuto/entity/enemy/EnemyProperties.java | 68 ++++- .../anuto/entity/enemy/EnemyType.java | 9 + .../logixisland/anuto/entity/enemy/Flyer.java | 9 +- .../anuto/entity/enemy/Healer.java | 9 +- .../anuto/entity/enemy/Soldier.java | 8 +- .../anuto/entity/enemy/Sprinter.java | 10 +- .../anuto/entity/enemy/WeaponType.java | 3 +- .../anuto/entity/tower/BouncingLaser.java | 2 + .../logixisland/anuto/entity/tower/Canon.java | 2 + .../anuto/entity/tower/DualCanon.java | 2 + .../anuto/entity/tower/GlueGun.java | 1 + .../anuto/entity/tower/GlueTower.java | 1 + .../anuto/entity/tower/MachineGun.java | 2 + .../anuto/entity/tower/MineLayer.java | 2 + .../anuto/entity/tower/Mortar.java | 2 + .../anuto/entity/tower/RocketLauncher.java | 2 + .../anuto/entity/tower/SimpleLaser.java | 2 + .../anuto/entity/tower/StraightLaser.java | 2 + .../anuto/entity/tower/Teleporter.java | 1 + .../logixisland/anuto/entity/tower/Tower.java | 14 + .../anuto/entity/tower/TowerProperties.java | 10 + .../ch/logixisland/anuto/util/Screenshot.java | 21 ++ .../logixisland/anuto/util/StringUtils.java | 33 ++- .../anuto/view/faq/EnemiesAdapter.java | 212 +++++++++++++++ .../anuto/view/faq/FAQActivity.java | 44 ++++ .../anuto/view/game/HeaderFragment.java | 26 +- .../anuto/view/game/MenuActivity.java | 47 ++++ .../anuto/view/game/TowerInfoFragment.java | 16 +- .../anuto/view/loadmenu/LoadMenuActivity.java | 131 ++++++++++ .../anuto/view/loadmenu/SaveGamesAdapter.java | 111 ++++++++ app/src/main/res/layout/activity_faq.xml | 24 ++ .../main/res/layout/activity_load_menu.xml | 44 ++++ app/src/main/res/layout/activity_menu.xml | 25 ++ app/src/main/res/layout/fragment_header.xml | 14 +- .../main/res/layout/fragment_tower_info.xml | 14 + app/src/main/res/layout/item_enemy.xml | 103 ++++++++ app/src/main/res/layout/item_savegame.xml | 71 +++++ app/src/main/res/values-be/strings.xml | 1 - app/src/main/res/values-ca/strings.xml | 1 - app/src/main/res/values-de-rCH/strings.xml | 1 - app/src/main/res/values-de/strings.xml | 12 +- app/src/main/res/values-el/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-sk/strings.xml | 1 - app/src/main/res/values/strings.xml | 23 +- app/src/main/res/values/theme_attributes.xml | 3 + app/src/main/res/values/theme_colour.xml | 3 + app/src/main/res/values/theme_dark.xml | 3 + app/src/main/res/values/theme_original.xml | 3 + build.gradle | 2 +- 66 files changed, 1506 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/ch/logixisland/anuto/business/game/SaveGameInfo.java create mode 100644 app/src/main/java/ch/logixisland/anuto/business/game/SaveGameRepository.java create mode 100644 app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyType.java create mode 100644 app/src/main/java/ch/logixisland/anuto/util/Screenshot.java create mode 100644 app/src/main/java/ch/logixisland/anuto/view/faq/EnemiesAdapter.java create mode 100644 app/src/main/java/ch/logixisland/anuto/view/faq/FAQActivity.java create mode 100644 app/src/main/java/ch/logixisland/anuto/view/loadmenu/LoadMenuActivity.java create mode 100644 app/src/main/java/ch/logixisland/anuto/view/loadmenu/SaveGamesAdapter.java create mode 100644 app/src/main/res/layout/activity_faq.xml create mode 100644 app/src/main/res/layout/activity_load_menu.xml create mode 100644 app/src/main/res/layout/item_enemy.xml create mode 100644 app/src/main/res/layout/item_savegame.xml diff --git a/app/build.gradle b/app/build.gradle index 2139083d..38b07836 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { minSdkVersion 17 targetSdkVersion 28 versionCode 21 - versionName "0.5-1" + versionName "0.5-2" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bdda0953..8294ee3d 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,6 +41,19 @@ android:icon="@drawable/settings" android:theme="@android:style/Theme.DeviceDefault"> + + + + + diff --git a/app/src/main/java/ch/logixisland/anuto/AnutoApplication.java b/app/src/main/java/ch/logixisland/anuto/AnutoApplication.java index 24b011fa..800885ce 100755 --- a/app/src/main/java/ch/logixisland/anuto/AnutoApplication.java +++ b/app/src/main/java/ch/logixisland/anuto/AnutoApplication.java @@ -1,19 +1,26 @@ package ch.logixisland.anuto; import android.app.Application; +import android.content.Context; public class AnutoApplication extends Application { + private static Context appContext; private static AnutoApplication sInstance; private GameFactory mGameFactory; @Override public void onCreate() { super.onCreate(); + appContext = getApplicationContext(); sInstance = this; mGameFactory = new GameFactory(getApplicationContext()); } + public static Context getContext() { + return appContext; + } + public static AnutoApplication getInstance() { return sInstance; } diff --git a/app/src/main/java/ch/logixisland/anuto/GameFactory.java b/app/src/main/java/ch/logixisland/anuto/GameFactory.java index b29da969..86a79ad9 100755 --- a/app/src/main/java/ch/logixisland/anuto/GameFactory.java +++ b/app/src/main/java/ch/logixisland/anuto/GameFactory.java @@ -130,7 +130,7 @@ private void initializeBusiness(Context context) { mMapRepository = new MapRepository(); mScoreBoard = new ScoreBoard(mGameEngine); mTowerSelector = new TowerSelector(mGameEngine, mScoreBoard); - mGameLoader = new GameLoader(context, mGameEngine, mGamePersister, mViewport, mEntityRegistry, mMapRepository); + mGameLoader = new GameLoader(context, mGameEngine, mGamePersister, mViewport, mEntityRegistry, mMapRepository, mRenderer); mHighScores = new HighScores(context, mGameEngine, mScoreBoard, mGameLoader); mGameState = new GameState(mScoreBoard, mHighScores, mTowerSelector); mTowerAging = new TowerAging(mGameEngine); diff --git a/app/src/main/java/ch/logixisland/anuto/business/game/GameLoader.java b/app/src/main/java/ch/logixisland/anuto/business/game/GameLoader.java index e5b0ab1d..1cac4bc0 100755 --- a/app/src/main/java/ch/logixisland/anuto/business/game/GameLoader.java +++ b/app/src/main/java/ch/logixisland/anuto/business/game/GameLoader.java @@ -1,17 +1,29 @@ package ch.logixisland.anuto.business.game; +import android.app.Activity; import android.content.Context; +import android.graphics.Bitmap; import android.util.Log; +import android.widget.Toast; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import ch.logixisland.anuto.AnutoApplication; import ch.logixisland.anuto.BuildConfig; +import ch.logixisland.anuto.GameFactory; import ch.logixisland.anuto.R; +import ch.logixisland.anuto.business.wave.WaveManager; import ch.logixisland.anuto.engine.logic.GameEngine; import ch.logixisland.anuto.engine.logic.entity.EntityRegistry; import ch.logixisland.anuto.engine.logic.loop.ErrorListener; @@ -20,14 +32,18 @@ import ch.logixisland.anuto.engine.logic.map.PlateauInfo; import ch.logixisland.anuto.engine.logic.map.WaveInfo; import ch.logixisland.anuto.engine.logic.persistence.GamePersister; +import ch.logixisland.anuto.engine.render.Renderer; import ch.logixisland.anuto.engine.render.Viewport; import ch.logixisland.anuto.entity.plateau.Plateau; import ch.logixisland.anuto.util.container.KeyValueStore; - +import ch.logixisland.anuto.util.iterator.Predicate; public class GameLoader implements ErrorListener { private static final String TAG = GameLoader.class.getSimpleName(); - private static final String SAVED_GAME_FILE = "saved_game.json"; + public static final String SAVED_GAME_FILE = "saved_game.json"; + public static final String SAVED_SCREENSHOT_FILE = "screen.png"; + public static final String SAVED_GAMEINFO_FILE = "gameinfo.json"; + public interface Listener { void gameLoaded(); @@ -39,18 +55,20 @@ public interface Listener { private final Viewport mViewport; private final EntityRegistry mEntityRegistry; private final MapRepository mMapRepository; + private final Renderer mRenderer; private String mCurrentMapId; private List mListeners = new CopyOnWriteArrayList<>(); public GameLoader(Context context, GameEngine gameEngine, GamePersister gamePersister, - Viewport viewport, EntityRegistry entityRegistry, MapRepository mapRepository) { + Viewport viewport, EntityRegistry entityRegistry, MapRepository mapRepository, Renderer renderer) { mContext = context; mGameEngine = gameEngine; mGamePersister = gamePersister; mViewport = viewport; mEntityRegistry = entityRegistry; mMapRepository = mapRepository; + mRenderer = renderer; mGameEngine.registerErrorListener(this); } @@ -86,39 +104,174 @@ public void execute() { } public void saveGame() { - if (mGameEngine.isThreadChangeNeeded()) { + saveGame("", false); + } + + public void saveGame(final String rootdir, final boolean userSavegame) { + if (mGameEngine.isThreadRunnging() && mGameEngine.isThreadChangeNeeded()) { mGameEngine.post(new Message() { @Override public void execute() { - saveGame(); + saveGame(rootdir, userSavegame); } }); return; } Log.i(TAG, "Saving game..."); + String fileName = userSavegame ? rootdir + File.separator + SAVED_GAME_FILE : SAVED_GAME_FILE; KeyValueStore gameState = new KeyValueStore(); mGamePersister.writeState(gameState); gameState.putInt("appVersion", BuildConfig.VERSION_CODE); gameState.putString("mapId", mCurrentMapId); try { - FileOutputStream outputStream = mContext.openFileOutput(SAVED_GAME_FILE, Context.MODE_PRIVATE); + FileOutputStream outputStream = userSavegame ? (new FileOutputStream(fileName, false)) : mContext.openFileOutput(fileName, Context.MODE_PRIVATE); gameState.toStream(outputStream); outputStream.close(); Log.i(TAG, "Game saved."); } catch (Exception e) { - mContext.deleteFile(SAVED_GAME_FILE); + mContext.deleteFile(fileName); + throw new RuntimeException("Could not save game!", e); + } + } + + public void makeNewSavegame(Activity activity) { + GameFactory daFac = AnutoApplication.getInstance().getGameFactory(); + WaveManager mWaveManager = daFac.getWaveManager(); + ScoreBoard mScoreBoard = daFac.getScoreBoard(); + + Date now = new Date(); + SimpleDateFormat dtFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + File rootdir = new File(mContext.getFilesDir() + File.separator + + "savegame" + File.separator + + getCurrentMapId() + File.separator + + dtFormat.format(now)); + rootdir.mkdirs(); + + Bitmap bitmap = mRenderer.getScreenshot(); + + try { + //FileOutputStream outputStream = mContext.openFileOutput("screen.png", Context.MODE_PRIVATE); + Log.i(TAG, "Saving screenshot..."); + + FileOutputStream outputStream = new FileOutputStream(new File(rootdir, SAVED_SCREENSHOT_FILE), false); + + int destWidth = 600; + int origWidth = bitmap.getWidth(); + + if (destWidth < origWidth) { + int origHeight = bitmap.getHeight(); + + int destHeight = (int) (((float) origHeight) / (((float) origWidth) / destWidth)); + bitmap = Bitmap.createScaledBitmap(bitmap, destWidth, destHeight, false); + } + + bitmap.compress(Bitmap.CompressFormat.PNG, 30, outputStream); + outputStream.flush(); + outputStream.close(); + Log.i(TAG, "Screenshot saved."); + + //MediaStore.Images.Media.insertImage(getContentResolver(),filename.getAbsolutePath(),filename.getName(),filename.getName()); + } catch (IOException e) { + e.printStackTrace(); throw new RuntimeException("Could not save game!", e); } + + try { + Log.i(TAG, "Creating savegame info..."); + saveGame(rootdir.getAbsolutePath(), true); + + KeyValueStore savegameInfo = new KeyValueStore(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + savegameInfo.putInt("appVersion", BuildConfig.VERSION_CODE); + savegameInfo.putString("dateTime", dateFormat.format(now)); + savegameInfo.putInt("waveNumber", mWaveManager.getWaveNumber()); + savegameInfo.putInt("remainingEnemiesCount", mWaveManager.getRemainingEnemiesCount()); + savegameInfo.putInt("score", mScoreBoard.getScore()); + savegameInfo.putInt("credits", mScoreBoard.getCredits()); + savegameInfo.putInt("lives", mScoreBoard.getLives()); + + FileOutputStream outputStream = new FileOutputStream(new File(rootdir, SAVED_GAMEINFO_FILE), false); + savegameInfo.toStream(outputStream); + outputStream.close(); + Log.i(TAG, "Savegame info saved."); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Could not save game!", e); + } + + Toast toast = (Toast) Toast.makeText(activity, activity.getString(ch.logixisland.anuto.R.string.saveGameSuccessful), Toast.LENGTH_LONG); + toast.show(); + } + + public static Predicate includedIn(final List coll) { + return new Predicate() { + @Override + public boolean apply(String value) { + return coll.contains(value); + } + }; + } + + public void deleteSavegame(File rootdir) { + File[] files = rootdir.listFiles(); + + if ((files == null) || (files.length == 0)) { + Log.d(TAG, "No Files Found"); + } else if (files.length != 3) { + Log.d(TAG, "Incorrect File Count"); + } else { + Log.d(TAG, "Size: " + files.length); + + final List ldeleteThis = Arrays.asList(SAVED_GAME_FILE, SAVED_SCREENSHOT_FILE, SAVED_GAMEINFO_FILE); + final List lfiles = new ArrayList<>(Arrays.asList(files)); + List result = new ArrayList<>(); + for (File one : lfiles) { + Log.d(TAG, "FileName:" + one.getName()); + if (ldeleteThis.contains(one.getName())) + result.add(one); + } + if (result.size() != lfiles.size()) + return; + for (File one : result) { + one.delete(); + } + rootdir.delete(); + } + } + + public KeyValueStore readSaveGame(final String fileName, final boolean userSavegame) { + KeyValueStore gameState; + + try { + gameState = getGameState(fileName, userSavegame); + } catch (FileNotFoundException e) { + Log.i(TAG, "No save game file found."); + return null; + } catch (Exception e) { + Log.i(TAG, "Could not read save game!"); + return null; + } + + if (gameState.getInt("appVersion") != BuildConfig.VERSION_CODE) { + Log.i(TAG, "App version mismatch."); + return null; + } + return gameState; } public void loadGame() { - if (mGameEngine.isThreadChangeNeeded()) { + loadGame(SAVED_GAME_FILE, false); + } + + public void loadGame(final String fileName, final boolean userSavegame) { + if (//mGameEngine.isThreadRunnging() && + mGameEngine.isThreadChangeNeeded()) { mGameEngine.post(new Message() { @Override public void execute() { - loadGame(); + loadGame(fileName, userSavegame); } }); return; @@ -128,9 +281,7 @@ public void execute() { KeyValueStore gameState; try { - FileInputStream inputStream = mContext.openFileInput(SAVED_GAME_FILE); - gameState = KeyValueStore.fromStream(inputStream); - inputStream.close(); + gameState = getGameState(fileName, userSavegame); } catch (FileNotFoundException e) { Log.i(TAG, "No save game file found."); loadMap(mMapRepository.getDefaultMapId()); @@ -149,6 +300,37 @@ public void execute() { initializeGame(mCurrentMapId, gameState); } + public KeyValueStore getGameState(final String fileName, final boolean userSavegame) throws FileNotFoundException, IOException { + Log.i(TAG, "Reading state..."); + KeyValueStore gameState; + + FileInputStream inputStream = null; + try { + inputStream = userSavegame ? new FileInputStream(fileName) : mContext.openFileInput(fileName); + gameState = KeyValueStore.fromStream(inputStream); + } finally { + if (inputStream != null) + inputStream.close(); + } + + return gameState; + } + + public void loadGameState(final KeyValueStore gameState) { + if (mGameEngine.isThreadChangeNeeded()) { + mGameEngine.post(new Message() { + @Override + public void execute() { + loadGameState(gameState); + } + }); + return; + } + + mCurrentMapId = gameState.getString("mapId"); + initializeGame(mCurrentMapId, gameState); + } + public void loadMap(final String mapId) { if (mGameEngine.isThreadChangeNeeded()) { mGameEngine.post(new Message() { @@ -212,4 +394,42 @@ public void error(Exception e, int loopCount) { } } + public boolean hasSavegames() { + File rootdir = new File(mContext.getFilesDir() + File.separator + + "savegame" + File.separator + + getCurrentMapId()); + + File[] files = rootdir.listFiles(); + + if ((files != null) && (files.length > 0)) { + return true; + } + + return false; + } + + public SaveGameRepository getSaveGameRepository() { + SaveGameRepository sgr = new SaveGameRepository(this); + File rootdir = new File(mContext.getFilesDir() + File.separator + + "savegame" + File.separator + + getCurrentMapId()); + + File[] files = rootdir.listFiles(); + + if ((files == null) || (files.length == 0)) { + Log.d(TAG, "No Files Found"); + } else { + Log.d(TAG, "Size: " + files.length); + final List lfiles = new ArrayList<>(Arrays.asList(files)); + Collections.sort(lfiles, Collections.reverseOrder()); + + for (File one : lfiles) { + Log.d(TAG, "FileName:" + one.getName()); + SaveGameInfo sgi = SaveGameInfo.createSGI(this, one); + if (sgi != null) + sgr.addSGI(sgi); + } + } + return sgr; + } } diff --git a/app/src/main/java/ch/logixisland/anuto/business/game/GameSpeed.java b/app/src/main/java/ch/logixisland/anuto/business/game/GameSpeed.java index 7689eda5..4850395f 100755 --- a/app/src/main/java/ch/logixisland/anuto/business/game/GameSpeed.java +++ b/app/src/main/java/ch/logixisland/anuto/business/game/GameSpeed.java @@ -7,8 +7,8 @@ import ch.logixisland.anuto.engine.logic.loop.Message; public class GameSpeed { - - private static final int FAST_FORWARD_SPEED = 4; + private static final int FAST_FORWARD_SPEED = 2; + private static final int MAX_FAST_FORWARD_SPEED = 128; public interface Listener { void gameSpeedChanged(); @@ -18,6 +18,7 @@ public interface Listener { private final List mListeners = new CopyOnWriteArrayList<>(); private boolean mFastForwardActive = false; + private int mFastForwardMultiplier = FAST_FORWARD_SPEED; public GameSpeed(GameEngine gameEngine) { mGameEngine = gameEngine; @@ -27,18 +28,40 @@ public boolean isFastForwardActive() { return mFastForwardActive; } - public void toggleFastForward() { + public void setFastForwardActive(final boolean active) { + if (mGameEngine.isThreadChangeNeeded()) { + mGameEngine.post(new Message() { + @Override + public void execute() { + setFastForwardActive(active); + } + }); + return; + } + + if (mFastForwardActive != active) { + mFastForwardActive = active; + updateTicks(); + } + } + + + public int fastForwardMultiplier() { + return mFastForwardMultiplier; + } + + public void cycleFastForward() { if (mGameEngine.isThreadChangeNeeded()) { mGameEngine.post(new Message() { @Override public void execute() { - toggleFastForward(); + cycleFastForward(); } }); return; } - setFastForwardActive(!mFastForwardActive); + cycleThroughMultiplier(); } public void addListener(Listener listener) { @@ -49,14 +72,20 @@ public void removeListener(Listener listener) { mListeners.remove(listener); } - private void setFastForwardActive(boolean fastForwardActive) { - if (mFastForwardActive != fastForwardActive) { - mFastForwardActive = fastForwardActive; - mGameEngine.setTicksPerLoop(mFastForwardActive ? FAST_FORWARD_SPEED : 1); + private void cycleThroughMultiplier() { + mFastForwardMultiplier = mFastForwardMultiplier < MAX_FAST_FORWARD_SPEED ? mFastForwardMultiplier * 2 : FAST_FORWARD_SPEED; + + updateTicks(); + } + + private void updateTicks() { + if (mFastForwardActive) + mGameEngine.setTicksPerLoop(mFastForwardMultiplier); + else + mGameEngine.setTicksPerLoop(1); for (Listener listener : mListeners) { listener.gameSpeedChanged(); } } - } } diff --git a/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameInfo.java b/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameInfo.java new file mode 100644 index 00000000..f252aea7 --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameInfo.java @@ -0,0 +1,71 @@ +package ch.logixisland.anuto.business.game; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import java.io.File; +import java.io.FileInputStream; + +import ch.logixisland.anuto.util.container.KeyValueStore; + +public class SaveGameInfo { + final private File mFolder; + final private KeyValueStore mSavegameState; + final private KeyValueStore mSavegameInfoStore; + final private Bitmap mCachedScreenshot; + + public static SaveGameInfo createSGI(GameLoader gameLoader, File folder) { + try { + KeyValueStore savegameState = gameLoader.readSaveGame(new File(folder, GameLoader.SAVED_GAME_FILE).getAbsolutePath(), true); + KeyValueStore savegameInfoStore = KeyValueStore.fromStream(new FileInputStream(new File(folder, GameLoader.SAVED_GAMEINFO_FILE))); + Bitmap cachedScreenshot = BitmapFactory.decodeFile(new File(folder, GameLoader.SAVED_SCREENSHOT_FILE).getAbsolutePath()); + return new SaveGameInfo(folder, savegameState, savegameInfoStore, cachedScreenshot); + } catch (Exception e) { + //throw new RuntimeException("Could not read save game!", e); + return null; + } + } + + private SaveGameInfo(File folder, KeyValueStore savegameState, KeyValueStore savegameInfoStore, Bitmap cachedScreenshot) { + mFolder = folder; + mSavegameState = savegameState; + mSavegameInfoStore = savegameInfoStore; + mCachedScreenshot = cachedScreenshot; + } + + public File getFolder() { + return mFolder; + } + + public KeyValueStore getSavegameState() { + return mSavegameState; + } + + public Bitmap getCachedScreenshot() { + return mCachedScreenshot; + } + + public String getDatetime() { + return mSavegameInfoStore.getString("dateTime"); + } + + public int getScore() { + return mSavegameInfoStore.getInt("score"); + } + + public int getWave() { + return mSavegameInfoStore.getInt("waveNumber"); + } + + public int getRemainingEnemiesCount() { + return mSavegameInfoStore.getInt("remainingEnemiesCount"); + } + + public int getCredits() { + return mSavegameInfoStore.getInt("credits"); + } + + public int getLives() { + return mSavegameInfoStore.getInt("lives"); + } +} diff --git a/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameRepository.java b/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameRepository.java new file mode 100644 index 00000000..536263d1 --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/business/game/SaveGameRepository.java @@ -0,0 +1,31 @@ +package ch.logixisland.anuto.business.game; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class SaveGameRepository { + + private final List mSavegameInfos; + private final GameLoader mGameLoader; + + public SaveGameRepository(GameLoader gameLoader) { + mSavegameInfos = new ArrayList<>(); + mGameLoader = gameLoader; + } + + public void addSGI(SaveGameInfo saveGameInfo) { + mSavegameInfos.add(saveGameInfo); + } + + public void removeSGIAt(int position) { + if(mSavegameInfos.size()>position) { + mGameLoader.deleteSavegame(mSavegameInfos.get(position).getFolder()); + mSavegameInfos.remove(position); + } + } + + public List getSavegameInfos() { + return Collections.unmodifiableList(mSavegameInfos); + } +} diff --git a/app/src/main/java/ch/logixisland/anuto/business/tower/TowerSelector.java b/app/src/main/java/ch/logixisland/anuto/business/tower/TowerSelector.java index eab58adc..d215916a 100755 --- a/app/src/main/java/ch/logixisland/anuto/business/tower/TowerSelector.java +++ b/app/src/main/java/ch/logixisland/anuto/business/tower/TowerSelector.java @@ -200,6 +200,11 @@ public void valueChanged(int value) { updateTowerInfo(); } + @Override + public void strengthChanged() { + updateTowerInfo(); + } + @Override public void creditsChanged(int credits) { if (mTowerInfo != null) { diff --git a/app/src/main/java/ch/logixisland/anuto/business/wave/WaveManager.java b/app/src/main/java/ch/logixisland/anuto/business/wave/WaveManager.java index 3f3944b0..c1d24848 100755 --- a/app/src/main/java/ch/logixisland/anuto/business/wave/WaveManager.java +++ b/app/src/main/java/ch/logixisland/anuto/business/wave/WaveManager.java @@ -85,6 +85,9 @@ public void execute() { return; } + setNextWaveReady(false); + nextWaveReadyDelayed(NEXT_WAVE_MIN_DELAY); + mGameState.gameStarted(); giveWaveRewardAndEarlyBonus(); @@ -93,8 +96,6 @@ public void execute() { updateRemainingEnemiesCount(); setWaveNumber(mWaveNumber + 1); - setNextWaveReady(false); - nextWaveReadyDelayed(NEXT_WAVE_MIN_DELAY); for (Listener listener : mListeners) { listener.waveStarted(); diff --git a/app/src/main/java/ch/logixisland/anuto/engine/logic/GameEngine.java b/app/src/main/java/ch/logixisland/anuto/engine/logic/GameEngine.java index 06df1957..b7ae35ae 100755 --- a/app/src/main/java/ch/logixisland/anuto/engine/logic/GameEngine.java +++ b/app/src/main/java/ch/logixisland/anuto/engine/logic/GameEngine.java @@ -151,6 +151,10 @@ public void setTicksPerLoop(int ticksPerLoop) { mGameLoop.setTicksPerLoop(ticksPerLoop); } + public boolean isThreadRunnging() { + return mGameLoop.isRunning(); + } + public boolean isThreadChangeNeeded() { return mGameLoop.isThreadChangeNeeded(); } diff --git a/app/src/main/java/ch/logixisland/anuto/engine/logic/loop/GameLoop.java b/app/src/main/java/ch/logixisland/anuto/engine/logic/loop/GameLoop.java index 50caf8a2..672a6c3b 100755 --- a/app/src/main/java/ch/logixisland/anuto/engine/logic/loop/GameLoop.java +++ b/app/src/main/java/ch/logixisland/anuto/engine/logic/loop/GameLoop.java @@ -53,6 +53,8 @@ public void clear() { mTickListeners.clear(); } + public boolean isRunning() { return mRunning; } + public void start() { if (!mRunning) { Log.i(TAG, "Starting game loop"); diff --git a/app/src/main/java/ch/logixisland/anuto/engine/render/Renderer.java b/app/src/main/java/ch/logixisland/anuto/engine/render/Renderer.java index 6dfc2d8b..16493316 100755 --- a/app/src/main/java/ch/logixisland/anuto/engine/render/Renderer.java +++ b/app/src/main/java/ch/logixisland/anuto/engine/render/Renderer.java @@ -1,5 +1,6 @@ package ch.logixisland.anuto.engine.render; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.view.View; @@ -9,6 +10,7 @@ import java.util.concurrent.locks.ReentrantLock; import ch.logixisland.anuto.engine.logic.loop.FrameRateLogger; +import ch.logixisland.anuto.util.Screenshot; import ch.logixisland.anuto.util.container.SafeMultiMap; import ch.logixisland.anuto.util.math.Vector2; @@ -60,6 +62,10 @@ public void invalidate() { } } + public Bitmap getScreenshot() { + return Screenshot.takeScreenshotOfRootView(mViewRef.get()); + } + public void draw(Canvas canvas) { mLock.lock(); diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Blob.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Blob.java index 99ad1006..71be0083 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Blob.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Blob.java @@ -15,16 +15,10 @@ public class Blob extends Enemy implements SpriteTransformation { - public final static String ENTITY_NAME = "blob"; + public final static String ENTITY_NAME = EnemyType.blob.name(); private final static float ANIMATION_SPEED = 1.5f; - private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder() - .setHealth(600) - .setSpeed(0.5f) - .setReward(20) - .setWeakAgainst(WeaponType.Explosive) - .setStrongAgainst(WeaponType.Bullet) - .build(); + private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder(ENTITY_NAME).build(); public static class Factory extends EntityFactory { @Override diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyProperties.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyProperties.java index 8e5fe53f..f575bfe2 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyProperties.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyProperties.java @@ -6,6 +6,7 @@ public class EnemyProperties { + private EnemyType mEnemyType; private int mHealth; private float mSpeed; private int mReward; @@ -16,27 +17,74 @@ public static class Builder { private EnemyProperties mResult = new EnemyProperties(); - public Builder setHealth(int health) { + public Builder(String entityName) { + + this.setEnemyType(EnemyType.valueOf(entityName)); + + switch (mResult.getEnemyType()) { + case soldier: + this.setHealth(300) + .setSpeed(1.0f) + .setReward(10); + break; + case blob: + this.setHealth(600) + .setSpeed(0.5f) + .setReward(20) + .setWeakAgainst(WeaponType.Explosive) + .setStrongAgainst(WeaponType.Bullet); + break; + case sprinter: + this.setHealth(200) + .setSpeed(3.0f) + .setReward(15) + .setWeakAgainst(WeaponType.Explosive) + .setStrongAgainst(WeaponType.Laser); + break; + case flyer: + this.setHealth(400) + .setSpeed(1.3f) + .setReward(30) + .setWeakAgainst(WeaponType.Laser, WeaponType.Bullet) + .setStrongAgainst(WeaponType.Glue); + break; + case healer: + this.setHealth(400) + .setSpeed(1.2f) + .setReward(30) + .setWeakAgainst(WeaponType.Laser, WeaponType.Bullet); + break; + default: + throw new RuntimeException("Unknown enemy!"); + } + } + + private Builder setEnemyType(EnemyType enemyType) { + mResult.mEnemyType = enemyType; + return this; + } + + private Builder setHealth(int health) { mResult.mHealth = health; return this; } - public Builder setSpeed(float speed) { + private Builder setSpeed(float speed) { mResult.mSpeed = speed; return this; } - public Builder setReward(int reward) { + private Builder setReward(int reward) { mResult.mReward = reward; return this; } - public Builder setWeakAgainst(WeaponType... weakAgainst) { + private Builder setWeakAgainst(WeaponType... weakAgainst) { mResult.mWeakAgainst = Arrays.asList(weakAgainst); return this; } - public Builder setStrongAgainst(WeaponType... strongAgainst) { + private Builder setStrongAgainst(WeaponType... strongAgainst) { mResult.mStrongAgainst = Arrays.asList(strongAgainst); return this; } @@ -47,13 +95,11 @@ public EnemyProperties build() { } - public int getHealth() { - return mHealth; - } + public EnemyType getEnemyType() { return mEnemyType; } - public float getSpeed() { - return mSpeed; - } + public int getHealth() { return mHealth; } + + public float getSpeed() { return mSpeed; } public int getReward() { return mReward; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyType.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyType.java new file mode 100644 index 00000000..943416be --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/EnemyType.java @@ -0,0 +1,9 @@ +package ch.logixisland.anuto.entity.enemy; + +public enum EnemyType { + soldier, + blob, + sprinter, + flyer, + healer +} diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Flyer.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Flyer.java index a89c811f..a91719bc 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Flyer.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Flyer.java @@ -15,15 +15,10 @@ public class Flyer extends Enemy implements SpriteTransformation { - public final static String ENTITY_NAME = "flyer"; + public final static String ENTITY_NAME = EnemyType.flyer.name(); private final static float ANIMATION_SPEED = 1.0f; - private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder() - .setHealth(400) - .setSpeed(1.3f) - .setReward(30) - .setWeakAgainst(WeaponType.Laser, WeaponType.Bullet) - .build(); + private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder(ENTITY_NAME).build(); public static class Factory extends EntityFactory { @Override diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Healer.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Healer.java index aa617b55..60ab2706 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Healer.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Healer.java @@ -22,7 +22,7 @@ public class Healer extends Enemy implements SpriteTransformation { - public final static String ENTITY_NAME = "healer"; + public final static String ENTITY_NAME = EnemyType.healer.name(); private final static float ANIMATION_SPEED = 1.5f; private final static float HEAL_SCALE_FACTOR = 2f; private final static float HEAL_ROTATION = 2.5f; @@ -32,12 +32,7 @@ public class Healer extends Enemy implements SpriteTransformation { private final static float HEAL_DURATION = 1.5f; private final static float HEAL_RADIUS = 0.7f; - private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder() - .setHealth(400) - .setSpeed(1.2f) - .setReward(30) - .setWeakAgainst(WeaponType.Laser, WeaponType.Bullet) - .build(); + private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder(ENTITY_NAME).build(); public static class Factory extends EntityFactory { @Override diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Soldier.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Soldier.java index 6af8f04e..d71bd815 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Soldier.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Soldier.java @@ -15,14 +15,10 @@ public class Soldier extends Enemy implements SpriteTransformation { - public final static String ENTITY_NAME = "soldier"; + public final static String ENTITY_NAME = EnemyType.soldier.name(); private final static float ANIMATION_SPEED = 1f; - private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder() - .setHealth(300) - .setSpeed(1.0f) - .setReward(10) - .build(); + private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder(ENTITY_NAME).build(); public static class Factory extends EntityFactory { @Override diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Sprinter.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Sprinter.java index ccd5447d..15b94d71 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/Sprinter.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/Sprinter.java @@ -17,16 +17,10 @@ public class Sprinter extends Enemy implements SpriteTransformation { - public final static String ENTITY_NAME = "sprinter"; + public final static String ENTITY_NAME = EnemyType.sprinter.name(); private final static float ANIMATION_SPEED = 0.7f; - private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder() - .setHealth(200) - .setSpeed(3.0f) - .setReward(15) - .setWeakAgainst(WeaponType.Explosive) - .setStrongAgainst(WeaponType.Laser) - .build(); + private final static EnemyProperties ENEMY_PROPERTIES = new EnemyProperties.Builder(ENTITY_NAME).build(); public static class Factory extends EntityFactory { @Override diff --git a/app/src/main/java/ch/logixisland/anuto/entity/enemy/WeaponType.java b/app/src/main/java/ch/logixisland/anuto/entity/enemy/WeaponType.java index 5c184780..5c24918c 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/enemy/WeaponType.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/enemy/WeaponType.java @@ -4,5 +4,6 @@ public enum WeaponType { None, Bullet, Laser, - Explosive + Explosive, + Glue } diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/BouncingLaser.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/BouncingLaser.java index e459a413..32a226ee 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/BouncingLaser.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/BouncingLaser.java @@ -41,6 +41,7 @@ public class BouncingLaser extends Tower implements SpriteTransformation { .setEnhanceReload(0.1f) .setUpgradeTowerName(ch.logixisland.anuto.entity.tower.StraightLaser.ENTITY_NAME) .setUpgradeCost(96450) + .setUpgradeLevel(2) .build(); public static class Factory extends EntityFactory { @@ -163,6 +164,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/Canon.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/Canon.java index 3d731d00..7911ca98 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/Canon.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/Canon.java @@ -45,6 +45,7 @@ public class Canon extends Tower implements SpriteTransformation { .setEnhanceReload(0.05f) .setUpgradeTowerName(DualCanon.ENTITY_NAME) .setUpgradeCost(5600) + .setUpgradeLevel(1) .build(); public static class Factory extends EntityFactory { @@ -183,6 +184,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/DualCanon.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/DualCanon.java index f54567f8..30b1e6a0 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/DualCanon.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/DualCanon.java @@ -45,6 +45,7 @@ public class DualCanon extends Tower implements SpriteTransformation { .setEnhanceReload(0.03f) .setUpgradeTowerName(MachineGun.ENTITY_NAME) .setUpgradeCost(88500) + .setUpgradeLevel(2) .build(); public static class Factory extends EntityFactory { @@ -247,6 +248,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueGun.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueGun.java index 7e1bea4d..aa663bcd 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueGun.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueGun.java @@ -45,6 +45,7 @@ public class GlueGun extends Tower implements SpriteTransformation { .setEnhanceReload(0f) .setUpgradeTowerName(Teleporter.ENTITY_NAME) .setUpgradeCost(1700) + .setUpgradeLevel(2) .build(); public static class Factory extends EntityFactory { diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueTower.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueTower.java index 8b491624..8f7a7c52 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueTower.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/GlueTower.java @@ -51,6 +51,7 @@ public class GlueTower extends Tower implements SpriteTransformation { .setEnhanceReload(0f) .setUpgradeTowerName(GlueGun.ENTITY_NAME) .setUpgradeCost(800) + .setUpgradeLevel(1) .build(); public static class Factory extends EntityFactory { diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/MachineGun.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/MachineGun.java index cc831b77..5646adb0 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/MachineGun.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/MachineGun.java @@ -43,6 +43,7 @@ public class MachineGun extends Tower implements SpriteTransformation { .setEnhanceDamage(120) .setEnhanceRange(0.05f) .setEnhanceReload(0.005f) + .setUpgradeLevel(3) .build(); public static class Factory extends EntityFactory { @@ -175,6 +176,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/MineLayer.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/MineLayer.java index f92b05a9..e5208928 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/MineLayer.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/MineLayer.java @@ -49,6 +49,7 @@ public class MineLayer extends Tower implements SpriteTransformation { .setEnhanceReload(0.05f) .setUpgradeTowerName(RocketLauncher.ENTITY_NAME) .setUpgradeCost(102850) + .setUpgradeLevel(2) .build(); public static class Factory extends EntityFactory { @@ -230,6 +231,7 @@ public List getTowerInfoValues() { properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.splash, mExplosionRadius)); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/Mortar.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/Mortar.java index 91bdb310..6e39880d 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/Mortar.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/Mortar.java @@ -46,6 +46,7 @@ public class Mortar extends Tower implements SpriteTransformation { .setEnhanceReload(0.05f) .setUpgradeTowerName(MineLayer.ENTITY_NAME) .setUpgradeCost(10000) + .setUpgradeLevel(1) .build(); public static class Factory extends EntityFactory { @@ -180,6 +181,7 @@ public List getTowerInfoValues() { properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.splash, mExplosionRadius)); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/RocketLauncher.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/RocketLauncher.java index fe7084c2..08a08630 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/RocketLauncher.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/RocketLauncher.java @@ -40,6 +40,7 @@ public class RocketLauncher extends Tower implements SpriteTransformation { .setEnhanceDamage(410) .setEnhanceRange(0.1f) .setEnhanceReload(0.07f) + .setUpgradeLevel(3) .build(); public static class Factory extends EntityFactory { @@ -180,6 +181,7 @@ public List getTowerInfoValues() { properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.splash, mExplosionRadius)); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/SimpleLaser.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/SimpleLaser.java index d3801d1d..5c283872 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/SimpleLaser.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/SimpleLaser.java @@ -40,6 +40,7 @@ public class SimpleLaser extends Tower implements SpriteTransformation { .setEnhanceReload(0.1f) .setUpgradeTowerName(ch.logixisland.anuto.entity.tower.BouncingLaser.ENTITY_NAME) .setUpgradeCost(7000) + .setUpgradeLevel(1) .build(); public static class Factory extends EntityFactory { @@ -153,6 +154,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/StraightLaser.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/StraightLaser.java index 9110482d..f3a61fd3 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/StraightLaser.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/StraightLaser.java @@ -38,6 +38,7 @@ public class StraightLaser extends Tower implements SpriteTransformation { .setEnhanceDamage(410) .setEnhanceRange(0.07f) .setEnhanceReload(0.07f) + .setUpgradeLevel(3) .build(); public static class Factory extends EntityFactory { @@ -152,6 +153,7 @@ public List getTowerInfoValues() { List properties = new ArrayList<>(); properties.add(new TowerInfoValue(R.string.damage, getDamage())); properties.add(new TowerInfoValue(R.string.reload, getReloadTime())); + properties.add(new TowerInfoValue(R.string.dps, getDamage()/getReloadTime())); properties.add(new TowerInfoValue(R.string.range, getRange())); properties.add(new TowerInfoValue(R.string.inflicted, getDamageInflicted())); return properties; diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/Teleporter.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/Teleporter.java index 531e0963..f84f400d 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/Teleporter.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/Teleporter.java @@ -41,6 +41,7 @@ public class Teleporter extends Tower implements SpriteTransformation { .setEnhanceDamage(0) .setEnhanceRange(0f) .setEnhanceReload(0.5f) + .setUpgradeLevel(3) .build(); public static class Factory extends EntityFactory { diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/Tower.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/Tower.java index b69d6e14..0c02ccae 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/Tower.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/Tower.java @@ -19,6 +19,7 @@ public abstract class Tower extends Entity { public interface Listener { void damageInflicted(float totalDamage); void valueChanged(int value); + void strengthChanged(); } private TowerProperties mTowerProperties; @@ -110,6 +111,7 @@ public boolean isBuilt() { public void setBuilt() { mBuilt = true; mReloaded = true; + updateStrength(); } public WeaponType getWeaponType() { @@ -176,6 +178,17 @@ public int getUpgradeCost() { return mTowerProperties.getUpgradeCost(); } + public int getUpgradeLevel() { + return mTowerProperties.getUpgradeLevel(); + } + + private void updateStrength() { + + for (Listener listener : mListeners) { + listener.strengthChanged(); + } + } + public void enhance() { mValue += getEnhanceCost(); mDamage += mTowerProperties.getEnhanceDamage() * (float) Math.pow(mTowerProperties.getEnhanceBase(), mLevel - 1); @@ -185,6 +198,7 @@ public void enhance() { mLevel++; mReloadTimer.setInterval(mReloadTime); + updateStrength(); } public boolean isEnhanceable() { diff --git a/app/src/main/java/ch/logixisland/anuto/entity/tower/TowerProperties.java b/app/src/main/java/ch/logixisland/anuto/entity/tower/TowerProperties.java index 1bb26fda..71b9bea3 100755 --- a/app/src/main/java/ch/logixisland/anuto/entity/tower/TowerProperties.java +++ b/app/src/main/java/ch/logixisland/anuto/entity/tower/TowerProperties.java @@ -17,6 +17,7 @@ public class TowerProperties { private float mEnhanceReload; private String mUpgradeTowerName; private int mUpgradeCost; + private int mUpgradeLevel; public static class Builder { @@ -87,6 +88,11 @@ public Builder setUpgradeCost(int upgradeCost) { return this; } + public Builder setUpgradeLevel(int upgradeLevel) { + mResult.mUpgradeLevel = upgradeLevel; + return this; + } + public TowerProperties build() { return mResult; } @@ -144,4 +150,8 @@ public int getUpgradeCost() { return mUpgradeCost; } + public int getUpgradeLevel() { + return mUpgradeLevel; + } + } diff --git a/app/src/main/java/ch/logixisland/anuto/util/Screenshot.java b/app/src/main/java/ch/logixisland/anuto/util/Screenshot.java new file mode 100644 index 00000000..54f6d8f2 --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/util/Screenshot.java @@ -0,0 +1,21 @@ +package ch.logixisland.anuto.util; + + +import android.graphics.Bitmap; +import android.view.View; + +public class Screenshot { + + public static Bitmap takeScreenshot(View v) { + v.setDrawingCacheEnabled(true); + v.buildDrawingCache(true); + Bitmap b = Bitmap.createBitmap(v.getDrawingCache()); + v.setDrawingCacheEnabled(false); + return b; + } + + public static Bitmap takeScreenshotOfRootView(View v) { + return takeScreenshot(v.getRootView()); + } + +} diff --git a/app/src/main/java/ch/logixisland/anuto/util/StringUtils.java b/app/src/main/java/ch/logixisland/anuto/util/StringUtils.java index b3655611..a6d9dcc6 100755 --- a/app/src/main/java/ch/logixisland/anuto/util/StringUtils.java +++ b/app/src/main/java/ch/logixisland/anuto/util/StringUtils.java @@ -24,23 +24,46 @@ public static String formatSuffix(float value) { public static String formatSuffix(float value, boolean integer) { String suffix = ""; - boolean big = false; + boolean usePointedFmt = false; + /*if (value >= 1e25f) { + suffix = "Y"; + value /= 1e24f; + usePointedFmt = true; + } else if (value >= 1e22f) { + suffix = "Z"; + value /= 1e21f; + usePointedFmt = true; + } else if (value >= 1e19f) { + suffix = "E"; + value /= 1e18f; + usePointedFmt = true; + } else if (value >= 1e16f) { + suffix = "P"; + value /= 1e15f; + usePointedFmt = true; + } else if (value >= 1e13f) { + suffix = "T"; + value /= 1e12f; + usePointedFmt = true; + } else*/ if (value >= 1e10f) { suffix = "G"; value /= 1e9f; - big = true; + usePointedFmt = true; } else if (value >= 1e7f) { suffix = "M"; value /= 1e6f; - big = true; + usePointedFmt = true; } else if (value >= 1e4f) { suffix = "k"; value /= 1e3f; - big = true; + usePointedFmt = true; + } else if (value < 1e2f) { + usePointedFmt = (value > 0f) && !integer; } - DecimalFormat fmt = (value < 1e2f && (!integer || big)) ? fmt1 : fmt0; + DecimalFormat fmt = (usePointedFmt) ? fmt1 : fmt0; return fmt.format(value) + suffix; } diff --git a/app/src/main/java/ch/logixisland/anuto/view/faq/EnemiesAdapter.java b/app/src/main/java/ch/logixisland/anuto/view/faq/EnemiesAdapter.java new file mode 100644 index 00000000..3e728242 --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/view/faq/EnemiesAdapter.java @@ -0,0 +1,212 @@ +package ch.logixisland.anuto.view.faq; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ch.logixisland.anuto.R; +import ch.logixisland.anuto.engine.theme.Theme; +import ch.logixisland.anuto.entity.enemy.EnemyProperties; +import ch.logixisland.anuto.entity.enemy.EnemyType; + +public class EnemiesAdapter extends BaseAdapter { + private static String sTheme; + private static Map sEnemyCache; + + private final List mEnemyProperties; + + private final WeakReference mActivityRef; + private Context appContext; + private Theme mTheme; + + public EnemiesAdapter(Activity activity, Context context, Theme theme) { + mActivityRef = new WeakReference<>(activity); + appContext = context; + mTheme = theme; + + if ((sTheme != theme.getName()) || (sEnemyCache == null)) { + sTheme = theme.getName(); + sEnemyCache = new HashMap<>(); + } + + mEnemyProperties = new ArrayList<>(); + for (EnemyType x : EnemyType.values()) { + mEnemyProperties.add(new EnemyProperties.Builder(x.name()).build()); + } + } + + static private class ViewHolder { + ImageView img_enemy; + TextView txt_name; + TextView txt_health; + TextView txt_speed; + TextView txt_reward; + TextView txt_weak_against; + TextView txt_strong_against; + + ViewHolder(View view) { + img_enemy = (ImageView) view.findViewById(R.id.img_enemy); + txt_name = (TextView) view.findViewById(R.id.txt_name); + txt_health = (TextView) view.findViewById(R.id.txt_health); + txt_speed = (TextView) view.findViewById(R.id.txt_speed); + txt_reward = (TextView) view.findViewById(R.id.txt_reward); + txt_weak_against = (TextView) view.findViewById(R.id.txt_weak_against); + txt_strong_against = (TextView) view.findViewById(R.id.txt_strong_against); + } + } + + @Override + public int getCount() { + return mEnemyProperties.size(); + } + + @Override + public Object getItem(int position) { + return mEnemyProperties.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + private Bitmap extractSingleBmp(EnemyType enemyType) { + int attrId, spriteCount, spriteId; + + switch (enemyType) { + case soldier: + attrId = R.attr.soldier; + spriteCount = 12; + spriteId = 0; + break; + case blob: + attrId = R.attr.blob; + spriteCount = 9; + spriteId = 0; + break; + case sprinter: + attrId = R.attr.sprinter; + spriteCount = 6; + spriteId = 3; + break; + case flyer: + attrId = R.attr.flyer; + spriteCount = 6; + spriteId = 4; + break; + case healer: + attrId = R.attr.healer; + spriteCount = 4; + spriteId = 0; + break; + default: + throw new RuntimeException("Unknown enemy!"); + } + + Bitmap sheet = BitmapFactory.decodeResource(appContext.getResources(), mTheme.getResourceId(attrId)); + int spriteWidth = sheet.getWidth() / spriteCount; + int spriteHeight = sheet.getHeight(); + + + float aspect = (float) spriteWidth / spriteHeight; + + float newHeight = 120; + float newWidth = newHeight * aspect; + float scaleHeight = (newHeight) / spriteHeight; + float scaleWidth = (newWidth) / spriteWidth; + Matrix matrix = new Matrix(); + matrix.postScale(scaleWidth, scaleHeight); + + Bitmap resizedBitmap = Bitmap.createBitmap(sheet, spriteWidth * spriteId, 0, spriteWidth, spriteHeight, matrix, false); + sheet.recycle(); + return resizedBitmap; + } + + + public View getView(int position, View convertView, ViewGroup parent) { + Activity activity = mActivityRef.get(); + + if (activity == null) { + return convertView; + } + + View enemyItemView; + + if (convertView == null) { + enemyItemView = LayoutInflater.from(activity).inflate(R.layout.item_enemy, parent, false); + } else { + enemyItemView = convertView; + } + EnemyProperties enemyProperties = mEnemyProperties.get(position); + ViewHolder viewHolder = new ViewHolder(enemyItemView); + String dmp; + + switch (enemyProperties.getEnemyType()) { + case soldier: + dmp = activity.getString(R.string.soldier); + break; + case blob: + dmp = activity.getString(R.string.blob); + break; + case sprinter: + dmp = activity.getString(R.string.sprinter); + break; + case flyer: + dmp = activity.getString(R.string.flyer); + break; + case healer: + dmp = activity.getString(R.string.healer); + break; + default: + throw new RuntimeException("Unknown enemy!"); + } + viewHolder.txt_name.setText(dmp); + + DecimalFormat fmt = new DecimalFormat(); + dmp = fmt.format(enemyProperties.getHealth()); + viewHolder.txt_health.setText(dmp); + + DecimalFormat df2 = new DecimalFormat("#0 '%'"); + dmp = df2.format(enemyProperties.getSpeed() * 100); + viewHolder.txt_speed.setText(dmp); + + dmp = fmt.format(enemyProperties.getReward()); + viewHolder.txt_reward.setText(dmp); + + dmp = TextUtils.join("\n", enemyProperties.getWeakAgainst()); + viewHolder.txt_weak_against.setText(dmp.length() > 0 ? dmp : activity.getString(R.string.none)); + viewHolder.txt_weak_against.setTextColor(mTheme.getColor(R.attr.weakAgainstColor)); + + + dmp = TextUtils.join("\n", enemyProperties.getStrongAgainst()); + viewHolder.txt_strong_against.setText(dmp.length() > 0 ? dmp : activity.getString(R.string.none)); + viewHolder.txt_strong_against.setTextColor(mTheme.getColor(R.attr.strongAgainstColor)); + + + if (!sEnemyCache.containsKey(enemyProperties.getEnemyType())) { + Bitmap bmp = extractSingleBmp(enemyProperties.getEnemyType()); + sEnemyCache.put(enemyProperties.getEnemyType(), bmp); + } + + viewHolder.img_enemy.setImageBitmap(sEnemyCache.get(enemyProperties.getEnemyType())); + + return enemyItemView; + } + +} diff --git a/app/src/main/java/ch/logixisland/anuto/view/faq/FAQActivity.java b/app/src/main/java/ch/logixisland/anuto/view/faq/FAQActivity.java new file mode 100644 index 00000000..0cf197da --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/view/faq/FAQActivity.java @@ -0,0 +1,44 @@ +package ch.logixisland.anuto.view.faq; + +import android.content.Context; +import android.os.Bundle; +import android.widget.GridView; + +import ch.logixisland.anuto.AnutoApplication; +import ch.logixisland.anuto.R; +import ch.logixisland.anuto.engine.theme.ActivityType; +import ch.logixisland.anuto.engine.theme.Theme; +import ch.logixisland.anuto.engine.theme.ThemeManager; +import ch.logixisland.anuto.view.AnutoActivity; + +public class FAQActivity extends AnutoActivity implements ThemeManager.Listener { + + private EnemiesAdapter mAdapter; + + private GridView grid_enemies; + private Context appContext; + private Theme mTheme; + + public FAQActivity() { + AnutoApplication app = AnutoApplication.getInstance(); + appContext = app.getApplicationContext(); + mTheme = app.getGameFactory().getGameEngine().getThemeManager().getTheme(); + + } + + @Override + protected ActivityType getActivityType() { + return ActivityType.Normal; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_faq); + + mAdapter = new EnemiesAdapter(this, appContext, mTheme); + + grid_enemies = (GridView) findViewById(R.id.grid_enemies); + grid_enemies.setAdapter(mAdapter); + } +} diff --git a/app/src/main/java/ch/logixisland/anuto/view/game/HeaderFragment.java b/app/src/main/java/ch/logixisland/anuto/view/game/HeaderFragment.java index d5cbbfa0..ee4e2d09 100755 --- a/app/src/main/java/ch/logixisland/anuto/view/game/HeaderFragment.java +++ b/app/src/main/java/ch/logixisland/anuto/view/game/HeaderFragment.java @@ -8,6 +8,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.CheckBox; import android.widget.TextView; import java.util.ArrayList; @@ -42,6 +43,7 @@ public class HeaderFragment extends AnutoFragment implements WaveManager.Listene private Button btn_next_wave; private Button btn_fast_forward; + private CheckBox checkbox_fast_active; private Button btn_menu; private Button btn_build_tower; @@ -70,11 +72,13 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, btn_next_wave = (Button) v.findViewById(R.id.btn_next_wave); btn_fast_forward = (Button) v.findViewById(R.id.btn_fast_forward); + checkbox_fast_active = (CheckBox) v.findViewById(R.id.checkbox_fast_active); btn_menu = (Button) v.findViewById(R.id.btn_menu); btn_build_tower = (Button) v.findViewById(R.id.btn_build_tower); btn_next_wave.setOnClickListener(this); btn_fast_forward.setOnClickListener(this); + checkbox_fast_active.setOnClickListener(this); btn_menu.setOnClickListener(this); btn_build_tower.setOnClickListener(this); fragment_header.setOnClickListener(this); @@ -84,7 +88,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, txt_credits.setText(getString(R.string.credits) + ": " + StringUtils.formatSuffix(mScoreBoard.getCredits())); txt_lives.setText(getString(R.string.lives) + ": " + mScoreBoard.getLives()); txt_bonus.setText(getString(R.string.bonus) + ": " + StringUtils.formatSuffix(mScoreBoard.getWaveBonus() + mScoreBoard.getEarlyBonus())); - btn_fast_forward.setText(getString(mSpeedManager.isFastForwardActive() ? R.string.fast_speed : R.string.normal_speed)); + btn_fast_forward.setText(getString(R.string.var_speed, mSpeedManager.fastForwardMultiplier())); final List towerViews = new ArrayList<>(); towerViews.add((TowerView) v.findViewById(R.id.view_tower_1)); @@ -135,24 +139,36 @@ public void onDetach() { public void onClick(View v) { if (v == fragment_header) { mTowerSelector.selectTower(null); + return; } if (v == btn_next_wave) { mWaveManager.startNextWave(); + return; } if (v == btn_fast_forward) { - mSpeedManager.toggleFastForward(); + mSpeedManager.cycleFastForward(); + return; + } + + if (v == checkbox_fast_active) { + boolean checked = checkbox_fast_active.isChecked(); + if (checked != mSpeedManager.isFastForwardActive()) + mSpeedManager.setFastForwardActive(checked); + return; } if (v == btn_menu) { mTowerSelector.selectTower(null); Intent intent = new Intent(getActivity(), MenuActivity.class); startActivity(intent); + return; } if (v == btn_build_tower) { mTowerSelector.toggleTowerBuildView(); + return; } } @@ -226,7 +242,11 @@ public void gameSpeedChanged() { mHandler.post(new Runnable() { @Override public void run() { - btn_fast_forward.setText(getString(mSpeedManager.isFastForwardActive() ? R.string.fast_speed : R.string.normal_speed)); + btn_fast_forward.setText(getString(R.string.var_speed, mSpeedManager.fastForwardMultiplier())); + + boolean checked = mSpeedManager.isFastForwardActive(); + if (checked != checkbox_fast_active.isChecked()) + checkbox_fast_active.setChecked(checked); } }); } diff --git a/app/src/main/java/ch/logixisland/anuto/view/game/MenuActivity.java b/app/src/main/java/ch/logixisland/anuto/view/game/MenuActivity.java index 1f1f70c2..4f0b86c2 100755 --- a/app/src/main/java/ch/logixisland/anuto/view/game/MenuActivity.java +++ b/app/src/main/java/ch/logixisland/anuto/view/game/MenuActivity.java @@ -10,8 +10,11 @@ import ch.logixisland.anuto.GameFactory; import ch.logixisland.anuto.R; import ch.logixisland.anuto.business.game.GameLoader; +import ch.logixisland.anuto.business.game.GameState; import ch.logixisland.anuto.engine.theme.ActivityType; import ch.logixisland.anuto.view.AnutoActivity; +import ch.logixisland.anuto.view.faq.FAQActivity; +import ch.logixisland.anuto.view.loadmenu.LoadMenuActivity; import ch.logixisland.anuto.view.map.ChangeMapActivity; import ch.logixisland.anuto.view.setting.SettingsActivity; @@ -19,19 +22,26 @@ public class MenuActivity extends AnutoActivity implements View.OnClickListener, private static final int REQUEST_CHANGE_MAP = 1; private static final int REQUEST_SETTINGS = 2; + private static final int REQUEST_LOADMENU = 3; + private static final int REQUEST_FAQ = 3; private final GameLoader mGameLoader; + private final GameState mGameState; private View activity_menu; private View menu_layout; private Button btn_restart; private Button btn_change_map; + private Button btn_quicksave; + private Button btn_loadmenu; + private Button btn_faq; private Button btn_settings; public MenuActivity() { GameFactory factory = AnutoApplication.getInstance().getGameFactory(); mGameLoader = factory.getGameLoader(); + mGameState = factory.getGameState(); } @Override @@ -46,6 +56,9 @@ protected void onCreate(Bundle savedInstanceState) { btn_restart = (Button) findViewById(R.id.btn_restart); btn_change_map = (Button) findViewById(R.id.btn_change_map); + btn_quicksave = (Button) findViewById(R.id.btn_quicksave); + btn_loadmenu = (Button) findViewById(R.id.btn_loadmenu); + btn_faq = (Button) findViewById(R.id.btn_faq); btn_settings = (Button) findViewById(R.id.btn_settings); activity_menu = findViewById(R.id.activity_menu); @@ -53,7 +66,12 @@ protected void onCreate(Bundle savedInstanceState) { btn_restart.setOnClickListener(this); btn_change_map.setOnClickListener(this); + btn_quicksave.setOnClickListener(this); + btn_loadmenu.setOnClickListener(this); + btn_faq.setOnClickListener(this); btn_settings.setOnClickListener(this); + btn_quicksave.setEnabled(mGameState.isGameStarted()); + btn_loadmenu.setEnabled(mGameLoader.hasSavegames()); activity_menu.setOnTouchListener(this); menu_layout.setOnTouchListener(this); @@ -64,16 +82,37 @@ public void onClick(View view) { if (view == btn_restart) { mGameLoader.restart(); finish(); + return; } if (view == btn_change_map) { Intent intent = new Intent(this, ChangeMapActivity.class); startActivityForResult(intent, REQUEST_CHANGE_MAP); + return; + } + + if (view == btn_quicksave) { + mGameLoader.makeNewSavegame(this); + btn_loadmenu.setEnabled(true); + return; + } + + if(view == btn_loadmenu) { + Intent intent = new Intent(this, LoadMenuActivity.class); + startActivityForResult(intent, REQUEST_LOADMENU); + return; + } + + if (view == btn_faq) { + Intent intent = new Intent(this, FAQActivity.class); + startActivityForResult(intent, REQUEST_FAQ); + return; } if (view == btn_settings) { Intent intent = new Intent(this, SettingsActivity.class); startActivityForResult(intent, REQUEST_SETTINGS); + return; } } @@ -99,6 +138,14 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { finish(); } + if (requestCode == REQUEST_LOADMENU) { + finish(); + } + + if (requestCode == REQUEST_FAQ) { + finish(); + } + if (requestCode == REQUEST_SETTINGS) { finish(); } diff --git a/app/src/main/java/ch/logixisland/anuto/view/game/TowerInfoFragment.java b/app/src/main/java/ch/logixisland/anuto/view/game/TowerInfoFragment.java index 0cf444de..c359d3cd 100755 --- a/app/src/main/java/ch/logixisland/anuto/view/game/TowerInfoFragment.java +++ b/app/src/main/java/ch/logixisland/anuto/view/game/TowerInfoFragment.java @@ -9,6 +9,7 @@ import android.widget.Button; import android.widget.TextView; +import java.text.DecimalFormat; import java.util.List; import ch.logixisland.anuto.AnutoApplication; @@ -31,8 +32,8 @@ public class TowerInfoFragment extends AnutoFragment implements View.OnClickList private Handler mHandler; private TextView txt_level; - private TextView[] txt_property = new TextView[5]; - private TextView[] txt_property_text = new TextView[5]; + private TextView[] txt_property = new TextView[6]; + private TextView[] txt_property_text = new TextView[6]; private Button btn_strategy; private Button btn_lock_target; @@ -58,6 +59,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa txt_property[2] = (TextView) v.findViewById(R.id.txt_property3); txt_property[3] = (TextView) v.findViewById(R.id.txt_property4); txt_property[4] = (TextView) v.findViewById(R.id.txt_property5); + txt_property[5] = (TextView) v.findViewById(R.id.txt_property6); TextView txt_level_text = (TextView) v.findViewById(R.id.txt_level_text); txt_level_text.setText(getResources().getString(R.string.level) + ":"); @@ -67,6 +69,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa txt_property_text[2] = (TextView) v.findViewById(R.id.txt_property_text3); txt_property_text[3] = (TextView) v.findViewById(R.id.txt_property_text4); txt_property_text[4] = (TextView) v.findViewById(R.id.txt_property_text5); + txt_property_text[5] = (TextView) v.findViewById(R.id.txt_property_text6); btn_strategy = (Button) v.findViewById(R.id.btn_strategy); btn_lock_target = (Button) v.findViewById(R.id.btn_lock_target); @@ -117,22 +120,27 @@ public void onDetach() { public void onClick(View v) { if (v == btn_strategy) { mTowerControl.cycleTowerStrategy(); + return; } if (v == btn_lock_target) { mTowerControl.toggleLockTarget(); + return; } if (v == btn_enhance) { mTowerControl.enhanceTower(); + return; } if (v == btn_upgrade) { mTowerControl.upgradeTower(); + return; } if (v == btn_sell) { mTowerControl.sellTower(); + return; } } @@ -180,7 +188,9 @@ private void hide() { } private void refresh(TowerInfo towerInfo) { - txt_level.setText(towerInfo.getLevel() + " / " + towerInfo.getLevelMax()); + DecimalFormat fmt = new DecimalFormat(); + String level = fmt.format(towerInfo.getLevel()) + " / " + fmt.format(towerInfo.getLevelMax()); + txt_level.setText(level); List properties = towerInfo.getProperties(); for (int i = 0; i < properties.size(); i++) { diff --git a/app/src/main/java/ch/logixisland/anuto/view/loadmenu/LoadMenuActivity.java b/app/src/main/java/ch/logixisland/anuto/view/loadmenu/LoadMenuActivity.java new file mode 100644 index 00000000..349bd68b --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/view/loadmenu/LoadMenuActivity.java @@ -0,0 +1,131 @@ +package ch.logixisland.anuto.view.loadmenu; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.Log; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ImageView; + +import ch.logixisland.anuto.AnutoApplication; +import ch.logixisland.anuto.GameFactory; +import ch.logixisland.anuto.R; +import ch.logixisland.anuto.business.game.GameLoader; +import ch.logixisland.anuto.business.game.SaveGameRepository; +import ch.logixisland.anuto.view.AnutoActivity; + +import static android.content.ContentValues.TAG; + +public class LoadMenuActivity extends AnutoActivity implements AdapterView.OnItemClickListener, + ViewTreeObserver.OnScrollChangedListener { + + public static int CONTEXT_MENU__DELETE_ID = 0; + + private final GameLoader mGameLoader; + private final SaveGameRepository mSaveGameRepository; + + private SaveGamesAdapter mAdapter; + + private ImageView arrow_up; + private ImageView arrow_down; + private GridView grid_savegames; + + + public LoadMenuActivity() { + GameFactory factory = AnutoApplication.getInstance().getGameFactory(); + mGameLoader = factory.getGameLoader(); + mSaveGameRepository = mGameLoader.getSaveGameRepository(); + } + + @Override + protected ch.logixisland.anuto.engine.theme.ActivityType getActivityType() { + return ch.logixisland.anuto.engine.theme.ActivityType.Normal; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_load_menu); + + mAdapter = new SaveGamesAdapter(this, mSaveGameRepository); + + arrow_up = (ImageView) findViewById(R.id.arrow_up); + arrow_down = (ImageView) findViewById(R.id.arrow_down); + + grid_savegames = (GridView) findViewById(R.id.grid_savegames); + grid_savegames.setOnItemClickListener(this); + grid_savegames.getViewTreeObserver().addOnScrollChangedListener(this); + grid_savegames.post(new Runnable() { + @Override + public void run() { + updateArrowVisibility(); + } + }); + grid_savegames.setAdapter(mAdapter); + registerForContextMenu(grid_savegames); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + mGameLoader.loadGameState(mAdapter.getItem(position).getSavegameState()); + + finish(); + } + + public void onCreateContextMenu(android.view.ContextMenu menu, View v, android.view.ContextMenu.ContextMenuInfo menuInfo) { + menu.add(0, CONTEXT_MENU__DELETE_ID, 0, R.string.delete); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + + if (item.getItemId() == CONTEXT_MENU__DELETE_ID) { + final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); + Log.d(TAG, "Item Timestamp at POSITION:" + mAdapter.getItem(info.position).getDatetime()); + new AlertDialog.Builder(this) + .setTitle(R.string.delete) + .setMessage(R.string.deleteConfirmation) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int whichButton) { + mSaveGameRepository.removeSGIAt(info.position); + mAdapter.notifyDataSetChanged(); + } + }) + .setNegativeButton(android.R.string.no, null).show(); + return true; + } + return false; + } + + @Override + public void onScrollChanged() { + updateArrowVisibility(); + } + + private void updateArrowVisibility() { + if (grid_savegames.getChildCount() <= 0) { + arrow_up.setVisibility(View.INVISIBLE); + arrow_down.setVisibility(View.INVISIBLE); + return; + } + + if (grid_savegames.getFirstVisiblePosition() == 0) { + arrow_up.setVisibility(grid_savegames.getChildAt(0).getTop() < -10 ? View.VISIBLE : View.INVISIBLE); + } else { + arrow_up.setVisibility(grid_savegames.getFirstVisiblePosition() > 0 ? View.VISIBLE : View.INVISIBLE); + } + + if (grid_savegames.getLastVisiblePosition() == mAdapter.getCount() - 1) { + arrow_down.setVisibility(grid_savegames.getChildAt(grid_savegames.getChildCount() - 1).getBottom() > grid_savegames.getHeight() + 10 ? View.VISIBLE : View.INVISIBLE); + } else { + arrow_down.setVisibility(grid_savegames.getLastVisiblePosition() < mAdapter.getCount() - 1 ? View.VISIBLE : View.INVISIBLE); + } + } +} diff --git a/app/src/main/java/ch/logixisland/anuto/view/loadmenu/SaveGamesAdapter.java b/app/src/main/java/ch/logixisland/anuto/view/loadmenu/SaveGamesAdapter.java new file mode 100644 index 00000000..2147038b --- /dev/null +++ b/app/src/main/java/ch/logixisland/anuto/view/loadmenu/SaveGamesAdapter.java @@ -0,0 +1,111 @@ +package ch.logixisland.anuto.view.loadmenu; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ch.logixisland.anuto.R; +import ch.logixisland.anuto.business.game.SaveGameInfo; +import ch.logixisland.anuto.business.game.SaveGameRepository; +import ch.logixisland.anuto.util.StringUtils; + +public class SaveGamesAdapter extends BaseAdapter { + + private static final Map sThumbCache = new HashMap<>(); + + private final WeakReference mActivityRef; + private final List mSaveGameInfos; + + SaveGamesAdapter(Activity activity, SaveGameRepository saveGameRepository) { + mActivityRef = new WeakReference<>(activity); + mSaveGameInfos = saveGameRepository.getSavegameInfos(); + } + + static private class ViewHolder { + ImageView img_thumb; + TextView txt_datetime; + TextView txt_score; + TextView txt_waveNumber; + TextView txt_remainingEnemiesCount; + TextView txt_credits; + TextView txt_lives; + + ViewHolder(View view) { + img_thumb = (ImageView) view.findViewById(R.id.img_thumb); + txt_datetime = (TextView) view.findViewById(R.id.txt_datetime); + txt_score = (TextView) view.findViewById(R.id.txt_score); + txt_waveNumber = (TextView) view.findViewById(R.id.txt_waveNumber); + txt_remainingEnemiesCount = (TextView) view.findViewById(R.id.txt_remainingEnemiesCount); + txt_credits = (TextView) view.findViewById(R.id.txt_credits); + txt_lives = (TextView) view.findViewById(R.id.txt_lives); + } + } + + @Override + public int getCount() { + return mSaveGameInfos.size(); + } + + @Override + public SaveGameInfo getItem(int position) { + return mSaveGameInfos.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + public void removeItem(int position) { + mSaveGameInfos.remove(position); + this.notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Activity activity = mActivityRef.get(); + + if (activity == null) { + return convertView; + } + + View sgItemView; + + if (convertView == null) { + sgItemView = LayoutInflater.from(activity).inflate(R.layout.item_savegame, parent, false); + } else { + sgItemView = convertView; + } + + Resources resources = activity.getResources(); + SaveGameInfo saveGameInfo = mSaveGameInfos.get(position); + ViewHolder viewHolder = new ViewHolder(sgItemView); + + viewHolder.txt_datetime.setText(saveGameInfo.getDatetime()); + String tmp = resources.getString(R.string.score) + ": " + StringUtils.formatSuffix(saveGameInfo.getScore()); + viewHolder.txt_score.setText(tmp); + tmp = resources.getString(R.string.wave) + ": " + StringUtils.formatSuffix(saveGameInfo.getWave()); + viewHolder.txt_waveNumber.setText(tmp); + tmp = resources.getString(R.string.remainingEnemiesCount) + ": " + StringUtils.formatSuffix(saveGameInfo.getRemainingEnemiesCount()); + viewHolder.txt_remainingEnemiesCount.setText(tmp); + tmp = resources.getString(R.string.credits) + ": " + StringUtils.formatSuffix(saveGameInfo.getCredits()); + viewHolder.txt_credits.setText(tmp); + tmp = resources.getString(R.string.lives) + ": " + StringUtils.formatSuffix(saveGameInfo.getLives()); + viewHolder.txt_lives.setText(tmp); + + viewHolder.img_thumb.setImageBitmap(saveGameInfo.getCachedScreenshot()); + + return sgItemView; + } +} diff --git a/app/src/main/res/layout/activity_faq.xml b/app/src/main/res/layout/activity_faq.xml new file mode 100644 index 00000000..7b4de309 --- /dev/null +++ b/app/src/main/res/layout/activity_faq.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/app/src/main/res/layout/activity_load_menu.xml b/app/src/main/res/layout/activity_load_menu.xml new file mode 100644 index 00000000..3ef7ad49 --- /dev/null +++ b/app/src/main/res/layout/activity_load_menu.xml @@ -0,0 +1,44 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/activity_menu.xml b/app/src/main/res/layout/activity_menu.xml index b473bf42..f8b8a064 100755 --- a/app/src/main/res/layout/activity_menu.xml +++ b/app/src/main/res/layout/activity_menu.xml @@ -33,6 +33,20 @@ android:maxLines="1" android:text="@string/restart"/> +