From 1315782808d6e2c3cdf170fd7356a8e1ce5f2f4f Mon Sep 17 00:00:00 2001 From: dtookey Date: Sun, 11 Oct 2020 18:48:09 -0400 Subject: [PATCH] Initial Commit --- .gitignore | 9 + app/.gitignore | 1 + app/build.gradle | 55 ++++++ app/proguard-rules.pro | 21 +++ .../gc/necrogame/ExampleInstrumentedTest.kt | 24 +++ app/src/main/AndroidManifest.xml | 23 +++ .../java/com/gc/necrogame/MainActivity.kt | 67 +++++++ .../java/com/gc/necrogame/Purchaseable.kt | 21 +++ .../java/com/gc/necrogame/StateComponent.kt | 8 + .../java/com/gc/necrogame/game/GameModel.kt | 145 +++++++++++++++ .../gc/necrogame/game/GameStateUpdateable.kt | 7 + .../com/gc/necrogame/game/Progressable.kt | 13 ++ .../com/gc/necrogame/game/PurchaseQuantity.kt | 21 +++ .../com/gc/necrogame/game/resources/Soul.kt | 27 +++ .../com/gc/necrogame/game/workers/Shade.kt | 70 +++++++ .../ui/battleground/BattlegroundFragment.kt | 38 ++++ .../ui/battleground/BattlegroundViewModel.kt | 23 +++ .../ui/graveyard/GraveyardFragment.kt | 125 +++++++++++++ .../ui/graveyard/GraveyardViewModel.kt | 42 +++++ .../com/gc/necrogame/ui/lair/LairFragment.kt | 41 +++++ .../com/gc/necrogame/ui/lair/LairViewModel.kt | 22 +++ .../drawable-v24/ic_launcher_foreground.xml | 30 +++ .../res/drawable/ic_dashboard_black_24dp.xml | 9 + app/src/main/res/drawable/ic_headstone.xml | 78 ++++++++ .../main/res/drawable/ic_home_black_24dp.xml | 9 + .../res/drawable/ic_launcher_background.xml | 170 +++++++++++++++++ .../drawable/ic_notifications_black_24dp.xml | 9 + app/src/main/res/layout/activity_main.xml | 33 ++++ .../main/res/layout/fragment_battleground.xml | 22 +++ .../main/res/layout/fragment_graveyard.xml | 84 +++++++++ app/src/main/res/layout/fragment_lair.xml | 31 ++++ app/src/main/res/menu/bottom_nav_menu.xml | 19 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes .../main/res/navigation/mobile_navigation.xml | 25 +++ app/src/main/res/res_raw/headstone.svg | 106 +++++++++++ app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 13 ++ app/src/main/res/values/styles.xml | 10 + .../java/com/gc/necrogame/ExampleUnitTest.kt | 17 ++ build.gradle | 26 +++ gradle.properties | 21 +++ gradlew | 172 ++++++++++++++++++ gradlew.bat | 84 +++++++++ settings.gradle | 2 + 56 files changed, 1794 insertions(+) create mode 100644 .gitignore create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/gc/necrogame/ExampleInstrumentedTest.kt create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/gc/necrogame/MainActivity.kt create mode 100644 app/src/main/java/com/gc/necrogame/Purchaseable.kt create mode 100644 app/src/main/java/com/gc/necrogame/StateComponent.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/GameModel.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/GameStateUpdateable.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/Progressable.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/PurchaseQuantity.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/resources/Soul.kt create mode 100644 app/src/main/java/com/gc/necrogame/game/workers/Shade.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundFragment.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundViewModel.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardFragment.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardViewModel.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/lair/LairFragment.kt create mode 100644 app/src/main/java/com/gc/necrogame/ui/lair/LairViewModel.kt create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_dashboard_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_headstone.xml create mode 100644 app/src/main/res/drawable/ic_home_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_notifications_black_24dp.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/fragment_battleground.xml create mode 100644 app/src/main/res/layout/fragment_graveyard.xml create mode 100644 app/src/main/res/layout/fragment_lair.xml create mode 100644 app/src/main/res/menu/bottom_nav_menu.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/navigation/mobile_navigation.xml create mode 100644 app/src/main/res/res_raw/headstone.svg create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/com/gc/necrogame/ExampleUnitTest.kt create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6df708 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +.idea/* +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f66ed76 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,55 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.1" + + defaultConfig { + applicationId "com.gc.necrogame" + minSdkVersion 29 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.2' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.2.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.2' + implementation 'androidx.navigation:navigation-fragment:2.3.0' + implementation 'androidx.navigation:navigation-ui:2.3.0' + implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + +// imported libraries + implementation 'com.google.code.gson:gson:2.8.6' + + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/gc/necrogame/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/gc/necrogame/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..d5f84c4 --- /dev/null +++ b/app/src/androidTest/java/com/gc/necrogame/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.gc.necrogame + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.gc.necrogame", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d5f7b49 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/MainActivity.kt b/app/src/main/java/com/gc/necrogame/MainActivity.kt new file mode 100644 index 0000000..e5774bb --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/MainActivity.kt @@ -0,0 +1,67 @@ +package com.gc.necrogame + +import android.content.Context +import android.os.Bundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.setupActionBarWithNavController +import androidx.navigation.ui.setupWithNavController +import com.gc.necrogame.game.GameModel +import com.google.android.material.bottomnavigation.BottomNavigationView +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch + + +class MainActivity : AppCompatActivity() { + + var gameState = GameModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + val navView: BottomNavigationView = findViewById(R.id.nav_view) + + val navController = findNavController(R.id.nav_host_fragment) + // Passing each menu ID as a set of Ids because each + // menu should be considered as top level destinations. + val appBarConfiguration = AppBarConfiguration( + setOf( + R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications + ) + ) + setupActionBarWithNavController(navController, appBarConfiguration) + navView.setupWithNavController(navController) + launchGameThread() + } + + private fun launchGameThread() { + + GlobalScope.launch { // launch a new coroutine in background and continue + gameState.updateLoop() + Log.i(MainActivity::class.simpleName, "Leaving Game Loop") + } + + } + + override fun onPause() { + super.onPause() + gameState.running = false + val fOut = applicationContext.openFileOutput("state.json", Context.MODE_PRIVATE) + GameModel.saveState(fOut, gameState) + } + + override fun onResume() { + super.onResume() + gameState.running = false + try { + val fIn = applicationContext.openFileInput("state.json") + gameState = GameModel.loadState(fIn) + } catch (e: Exception) { + Log.e(MainActivity::class.simpleName, "Error reading saved game state", e) + gameState = GameModel() + } + launchGameThread() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/Purchaseable.kt b/app/src/main/java/com/gc/necrogame/Purchaseable.kt new file mode 100644 index 0000000..c0abadb --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/Purchaseable.kt @@ -0,0 +1,21 @@ +package com.gc.necrogame + +import com.gc.necrogame.game.GameModel +import com.gc.necrogame.game.Resources +import com.gc.necrogame.game.PurchaseQuantity + +interface Purchasable { + fun getCost(state: GameModel, pQty: PurchaseQuantity): Resources + + fun purchase(state: GameModel, pQty: PurchaseQuantity) + + fun canPurchase(state: GameModel, pQty: PurchaseQuantity): Boolean { + val cost = getCost(state, pQty) + val heldResources = state.resources + val haveAdequate = + (heldResources.soul - cost.soul) >= 0 && (heldResources.flesh - cost.flesh) >= 0 + return haveAdequate + } + + fun maxPurcahsable(state: GameModel): Double +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/StateComponent.kt b/app/src/main/java/com/gc/necrogame/StateComponent.kt new file mode 100644 index 0000000..c044ca6 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/StateComponent.kt @@ -0,0 +1,8 @@ +package com.gc.necrogame + +import com.gc.necrogame.game.GameModel + +interface StateComponent { + fun getQty(state: GameModel): Double + fun updateQty(state: GameModel, qty: Double) +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/GameModel.kt b/app/src/main/java/com/gc/necrogame/game/GameModel.kt new file mode 100644 index 0000000..53e9054 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/GameModel.kt @@ -0,0 +1,145 @@ +package com.gc.necrogame.game + +import android.util.Log +import com.gc.necrogame.game.resources.Soul +import com.gc.necrogame.game.workers.Shade +import com.google.gson.Gson +import kotlinx.coroutines.delay +import java.io.InputStream +import java.io.InputStreamReader +import java.io.OutputStream +import java.io.OutputStreamWriter +import java.time.Instant +import java.util.concurrent.locks.ReentrantLock + + +class GameModel( + val workers: WorkerCount = WorkerCount(), + val fighters: FighterCount = FighterCount(), + val resources: Resources = Resources() +) { + + init{ + + Log.i(GameModel::class.simpleName, "New gameModel") + } + @Transient + var lastInstant: Instant = Instant.now() + + @Transient + private val updaters = ArrayList() + + @Transient + val updaterLock = ReentrantLock() + + @Transient + var running = true + + suspend fun updateLoop() { + Log.i(GameModel::class.simpleName, "Starting game update loop") + while (running) { + val now = Instant.now() + updaterLock.lock() + try { + updateWorkers(now) + updateFighters(now) + updateResources(now) + for (updater in updaters) { + updater.update(this, now) + } + } finally { + updaterLock.unlock() + } + val durToSleep = now.toEpochMilli() + baseTimeStep - Instant.now().toEpochMilli() + lastInstant = now + if (durToSleep > 0) delay(durToSleep) + } + } + + fun updateWorkers(now: Instant) { + Shade.update(this, now) + } + + fun updateFighters(now: Instant) { + + } + + fun updateResources(now: Instant) { + Soul.update(this, now) + } + + fun removeUpdater(u: GameStateUpdateable) { + updaterLock.lock() + try { + updaters.remove(u) + } finally { + updaterLock.unlock() + } + } + + fun addUpdater(u: GameStateUpdateable) { + updaterLock.lock() + try { + updaters.add(u) + } finally { + updaterLock.unlock() + } + } + + companion object { + var baseTimeStep = 15L + + fun loadState(fIn: InputStream): GameModel { + val gson = Gson() + try { + val isr = InputStreamReader(fIn) + val raw = isr.readText() + val savedModel = gson.fromJson(raw, GameModel::class.java) + return GameModel( + workers = savedModel.workers, + fighters = savedModel.fighters, + resources = savedModel.resources + ) + } catch (e: java.lang.Exception) { + Log.e(GameModel::class.simpleName, "Error reading game state from file", e) + } + return GameModel() + } + + fun saveState(fOut: OutputStream, gameState: GameModel) { + val gson = Gson() + try { + val state = gson.toJson(gameState, GameModel::class.java) + val writer = OutputStreamWriter(fOut) + writer.write(state) + writer.flush() + writer.close() + fOut.close() + } catch (e: Exception) { + Log.e(GameModel::class.simpleName, "error writing game state to file", e) + } + } + } +} + +data class WorkerCount( + var shades: Double = 0.0, + var skeletons: Double = 0.0, + var abominations: Double = 0.0 +) + +data class FighterCount( + var zombies: Double = 0.0, + var vampires: Double = 0.0, + var hulks: Double = 0.0 +) + +data class Resources( + var soul: Double = 10.0, + var flesh: Double = 0.0 +){ + fun subtract(r: Resources){ + this.soul -= r.soul + this.flesh -= r.flesh + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/GameStateUpdateable.kt b/app/src/main/java/com/gc/necrogame/game/GameStateUpdateable.kt new file mode 100644 index 0000000..2388d41 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/GameStateUpdateable.kt @@ -0,0 +1,7 @@ +package com.gc.necrogame.game + +import java.time.Instant + +interface GameStateUpdateable { + fun update(state: GameModel, now: Instant) +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/Progressable.kt b/app/src/main/java/com/gc/necrogame/game/Progressable.kt new file mode 100644 index 0000000..57f0da6 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/Progressable.kt @@ -0,0 +1,13 @@ +package com.gc.necrogame.game + +import java.time.Instant + +interface Progressable { + val lastStep: Instant + val step: Long + + fun getProgress(now: Instant): Long { + val diff = now.toEpochMilli() - lastStep.toEpochMilli() + return step - diff + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/PurchaseQuantity.kt b/app/src/main/java/com/gc/necrogame/game/PurchaseQuantity.kt new file mode 100644 index 0000000..c875faa --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/PurchaseQuantity.kt @@ -0,0 +1,21 @@ +package com.gc.necrogame.game + +import com.gc.necrogame.Purchasable + +enum class PurchaseQuantity { + ONE, + TEN, + HUNDRED, + MAX; + + companion object { + fun getAmount(q: PurchaseQuantity, purchasable: Purchasable, state: GameModel): Double { + return when (q) { + ONE -> 1.0 + TEN -> 10.0 + HUNDRED -> 100.0 + MAX -> purchasable.maxPurcahsable(state) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/resources/Soul.kt b/app/src/main/java/com/gc/necrogame/game/resources/Soul.kt new file mode 100644 index 0000000..c0143d9 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/resources/Soul.kt @@ -0,0 +1,27 @@ +package com.gc.necrogame.game.resources + +import com.gc.necrogame.StateComponent +import com.gc.necrogame.game.GameModel +import com.gc.necrogame.game.GameStateUpdateable +import java.time.Instant + +object Soul : GameStateUpdateable, StateComponent { + + private var step = 1000L + + private var lastStep = Instant.now() + + override fun update(state: GameModel, now: Instant) { + + } + + override fun getQty(state: GameModel): Double { + return state.resources.soul + } + + override fun updateQty(state: GameModel, qty: Double) { + state.resources.soul = qty + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/game/workers/Shade.kt b/app/src/main/java/com/gc/necrogame/game/workers/Shade.kt new file mode 100644 index 0000000..d975027 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/game/workers/Shade.kt @@ -0,0 +1,70 @@ +package com.gc.necrogame.game.workers + +import com.gc.necrogame.Purchasable +import com.gc.necrogame.StateComponent +import com.gc.necrogame.game.* +import com.gc.necrogame.game.resources.Soul +import java.time.Instant +import kotlin.math.floor +import kotlin.math.ln +import kotlin.math.pow + +object Shade : GameStateUpdateable, Progressable, Purchasable, StateComponent { + + override val step = 1000L + override var lastStep: Instant = Instant.now() + + override fun update(state: GameModel, now: Instant) { + val time = lastStep.toEpochMilli() + step + val then = now.toEpochMilli() + + if (time < then) { + val old = Soul.getQty(state) + val new = old + getQty(state) + Soul.updateQty(state, new) + + lastStep = now + } + } + + override fun getCost(state: GameModel, pQty: PurchaseQuantity): Resources { + val pqty = PurchaseQuantity.getAmount(pQty, Shade, state) + val qty: Double = if (pqty == 0.0) { + 1.0 + } else { + pqty + } + val totalShades = getQty(state) + qty + return Resources(soul = getSpecificCost(totalShades)) + } + + private fun getSpecificCost(qty: Double): Double { + return 1 + 1.05.pow(qty) + } + + override fun purchase(state: GameModel, pQty: PurchaseQuantity) { + val cost = getCost(state, pQty) + val qty = PurchaseQuantity.getAmount(pQty, Shade, state) + state.resources.subtract(cost) + updateQty(state, getQty(state) + qty) + } + + override fun maxPurcahsable(state: GameModel): Double { + val margin = + floor(20.4959 * ln(Soul.getQty(state) - 1.0)) - getQty(state) + return if (margin < 1.0) { + 0.0 + } else { + margin + } + } + + override fun getQty(state: GameModel): Double { + return state.workers.shades + } + + override fun updateQty(state: GameModel, qty: Double) { + state.workers.shades = qty + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundFragment.kt b/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundFragment.kt new file mode 100644 index 0000000..7a0a52b --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundFragment.kt @@ -0,0 +1,38 @@ +package com.gc.necrogame.ui.battleground + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.gc.necrogame.MainActivity +import com.gc.necrogame.R + +class BattlegroundFragment : Fragment() { + + private lateinit var graveyardViewModel: BattlegroundViewModel + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + graveyardViewModel = + ViewModelProvider(this).get(BattlegroundViewModel::class.java) + val root = inflater.inflate(R.layout.fragment_battleground, container, false) + val textView: TextView = root.findViewById(R.id.text_notifications) + graveyardViewModel.text.observe(viewLifecycleOwner, Observer { + textView.text = it + }) + (activity as MainActivity).gameState.addUpdater(graveyardViewModel) + return root + } + + override fun onDestroy() { + super.onDestroy() + (activity as MainActivity).gameState.removeUpdater(graveyardViewModel) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundViewModel.kt b/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundViewModel.kt new file mode 100644 index 0000000..0435cbd --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/battleground/BattlegroundViewModel.kt @@ -0,0 +1,23 @@ +package com.gc.necrogame.ui.battleground + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.gc.necrogame.game.GameModel +import com.gc.necrogame.game.GameStateUpdateable +import com.gc.necrogame.ui.lair.LairViewModel +import java.time.Instant + +class BattlegroundViewModel : ViewModel(), GameStateUpdateable { + + private val _text = MutableLiveData().apply { + value = "This is notifications Fragment" + } + + val text: LiveData = _text + + override fun update(state: GameModel, now: Instant) { +// TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardFragment.kt b/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardFragment.kt new file mode 100644 index 0000000..ba0e033 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardFragment.kt @@ -0,0 +1,125 @@ +package com.gc.necrogame.ui.graveyard + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.ProgressBar +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.gc.necrogame.MainActivity +import com.gc.necrogame.R +import com.gc.necrogame.game.PurchaseQuantity +import com.gc.necrogame.game.workers.Shade + +class GraveyardFragment : Fragment() { + + val mActivity: MainActivity + get() { + return (activity as MainActivity) + } + + private lateinit var graveyardViewModel: GraveyardViewModel + + private var purchaseQty = PurchaseQuantity.ONE + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + graveyardViewModel = ViewModelProvider(this).get(GraveyardViewModel::class.java) + val root = inflater.inflate(R.layout.fragment_graveyard, container, false) + + initObservers(root, graveyardViewModel) + initButtonListeners(root) + updateButtonTexts(root) + updateButtonAvailability(root) + (activity as MainActivity).gameState.addUpdater(graveyardViewModel) + return root + } + + + private fun initObservers(v: View, graveyardViewModel: GraveyardViewModel) { + val shadeCountView = v.findViewById(R.id.text_shade) + graveyardViewModel.shadeCount.observe(viewLifecycleOwner, Observer { + shadeCountView.text = getString(R.string.shades_d, it) + }) + + val shadeProgress = v.findViewById(R.id.shade_progress) + graveyardViewModel.shadeProgress.observe(viewLifecycleOwner, { + shadeProgress.max = Shade.step.toInt() + shadeProgress.progress = it + }) + + val soulCountView = v.findViewById(R.id.graveyard_resource_soul_count) + graveyardViewModel.soulCount.observe(viewLifecycleOwner, { + soulCountView.text = getString(R.string.souls_d, it) + if (purchaseQty == PurchaseQuantity.MAX) { + updateButtonTexts(requireView()) + } + updateButtonAvailability(requireView()) + + }) + + } + + private fun initButtonListeners(v: View) { + val buyShadeButton: Button = v.findViewById(R.id.shade_buy_button) + buyShadeButton.setOnClickListener(purchaseShadeHandler) + + val buyQtyButton: Button = v.findViewById(R.id.graveyard_purchase_qty) + buyQtyButton.setOnClickListener(purchaseQtyHandler) + } + + private val purchaseQtyHandler = View.OnClickListener { + val values = PurchaseQuantity.values() + val currentIndex = PurchaseQuantity.values().indexOf(purchaseQty) + purchaseQty = values[(currentIndex + 1) % values.size] + + updateButtonTexts(requireView()) + updateButtonAvailability(requireView()) + } + + private val purchaseShadeHandler = View.OnClickListener { + val state = mActivity.gameState + if (Shade.canPurchase(state, purchaseQty)) { + Shade.purchase(state, purchaseQty) + updateButtonTexts(requireView()) + updateButtonAvailability(requireView()) + } + } + + private fun updateButtonTexts(v: View) { + val state = mActivity.gameState + + val buyQtyButton: Button = v.findViewById(R.id.graveyard_purchase_qty) + buyQtyButton.text = when (purchaseQty) { + PurchaseQuantity.ONE -> getString(R.string.purchase_one) + PurchaseQuantity.TEN -> getString(R.string.purchase_ten) + PurchaseQuantity.HUNDRED -> getString(R.string.purchase_hundred) + PurchaseQuantity.MAX -> getString(R.string.purchase_max) + } + + + val shadeBuybutton: Button = v.findViewById(R.id.shade_buy_button) + val shadeQty = PurchaseQuantity.getAmount(purchaseQty, Shade, state) + val cost = Shade.getCost(state, purchaseQty) + shadeBuybutton.text = getString(R.string.buy_d, shadeQty, cost.soul) + } + + private fun updateButtonAvailability(v: View) { + val state = mActivity.gameState + val shadeBuybutton: Button = v.findViewById(R.id.shade_buy_button) + shadeBuybutton.isEnabled = Shade.canPurchase(state, purchaseQty) + } + + override fun onDestroy() { + super.onDestroy() + (activity as MainActivity).gameState.removeUpdater(graveyardViewModel) + } + +} + diff --git a/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardViewModel.kt b/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardViewModel.kt new file mode 100644 index 0000000..4b3a843 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/graveyard/GraveyardViewModel.kt @@ -0,0 +1,42 @@ +package com.gc.necrogame.ui.graveyard + +import android.os.Handler +import android.os.Looper +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.gc.necrogame.game.GameModel +import com.gc.necrogame.game.GameStateUpdateable +import com.gc.necrogame.game.resources.Soul +import com.gc.necrogame.game.workers.Shade +import java.time.Instant + +class GraveyardViewModel : ViewModel(), GameStateUpdateable { + + val ui = Handler(Looper.getMainLooper()) + + private val _shadeCount = MutableLiveData().apply { + value = 0.0 + } + val shadeCount: LiveData = _shadeCount + + private val _soulCount = MutableLiveData().apply { + value = 0.0 + } + val soulCount: LiveData = _soulCount + + private val _shadeProgress = MutableLiveData().apply { + value = 0 + } + val shadeProgress: LiveData = _shadeProgress + + + override fun update(state: GameModel, now: Instant) { + ui.post { + _shadeCount.value = Shade.getQty(state) + _soulCount.value = Soul.getQty(state) + _shadeProgress.value = Shade.getProgress(now).toInt() + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/ui/lair/LairFragment.kt b/app/src/main/java/com/gc/necrogame/ui/lair/LairFragment.kt new file mode 100644 index 0000000..cace718 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/lair/LairFragment.kt @@ -0,0 +1,41 @@ +package com.gc.necrogame.ui.lair + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.gc.necrogame.MainActivity +import com.gc.necrogame.R + +class LairFragment : Fragment() { + + private lateinit var lairViewModel: LairViewModel + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + lairViewModel = + ViewModelProvider(this).get(LairViewModel::class.java) + val root = inflater.inflate(R.layout.fragment_lair, container, false) + val textView: TextView = root.findViewById(R.id.text_home) + lairViewModel.text.observe(viewLifecycleOwner, Observer { + textView.text = it + }) + + (activity as MainActivity).gameState.addUpdater(lairViewModel) + + return root + } + + + override fun onDestroyView() { + super.onDestroyView() + (activity as MainActivity).gameState.removeUpdater(lairViewModel) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gc/necrogame/ui/lair/LairViewModel.kt b/app/src/main/java/com/gc/necrogame/ui/lair/LairViewModel.kt new file mode 100644 index 0000000..9167552 --- /dev/null +++ b/app/src/main/java/com/gc/necrogame/ui/lair/LairViewModel.kt @@ -0,0 +1,22 @@ +package com.gc.necrogame.ui.lair + +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.gc.necrogame.game.GameModel +import com.gc.necrogame.game.GameStateUpdateable +import java.time.Instant + +class LairViewModel : ViewModel(), GameStateUpdateable { + + private val _text = MutableLiveData().apply { + value = "This is home Fragment" + } + val text: LiveData = _text + + + override fun update(state: GameModel, now: Instant) { +// TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 0000000..46fc8de --- /dev/null +++ b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_headstone.xml b/app/src/main/res/drawable/ic_headstone.xml new file mode 100644 index 0000000..0e3fc77 --- /dev/null +++ b/app/src/main/res/drawable/ic_headstone.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 0000000..f8bb0b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..78b75c3 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..38c0aa8 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_battleground.xml b/app/src/main/res/layout/fragment_battleground.xml new file mode 100644 index 0000000..2b100bf --- /dev/null +++ b/app/src/main/res/layout/fragment_battleground.xml @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_graveyard.xml b/app/src/main/res/layout/fragment_graveyard.xml new file mode 100644 index 0000000..6025146 --- /dev/null +++ b/app/src/main/res/layout/fragment_graveyard.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + +