Initial Commit
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
*.apk
|
||||
*.aab
|
||||
*.ap_
|
||||
*.dex
|
||||
*.class
|
||||
*.log
|
||||
*.hprof
|
||||
*.iws
|
||||
*.ipr
|
||||
.idea/
|
||||
.gradle/
|
||||
build/
|
||||
app/build/
|
||||
app/release/
|
||||
local.properties
|
||||
*.keystore
|
||||
!gradle-wrapper.jar
|
||||
/cxx/
|
||||
*.navigation/
|
||||
*.orig
|
||||
*.tflite
|
||||
__pycache__/
|
||||
*.pyc
|
||||
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,53 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "ca.jonathanmccaffrey.igp"
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "ca.jonathanmccaffrey.igp"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material.icons.extended)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
implementation(libs.androidx.compose.ui.graphics)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||
}
|
||||
Vendored
+21
@@ -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
|
||||
@@ -0,0 +1,24 @@
|
||||
package ca.jonathanmccaffrey.igp
|
||||
|
||||
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("ca.jonathanmccaffrey.igp", appContext.packageName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.IGP">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.IGP">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,185 @@
|
||||
package ca.jonathanmccaffrey.igp
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Book
|
||||
import androidx.compose.material.icons.filled.Build
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.outlined.Book
|
||||
import androidx.compose.material.icons.outlined.Build
|
||||
import androidx.compose.material.icons.outlined.Home
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import ca.jonathanmccaffrey.igp.di.ServiceLocator
|
||||
import ca.jonathanmccaffrey.igp.ui.theme.IGPTheme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ServiceLocator.initialize(applicationContext)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
IGPTheme {
|
||||
IGPApp()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class BottomNavItem(
|
||||
val label: String,
|
||||
val selectedIcon: ImageVector,
|
||||
val unselectedIcon: ImageVector,
|
||||
)
|
||||
|
||||
private val bottomNavItems = listOf(
|
||||
BottomNavItem("Home", Icons.Filled.Home, Icons.Outlined.Home),
|
||||
BottomNavItem("Database", Icons.Filled.Search, Icons.Outlined.Search),
|
||||
BottomNavItem("Build Calculator", Icons.Filled.Build, Icons.Outlined.Build),
|
||||
BottomNavItem("Notes", Icons.Filled.Book, Icons.Outlined.Book),
|
||||
BottomNavItem("More", Icons.Filled.MoreVert, Icons.Outlined.MoreVert),
|
||||
)
|
||||
|
||||
sealed class ScreenContent {
|
||||
data object Home : ScreenContent()
|
||||
data object Database : ScreenContent()
|
||||
data object BuildCalculator : ScreenContent()
|
||||
data object EconomyComparison : ScreenContent()
|
||||
data object MemoryTester : ScreenContent()
|
||||
data object Notes : ScreenContent()
|
||||
data object About : ScreenContent()
|
||||
data object HarassCalculator : ScreenContent()
|
||||
data object DataTables : ScreenContent()
|
||||
data object Permissions : ScreenContent()
|
||||
data object DataCollection : ScreenContent()
|
||||
data object Streams : ScreenContent()
|
||||
data object Contact : ScreenContent()
|
||||
data object RoadMap : ScreenContent()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun IGPApp() {
|
||||
var selectedNavIndex by remember { mutableStateOf(0) }
|
||||
|
||||
val screens = listOf(
|
||||
listOf(ScreenContent.Home),
|
||||
listOf(ScreenContent.Database),
|
||||
listOf(ScreenContent.BuildCalculator, ScreenContent.EconomyComparison, ScreenContent.MemoryTester, ScreenContent.HarassCalculator, ScreenContent.DataTables),
|
||||
listOf(ScreenContent.Notes),
|
||||
listOf(ScreenContent.About, ScreenContent.Permissions, ScreenContent.DataCollection, ScreenContent.Streams, ScreenContent.Contact, ScreenContent.RoadMap),
|
||||
)
|
||||
|
||||
var currentScreen by remember { mutableStateOf<ScreenContent>(ScreenContent.Home) }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
bottomBar = {
|
||||
NavigationBar {
|
||||
bottomNavItems.forEachIndexed { index, item ->
|
||||
NavigationBarItem(
|
||||
selected = selectedNavIndex == index,
|
||||
onClick = {
|
||||
selectedNavIndex = index
|
||||
currentScreen = screens[index].first()
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = if (selectedNavIndex == index) item.selectedIcon else item.unselectedIcon,
|
||||
contentDescription = item.label,
|
||||
)
|
||||
},
|
||||
label = { Text(item.label) },
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
when (currentScreen) {
|
||||
is ScreenContent.Home -> HomeScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.Database -> DatabaseScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.BuildCalculator -> BuildCalculatorScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.EconomyComparison -> EconomyComparisonScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.MemoryTester -> MemoryTesterScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.Notes -> NotesScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.About -> AboutScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.HarassCalculator -> HarassCalculatorScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.DataTables -> DataTablesScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.Permissions -> PermissionsScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.DataCollection -> DataCollectionScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.Streams -> StreamsScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.Contact -> ContactScreen(Modifier.padding(innerPadding))
|
||||
is ScreenContent.RoadMap -> RoadMapScreen(Modifier.padding(innerPadding))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlaceholderScreen(name: String, modifier: Modifier = Modifier) {
|
||||
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Text(text = name, textAlign = TextAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Home", modifier)
|
||||
|
||||
@Composable
|
||||
fun DatabaseScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Database", modifier)
|
||||
|
||||
@Composable
|
||||
fun BuildCalculatorScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Build Calculator", modifier)
|
||||
|
||||
@Composable
|
||||
fun EconomyComparisonScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Economy Comparison", modifier)
|
||||
|
||||
@Composable
|
||||
fun MemoryTesterScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Memory Tester", modifier)
|
||||
|
||||
@Composable
|
||||
fun NotesScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Notes", modifier)
|
||||
|
||||
@Composable
|
||||
fun AboutScreen(modifier: Modifier = Modifier) = PlaceholderScreen("About", modifier)
|
||||
|
||||
@Composable
|
||||
fun HarassCalculatorScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Harass Calculator", modifier)
|
||||
|
||||
@Composable
|
||||
fun DataTablesScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Data Tables", modifier)
|
||||
|
||||
@Composable
|
||||
fun PermissionsScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Permissions", modifier)
|
||||
|
||||
@Composable
|
||||
fun DataCollectionScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Data Collection", modifier)
|
||||
|
||||
@Composable
|
||||
fun StreamsScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Streams", modifier)
|
||||
|
||||
@Composable
|
||||
fun ContactScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Contact", modifier)
|
||||
|
||||
@Composable
|
||||
fun RoadMapScreen(modifier: Modifier = Modifier) = PlaceholderScreen("Road Map", modifier)
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data
|
||||
|
||||
object Constants {
|
||||
const val APP_NAME = "IGP Fan Reference"
|
||||
const val CURRENT_PATCH = "1.0.0"
|
||||
const val PATCH_DATE = "2026-05-29"
|
||||
const val GITHUB_URL = "https://github.com/anomalyco/IGP"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models
|
||||
|
||||
class TravelTime(val index: Int, val value: Float)
|
||||
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models
|
||||
|
||||
class Variable {
|
||||
var key: String = ""
|
||||
var value: String = ""
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models
|
||||
|
||||
object Variables {
|
||||
const val gamePatch = " June 2025 Build (playtest)"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.buildorder
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class BuildOrderModel {
|
||||
constructor() {
|
||||
initialize(IdsEntity.FACTION_QRath)
|
||||
}
|
||||
|
||||
constructor(factionType: String) {
|
||||
initialize(factionType)
|
||||
}
|
||||
|
||||
var name: String = ""
|
||||
var notes: String = ""
|
||||
var buildTypes: MutableList<String> = mutableListOf()
|
||||
var currentSupplyUsed: Int = 0
|
||||
var startedOrders: MutableMap<Int, MutableList<EntityModel>> = mutableMapOf()
|
||||
var completedOrders: MutableMap<Int, MutableList<EntityModel>> = mutableMapOf()
|
||||
var depletedOrders: MutableMap<Int, MutableList<EntityModel>> = mutableMapOf()
|
||||
var uniqueCompletedTimes: MutableMap<String, Int> = mutableMapOf()
|
||||
var uniqueCompletedCount: MutableMap<String, Int> = mutableMapOf()
|
||||
var supplyCountTimes: MutableMap<Int, Int> = mutableMapOf()
|
||||
var uniqueCompleted: MutableMap<String, MutableList<EntityModel>> = mutableMapOf()
|
||||
var trainingCapacityUsed: MutableList<TrainingCapacityUsedModel> = mutableListOf()
|
||||
|
||||
fun initialize(faction: String) {
|
||||
val factionStartingTownHall = when (faction) {
|
||||
IdsEntity.FACTION_QRath -> IdsEntity.STARTING_TownHall_QRath
|
||||
IdsEntity.FACTION_Aru -> IdsEntity.STARTING_TownHall_Aru
|
||||
else -> ""
|
||||
}
|
||||
if (factionStartingTownHall.isEmpty()) throw Exception("Reminder to add support to new factions")
|
||||
|
||||
startedOrders = mutableMapOf(
|
||||
0 to mutableListOf(
|
||||
EntityModel.get(IdsEntity.STARTING_Bastion),
|
||||
EntityModel.get(IdsEntity.STARTING_TownHall_Aru)
|
||||
)
|
||||
)
|
||||
completedOrders = mutableMapOf(
|
||||
0 to mutableListOf(
|
||||
EntityModel.get(IdsEntity.STARTING_Bastion),
|
||||
EntityModel.get(IdsEntity.STARTING_TownHall_Aru)
|
||||
)
|
||||
)
|
||||
uniqueCompletedTimes = mutableMapOf(
|
||||
IdsEntity.STARTING_Bastion to 0,
|
||||
IdsEntity.STARTING_TownHall_Aru to 0
|
||||
)
|
||||
uniqueCompletedCount = mutableMapOf(
|
||||
IdsEntity.STARTING_Bastion to 1,
|
||||
IdsEntity.STARTING_TownHall_Aru to 1
|
||||
)
|
||||
supplyCountTimes = mutableMapOf(0 to 0)
|
||||
}
|
||||
|
||||
fun getHarvestersCompletedBefore(interval: Int): List<EntityModel> {
|
||||
return startedOrders.flatMap { (startTime, orders) ->
|
||||
orders.filter { order ->
|
||||
startTime + (order.production()?.buildTime ?: 0) <= interval &&
|
||||
order.harvest() != null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.buildorder
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.economy.EconomyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.EntityData
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class BuildToCompareModel {
|
||||
private var numberOfTownHallExpansions: Int = 0
|
||||
var faction: String = ""
|
||||
|
||||
val getTownHallEntity: EntityModel
|
||||
get() = EntityData.get()[
|
||||
if (faction == IdsEntity.FACTION_QRath) IdsEntity.BUILDING_Acropolis
|
||||
else IdsEntity.BUILDING_GroveHeart
|
||||
]!!
|
||||
|
||||
val getTownHallMining2Entity: EntityModel
|
||||
get() = EntityData.get()[
|
||||
if (faction == IdsEntity.FACTION_QRath) IdsEntity.BUPGRADE_MiningLevel2_QRath
|
||||
else IdsEntity.BUPGRADE_MiningLevel2_Aru
|
||||
]!!
|
||||
|
||||
var timeToBuildTownHall: MutableList<Int> = mutableListOf()
|
||||
|
||||
var economyOverTimeModel: MutableList<EconomyModel> = mutableListOf()
|
||||
var buildOrderModel: BuildOrderModel = BuildOrderModel()
|
||||
var chartColor: String = ""
|
||||
|
||||
fun getNumberOfTownHallExpansions(): Int = numberOfTownHallExpansions
|
||||
|
||||
fun setNumberOfTownHallExpansions(value: Int) {
|
||||
if (value >= 0 && value < 6 && value != numberOfTownHallExpansions) {
|
||||
numberOfTownHallExpansions = value
|
||||
while (timeToBuildTownHall.size < numberOfTownHallExpansions)
|
||||
timeToBuildTownHall.add((timeToBuildTownHall.size + 1) * 30)
|
||||
while (timeToBuildTownHall.size > numberOfTownHallExpansions)
|
||||
timeToBuildTownHall.removeAt(timeToBuildTownHall.lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.buildorder
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class ResearchSlot {
|
||||
var startingInterval: Int = 30
|
||||
var slots: Int = 1
|
||||
var researchType: String = IdsEntity.BUILDING_Reliquary
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.buildorder
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class TrainingCapacityUsedModel {
|
||||
var usedSlots: Int = 4
|
||||
var usedBuilding: String = IdsEntity.BUILDING_LegionHall
|
||||
var startingUsageTime: Int = 30
|
||||
var stopUsageTime: Int = 60
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.buildorder
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class TrainingSlot {
|
||||
var startingInterval: Int = 30
|
||||
var slots: Int = 10
|
||||
var productionType: String = IdsEntity.BUILDING_LegionHall
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.chart
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.chart.enums.ChartColourType
|
||||
|
||||
class ChartModel {
|
||||
var points: MutableList<PointModel> = mutableListOf()
|
||||
var chartColor: String = ChartColourType.Red.name
|
||||
var offset: Int = 0
|
||||
var intervalDisplayMax: Int = 300
|
||||
var valueDisplayMax: Int = 5000
|
||||
var highestIntervalPoint: Float = 5000f
|
||||
var highestValuePoint: Float = 5000f
|
||||
|
||||
companion object {
|
||||
fun getAll(): List<ChartModel> {
|
||||
val cs = mutableListOf<ChartModel>()
|
||||
|
||||
val c1 = ChartModel().apply {
|
||||
intervalDisplayMax = 1000
|
||||
valueDisplayMax = 300
|
||||
chartColor = "Orange"
|
||||
points = mutableListOf()
|
||||
}
|
||||
|
||||
for (i in 0 until c1.intervalDisplayMax) {
|
||||
c1.points.add(PointModel().apply {
|
||||
interval = i.toFloat()
|
||||
value = (i.toFloat() / c1.intervalDisplayMax.toFloat() * c1.valueDisplayMax.toFloat()).toInt()
|
||||
.toFloat()
|
||||
})
|
||||
}
|
||||
|
||||
cs.add(c1)
|
||||
return cs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.chart
|
||||
|
||||
class PointModel {
|
||||
var interval: Float = 0f
|
||||
var value: Float = 0f
|
||||
var tempValue: Float = 0f
|
||||
|
||||
fun getInterval(highestInterval: Float, displayScale: Float): String {
|
||||
val display = interval / highestInterval * displayScale
|
||||
return display.toInt().toString()
|
||||
}
|
||||
|
||||
fun getValue(highestValue: Float, displayScale: Float): String {
|
||||
val display = value / highestValue * displayScale
|
||||
return display.toInt().toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.chart.enums
|
||||
|
||||
enum class ChartColourType {
|
||||
Red,
|
||||
LightGreen,
|
||||
Cyan,
|
||||
Yellow,
|
||||
Orange,
|
||||
LightBlue,
|
||||
Pink
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.economy
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
|
||||
class EconomyModel {
|
||||
var interval: Int = 0
|
||||
var alloy: Float = 0f
|
||||
var alloyIncome: Float = 0f
|
||||
var ether: Float = 0f
|
||||
var etherIncome: Float = 0f
|
||||
var pyre: Float = 0f
|
||||
var supply: Int = 0
|
||||
var workerCount: Int = 6
|
||||
var busyWorkerCount: Int = 0
|
||||
var creatingWorkerCount: Int = 0
|
||||
var creatingWorkerDelays: MutableList<Int> = mutableListOf()
|
||||
var harvestPoints: MutableList<EntityModel> = mutableListOf()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.economy
|
||||
|
||||
class EconomyOverTimeModel {
|
||||
var lastInterval: Int = 0
|
||||
var economyOverTime: MutableList<EconomyModel> = mutableListOf()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.economy.enums
|
||||
|
||||
enum class HarvesterType {
|
||||
Worker,
|
||||
EtherExtractor,
|
||||
Bastion
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.economy.enums
|
||||
|
||||
enum class RequestType {
|
||||
Unit,
|
||||
Building
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.economy.enums
|
||||
|
||||
enum class WorkerStateType {
|
||||
Building,
|
||||
Unit
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.EntityData
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityFactionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityHarvestModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityHotkeyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdAbilityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdArmyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdPassiveModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdPyreSpellModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdUpgradeModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityIdVanguardModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.IEntityPartInterface
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityInfoModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityMechanicModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityMovementModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityPassiveModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityProductionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityRequirementModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityStrategyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntitySupplyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityTierModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityVanguardAddedModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityVanguardReplacedModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityVitalityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.parts.EntityWeaponModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.DescriptiveType
|
||||
|
||||
class EntityModel(
|
||||
var dataType: String,
|
||||
var entityType: String,
|
||||
var isSpeculative: Boolean = false
|
||||
) {
|
||||
var entityParts: MutableList<IEntityPartInterface> = mutableListOf()
|
||||
var descriptive: String = DescriptiveType.None
|
||||
|
||||
fun getName(): String {
|
||||
val entityInfo = entityParts.firstOrNull { it is EntityInfoModel } as? EntityInfoModel
|
||||
return entityInfo?.name ?: ""
|
||||
}
|
||||
|
||||
fun getFaction(): String {
|
||||
val entityInfo = entityParts.firstOrNull { it is EntityFactionModel } as? EntityFactionModel
|
||||
return entityInfo?.let { EntityData.get()[it.faction]?.getName() } ?: ""
|
||||
}
|
||||
|
||||
fun getImmortal(): String {
|
||||
val entityInfo = entityParts.firstOrNull { it is EntityVanguardAddedModel } as? EntityVanguardAddedModel
|
||||
return entityInfo?.let { EntityData.get()[it.immortalId]?.getName() } ?: ""
|
||||
}
|
||||
|
||||
fun clone(): EntityModel {
|
||||
val cloned = EntityModel(dataType, entityType, isSpeculative)
|
||||
cloned.entityParts = entityParts.toMutableList()
|
||||
cloned.descriptive = descriptive
|
||||
return cloned
|
||||
}
|
||||
|
||||
fun copyFrom(entity: EntityModel) {
|
||||
dataType = entity.dataType
|
||||
entityType = entity.entityType
|
||||
entityParts = entity.entityParts.toMutableList()
|
||||
}
|
||||
|
||||
fun addPart(unitPart: IEntityPartInterface): EntityModel {
|
||||
unitPart.parent = this
|
||||
entityParts.add(unitPart)
|
||||
return this
|
||||
}
|
||||
|
||||
fun info(): EntityInfoModel =
|
||||
entityParts.find { it is EntityInfoModel } as EntityInfoModel
|
||||
|
||||
fun supply(): EntitySupplyModel? =
|
||||
entityParts.find { it is EntitySupplyModel } as? EntitySupplyModel
|
||||
|
||||
fun tier(): EntityTierModel =
|
||||
entityParts.find { it is EntityTierModel } as EntityTierModel
|
||||
|
||||
fun production(): EntityProductionModel? =
|
||||
entityParts.find { it is EntityProductionModel } as? EntityProductionModel
|
||||
|
||||
fun movement(): EntityMovementModel =
|
||||
entityParts.find { it is EntityMovementModel } as EntityMovementModel
|
||||
|
||||
fun vitality(): EntityVitalityModel =
|
||||
entityParts.find { it is EntityVitalityModel } as EntityVitalityModel
|
||||
|
||||
fun requirements(): List<EntityRequirementModel> =
|
||||
entityParts.filterIsInstance<EntityRequirementModel>()
|
||||
|
||||
fun weapons(): List<EntityWeaponModel> =
|
||||
entityParts.filterIsInstance<EntityWeaponModel>()
|
||||
|
||||
fun replaceds(): List<EntityVanguardReplacedModel> =
|
||||
entityParts.filterIsInstance<EntityVanguardReplacedModel>()
|
||||
|
||||
fun vanguardAdded(): EntityVanguardAddedModel? =
|
||||
entityParts.find { it is EntityVanguardAddedModel } as? EntityVanguardAddedModel
|
||||
|
||||
fun hotkey(): EntityHotkeyModel? =
|
||||
entityParts.find { it is EntityHotkeyModel } as? EntityHotkeyModel
|
||||
|
||||
fun faction(): EntityFactionModel? =
|
||||
entityParts.find { it is EntityFactionModel } as? EntityFactionModel
|
||||
|
||||
fun harvest(): EntityHarvestModel? =
|
||||
entityParts.find { it is EntityHarvestModel } as? EntityHarvestModel
|
||||
|
||||
fun idAbilities(): List<EntityIdAbilityModel> =
|
||||
entityParts.filterIsInstance<EntityIdAbilityModel>()
|
||||
|
||||
fun idArmies(): List<EntityIdArmyModel> =
|
||||
entityParts.filterIsInstance<EntityIdArmyModel>()
|
||||
|
||||
fun idPassives(): List<EntityIdPassiveModel> =
|
||||
entityParts.filterIsInstance<EntityIdPassiveModel>()
|
||||
|
||||
fun idUpgrades(): List<EntityIdUpgradeModel> =
|
||||
entityParts.filterIsInstance<EntityIdUpgradeModel>()
|
||||
|
||||
fun idVanguards(): List<EntityIdVanguardModel> =
|
||||
entityParts.filterIsInstance<EntityIdVanguardModel>()
|
||||
|
||||
fun idPyreSpells(): List<EntityIdPyreSpellModel> =
|
||||
entityParts.filterIsInstance<EntityIdPyreSpellModel>()
|
||||
|
||||
fun mechanics(): List<EntityMechanicModel> =
|
||||
entityParts.filterIsInstance<EntityMechanicModel>()
|
||||
|
||||
fun passives(): List<EntityPassiveModel> =
|
||||
entityParts.filterIsInstance<EntityPassiveModel>()
|
||||
|
||||
fun strategies(): List<EntityStrategyModel> =
|
||||
entityParts.filterIsInstance<EntityStrategyModel>()
|
||||
|
||||
companion object {
|
||||
private var _database: MutableMap<String, EntityModel>? = null
|
||||
private var _entityModels: MutableList<EntityModel>? = null
|
||||
private var _entityModelsOnlyHotkey: MutableList<EntityModel>? = null
|
||||
private var _entityModelsByHotkey: MutableMap<String, MutableList<EntityModel>>? = null
|
||||
|
||||
fun getDictionary(): Map<String, EntityModel> {
|
||||
if (_database == null) _database = EntityData.get().toMutableMap()
|
||||
return _database!!
|
||||
}
|
||||
|
||||
fun get(entity: String): EntityModel {
|
||||
if (_database == null) _database = EntityData.get().toMutableMap()
|
||||
return _database!![entity]!!
|
||||
}
|
||||
|
||||
fun getList(): List<EntityModel> {
|
||||
if (_entityModels == null) _entityModels = EntityData.get().values.toMutableList()
|
||||
return _entityModels!!
|
||||
}
|
||||
|
||||
fun getListOnlyHotkey(): List<EntityModel> {
|
||||
if (_entityModelsOnlyHotkey == null) {
|
||||
_entityModelsOnlyHotkey = mutableListOf()
|
||||
for (entity in EntityData.get().values) {
|
||||
if (entity.hotkey() != null) {
|
||||
_entityModelsOnlyHotkey!!.add(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _entityModelsOnlyHotkey!!
|
||||
}
|
||||
|
||||
fun getEntitiesByHotkey(): Map<String, List<EntityModel>> {
|
||||
if (_entityModelsByHotkey == null) {
|
||||
_entityModelsByHotkey = mutableMapOf()
|
||||
for (entity in getList()) {
|
||||
val entityHotkey = entity.hotkey()
|
||||
if (entityHotkey != null) {
|
||||
if (!_entityModelsByHotkey!!.containsKey(entityHotkey.hotkey))
|
||||
_entityModelsByHotkey!![entityHotkey.hotkey] = mutableListOf()
|
||||
_entityModelsByHotkey!![entityHotkey.hotkey]!!.add(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
return _entityModelsByHotkey!!
|
||||
}
|
||||
|
||||
fun getFrom(
|
||||
hotkey: String,
|
||||
hotkeyGroup: String,
|
||||
holdSpace: Boolean,
|
||||
faction: String,
|
||||
immortal: String
|
||||
): EntityModel? {
|
||||
if (hotkey.isEmpty()) return null
|
||||
if (!getEntitiesByHotkey().containsKey(hotkey)) return null
|
||||
|
||||
val foundList = getEntitiesByHotkey()[hotkey]!!.filter { entity ->
|
||||
entity.hotkey()?.hotkeyGroup == hotkeyGroup &&
|
||||
entity.hotkey()?.holdSpace == holdSpace &&
|
||||
entity.faction()?.faction == faction &&
|
||||
(entity.vanguardAdded()?.immortalId == immortal || entity.vanguardAdded() == null) &&
|
||||
(entity.replaceds().isEmpty() || entity.replaceds().none { it.immortalId == immortal })
|
||||
}
|
||||
|
||||
return foundList.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.data
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
|
||||
object EntityData {
|
||||
private fun getAbilityData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Ability.cs - contains abilities like RadiantWard, Windstep, etc.
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getArmyData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Army.cs - contains army units, vanguards, etc.
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getBuildingData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Building.cs - contains buildings and upgrades
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getImmortalData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Immortal.cs - contains immortal entities
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getMiscData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Misc.cs - contains misc entities like rocks, teapots
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getPassiveData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Passive.cs - contains passive entities
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun getResearchData(): Map<String, EntityModel> {
|
||||
// TODO: Convert from EntityData.Research.cs - contains research/upgrade entities
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
fun get(): Map<String, EntityModel> {
|
||||
return getResearchData() +
|
||||
getArmyData() +
|
||||
getAbilityData() +
|
||||
getMiscData() +
|
||||
getImmortalData() +
|
||||
getBuildingData() +
|
||||
getPassiveData()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.data
|
||||
|
||||
object EntityType {
|
||||
const val None = "None"
|
||||
const val Any = "Any"
|
||||
const val Teapot = "Teapot"
|
||||
const val Family = "Family"
|
||||
const val Faction = "Faction"
|
||||
const val Command = "Command"
|
||||
const val Worker = "Worker"
|
||||
const val Army = "Army"
|
||||
const val Building = "Building"
|
||||
const val Building_Upgrade = "Building_Upgrade"
|
||||
const val Immortal = "Immortal"
|
||||
const val Pyre_Spell = "Spell"
|
||||
const val Pyre_Event = "Pyre_Event"
|
||||
const val Ability = "Ability"
|
||||
const val Tech = "Tech"
|
||||
const val Passive = "Passive"
|
||||
}
|
||||
|
||||
object ImmortalSpellType {
|
||||
const val Utitlity = "Utitlity"
|
||||
const val Combat = "Combat"
|
||||
const val Ultimate = "Ultimate"
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.data
|
||||
|
||||
object IdsEntity {
|
||||
const val Any = "Any"
|
||||
const val None = "None"
|
||||
|
||||
const val PYREEVENT_TowerKilled = "9a923928-b016-49f2-8c7d-950abf09e287"
|
||||
const val PYREEVENT_CampTaken = "cc27a9b2-69e2-4322-8102-7a9f8bea7871"
|
||||
const val PYREEVENT_MinerTaken = "5b158cf2-2810-4a2a-8131-c4fe4b392ce9"
|
||||
const val TEAPOT_Teapot = "7c30273e-b73b-458f-88d6-545360d046cc"
|
||||
const val TEAPOT_FlyingTeapot = "3eb385ed-7086-4abb-8670-332e7a16c008"
|
||||
const val FAMILY_Sylv = "73d69995-128d-4cfe-a40a-e5f00491f87b"
|
||||
const val FAMILY_Human = "466d3be4-5322-4d5c-88d2-fb26563c8ee8"
|
||||
const val FAMILY_Angelic = "c43686a6-f6d0-4a18-9870-338c64511051"
|
||||
const val FAMILY_Coalition = "8aba0aff-ce18-4e15-afdc-28bb12a112bb"
|
||||
const val FAMILY_Rae = "ce8d60f3-b590-4619-ad90-27e65f77312b"
|
||||
const val FAMILY_Demonic = "f61a3630-9474-4ec3-bc71-997cacc52bc1"
|
||||
const val FAMILY_NazRa = "56cc934f-57a9-442c-909a-25690f836679"
|
||||
|
||||
const val FACTION_Neutral = "95da29af-99da-45fe-80f6-4ae1cc0d0f47"
|
||||
const val FACTION_Aru = "fb103962-7518-48df-b7d9-83906a009db8"
|
||||
const val FACTION_Iratek = "dbc12bda-b4f2-4fa0-8270-18dc1646d62d"
|
||||
const val FACTION_Yul = "9c0492af-1ef8-4113-9010-92178493f8b3"
|
||||
const val FACTION_Jora = "692f534f-2bdc-4b27-90b4-d88bed3dd910"
|
||||
const val FACTION_Telmetra = "1b1e2742-81c9-42d0-966c-1e43eb11e34a"
|
||||
const val FACTION_Kjor = "1b1a354a-863f-440e-b4e7-acad41a6ece8"
|
||||
const val FACTION_QRath = "3bb4bdf7-d7bf-45cb-b123-02f8ba52b848"
|
||||
const val FACTION_YRiah = "c7537d12-a536-4ef5-99b9-d7ad704716fe"
|
||||
const val FACTION_ArkShai = "ffe82eea-b8c6-4933-9230-cd019fd1c259"
|
||||
const val FACTION_Herlesh = "e6c09f4a-ae7d-4bfd-b5d4-a63445d59498"
|
||||
const val FACTION_Khardu = "a1764de6-8178-4775-819a-59d23677dd76"
|
||||
const val COMMAND_Attack = "168486ff-581e-46da-a308-74f1d7d615fd"
|
||||
const val COMMAND_StandGround = "cb9ee44f-7293-4a82-826c-a3829491006b"
|
||||
const val MISC_Rocks = "030016ad-b972-4ad5-a601-41a99f8db305"
|
||||
const val NEUTRAL_Tower = "40a5d5c7-42b8-48af-b71f-d75fedafb7b6"
|
||||
const val NEUTRAL_PyreCamp = "185a9895-63da-402b-8d09-4c8609d52b04"
|
||||
const val NEUTRAL_PyreMiner = "474727ee-0353-462f-9241-fb9031eb52a8"
|
||||
const val STARTING_Bastion = "73d17ce2-8304-43dc-a0dd-d4a5666ea0b3"
|
||||
const val STARTING_Tower = "3ca43196-db92-4beb-b5c5-65bdffbd32cf"
|
||||
const val STARTING_TownHall_Aru = "f08e5320-8419-4259-b48d-e201b1f05ccf"
|
||||
const val STARTING_TownHall_QRath = "150a4727-f831-48be-81fe-4dfd3588dfec"
|
||||
const val IMMORTAL_Orzum = "IMMORTAL_Orzum"
|
||||
const val IMMORTAL_Ajari = "IMMORTAL_Ajari"
|
||||
const val IMMORTAL_Atzlan = "IMMORTAL_Atzlan"
|
||||
const val IMMORTAL_Mala = "IMMORTAL_Mala"
|
||||
const val IMMORTAL_Xol = "IMMORTAL_Xol"
|
||||
|
||||
const val ISPELL_SummonCitadel = "ISPELL_SummonCitadel"
|
||||
const val ISPELL_RookOfIra = "ISPELL_RookOfIra"
|
||||
const val ISPELL_EmpireUnbroken = "ISPELL_EmpireUnbroken"
|
||||
const val ISPELL_PillarOfHeaven = "ISPELL_PillarOfHeaven"
|
||||
const val ISPELL_HeavensAegis = "ISPELL_HeavensAegis"
|
||||
const val ISPELL_DeliverFromEvil = "ISPELL_DeliverFromEvil"
|
||||
const val ISPELL_Salvation = "ISPELL_Salvation"
|
||||
const val ISPELL_SummonGroveGuardian = "ISPELL_SummonGroveGuardian"
|
||||
const val ISPELL_ConstructBloodWell = "ISPELL_ConstructBloodWell"
|
||||
const val ISPELL_RedHarvest = "ISPELL_RedHarvest"
|
||||
const val ISPELL_ProphetsFavor = "ISPELL_ProphetsFavor"
|
||||
const val ISPELL_RainOfBlood = "ISPELL_RainOfBlood"
|
||||
const val ISPELL_ProphetOfTheHunt = "ISPELL_ProphetOfTheHunt"
|
||||
const val ISPELL_HuntingGrounds = "ISPELL_HuntingGrounds"
|
||||
const val ISPELL_TheGreatHunt = "ISPELL_TheGreatHunt"
|
||||
const val ISPELL_ProphetOfTheRoots = "ISPELL_ProphetOfTheRoots"
|
||||
const val ISPELL_WallOfRoots = "ISPELL_WallOfRoots"
|
||||
const val ISPELL_SummonDeepWyrm = "ISPELL_SummonDeepWyrm"
|
||||
const val ISPELL_SummonRootBud = "ISPELL_SummonRootBud"
|
||||
|
||||
const val IPASSIVE_MendingGrace = "IPASSIVE_MendingGrace"
|
||||
const val IPASSIVE_OrdainedConquest = "IPASSIVE_OrdainedConquest"
|
||||
const val IPASSIVE_MothersHunger = "IPASSIVE_MothersHunger"
|
||||
const val IPASSIVE_StalkersSense = "IPASSIVE_StalkersSense"
|
||||
const val IPASSIVE_GreenThumb = "IPASSIVE_GreenThumb"
|
||||
|
||||
const val BUILDING_Acropolis = "BUILDING_Acropolis"
|
||||
const val BUILDING_ApostleOfBinding = "BUILDING_ApostleOfBinding"
|
||||
const val BUILDING_GroveHeart = "BUILDING_GroveHeart"
|
||||
const val BUILDING_EtherMaw = "BUILDING_EtherMaw"
|
||||
const val BUPGRADE_MiningLevel2_QRath = "BUPGRADE_MiningLevel2_QRath"
|
||||
const val BUPGRADE_MiningLevel2_Aru = "BUPGRADE_MiningLevel2_Aru"
|
||||
const val CONVERSION_EtherSruge_QRath = "CONVERSION_EtherSruge_QRath"
|
||||
const val CONVERSION_EtherSruge_Aru = "CONVERSION_EtherSruge_Aru"
|
||||
|
||||
const val BUPGRADE_GodHeart = "BUPGRADE_GodHeart"
|
||||
const val BUPGRADE_Omnivore = "BUPGRADE_Omnivore"
|
||||
const val BUILDING_LegionHall = "BUILDING_LegionHall"
|
||||
const val BUILDING_SoulFoundry = "BUILDING_SoulFoundry"
|
||||
const val BUILDING_Angelarium = "BUILDING_Angelarium"
|
||||
const val BUILDING_AltarOfTheWorthy = "BUILDING_AltarOfTheWorthy"
|
||||
const val BUILDING_AmberWomb = "BUILDING_AmberWomb"
|
||||
const val BUILDING_BoneCanopy = "BUILDING_BoneCanopy"
|
||||
const val BUILDING_Reliquary = "BUILDING_Reliquary"
|
||||
const val BUILDING_MonasteryOfIzur = "BUILDING_MonasteryOfIzur"
|
||||
const val BUILDING_HouseOfFadingSaints = "BUILDING_HouseOfFadingSaints"
|
||||
const val BUILDING_EyeOfAros = "BUILDING_EyeOfAros"
|
||||
const val BUILDING_BearerOfTheCrown = "BUILDING_BearerOfTheCrown"
|
||||
const val BUILDING_RedVale = "BUILDING_RedVale"
|
||||
const val BUILDING_DeepNest = "BUILDING_DeepNest"
|
||||
const val BUILDING_MurderHollow = "BUILDING_MurderHollow"
|
||||
const val BUILDING_Neurocyte = "BUILDING_Neurocyte"
|
||||
const val BUILDING_RootCradle = "BUILDING_RootCradle"
|
||||
const val DEFENSE_FireSinger = "DEFENSE_FireSinger"
|
||||
const val BUILDING_KeeperOfTheHardenedFlames = "BUILDING_KeeperOfTheHardenedFlames"
|
||||
const val DEFENSE_Aerovore = "DEFENSE_Aerovore"
|
||||
|
||||
const val UPGRADE_GreavesOfAhqar = "UPGRADE_GreavesOfAhqar"
|
||||
const val UPGRADE_FortifiedIcons = "UPGRADE_FortifiedIcons"
|
||||
const val UPGRADE_PsalmOfFire = "UPGRADE_PsalmOfFire"
|
||||
const val UPGRADE_FaithCastBlades = "UPGRADE_FaithCastBlades"
|
||||
const val UPGRADE_RelicOfTheWrathfulGaze = "UPGRADE_RelicOfTheWrathfulGaze"
|
||||
const val UPGRADE_WindStep = "UPGRADE_WindStep"
|
||||
const val UPGRADE_ZephyrRange = "UPGRADE_ZephyrRange"
|
||||
const val UPGRADE_SiroccoScript = "UPGRADE_SiroccoScript"
|
||||
const val UPGRADE_IconOfTheEnduringVigil = "UPGRADE_IconOfTheEnduringVigil"
|
||||
const val UPGRADE_AbsolverHealthUpgrade = "UPGRADE_AbsolverHealthUpgrade"
|
||||
const val UPGRADE_Awestrike = "UPGRADE_Awestrike"
|
||||
const val UPGRADE_IconOfKhastEem = "UPGRADE_IconOfKhastEem"
|
||||
const val UPGRADE_WingsOfTheKenLatir = "UPGRADE_WingsOfTheKenLatir"
|
||||
const val UPGRADE_TitheBlades = "UPGRADE_TitheBlades"
|
||||
const val UPGRADE_Offering = "UPGRADE_Offering"
|
||||
const val UPGRADE_PursuitLigaments = "UPGRADE_PursuitLigaments"
|
||||
const val UPGRADE_EthericFibers = "UPGRADE_EthericFibers"
|
||||
const val UPGRADE_ObstructingSwarm = "UPGRADE_ObstructingSwarm"
|
||||
const val UPGRADE_Hematoma = "UPGRADE_Hematoma"
|
||||
const val UPGRADE_ResinantSpeed = "UPGRADE_ResinantSpeed"
|
||||
const val UPGRADE_RootShepherdHidden = "UPGRADE_RootShepherdHidden"
|
||||
const val UPGRADE_RootShepherdSpeed = "UPGRADE_RootShepherdSpeed"
|
||||
const val UPGRADE_EoxBowstring = "UPGRADE_EoxBowstring"
|
||||
const val UPGRADE_SporeBurst = "UPGRADE_SporeBurst"
|
||||
const val UPGRADE_VitellineCysts = "UPGRADE_VitellineCysts"
|
||||
const val UPGRADE_HyperAdrenoceptors = "UPGRADE_HyperAdrenoceptors"
|
||||
const val UPGRADE_BloodPlague = "UPGRADE_BloodPlague"
|
||||
const val UPGRADE_BirthingStorm = "UPGRADE_BirthingStorm"
|
||||
const val UPGRADE_GodphageDamage = "UPGRADE_GodphageDamage"
|
||||
const val UPGRADE_GENERIC_Attack1 = "UPGRADE_GENERIC_Attack1"
|
||||
const val UPGRADE_GENERIC_Defense1 = "UPGRADE_GENERIC_Defense1"
|
||||
const val UPGRADE_RadiantWard = "UPGRADE_RadiantWard"
|
||||
const val UPGRADE_Ambush = "UPGRADE_Ambush"
|
||||
|
||||
const val PASSIVE_Detection = "434468fa-83b2-4fc9-a38c-1a3d00bcf055"
|
||||
const val PASSIVE_WraithBowRange = "196dd8a6-2044-44e1-aac4-fbaa40552699"
|
||||
const val PASSIVE_HiddenX = "7b819996-ffc0-4e07-9c11-c91c5f9d467b"
|
||||
const val PASSIVE_Respite = "607c39f4-a957-4a7a-8fc6-a239f9e570ec"
|
||||
const val PASSIVE_BastionPassives = "ea42b9cb-2456-4ed2-b490-fcfde12c6153"
|
||||
const val PASSIVE_HallowedWarrior = "fea43ced-33f3-4531-af7d-740c1789fec1"
|
||||
const val PASSIVE_GreavesOfAhqar = "3c408d75-7bee-4089-84c0-74620ac708b6"
|
||||
const val PASSIVE_FortifiedIcons = "35f3f02f-e22e-44be-b2ea-82972c383308"
|
||||
const val PASSIVE_HarvestAlloy = "84bacf5a-b106-455c-8cff-66c3998404f8"
|
||||
const val PASSIVE_RelicOfTheWrathfulGaze = "ccebc0c9-cfd5-465a-8a5d-2495bd745a83"
|
||||
const val PASSIVE_WingsOfTheKenLatir = "48909ff5-63db-4c99-b62f-d290e127e0bf"
|
||||
const val PASSIVE_ExecutionRites = "8d017a17-320f-4c2a-b139-d2d83bf7ecd0"
|
||||
const val PASSIVE_IconOfKhastEem = "7a211da6-4713-40f5-a171-1e3b6e02bf09"
|
||||
const val PASSIVE_FaithCastBlades = "da4f8c9c-1b22-4b3f-94fc-11bc12cde02d"
|
||||
const val PASSIVE_ThroneMovingShot = "699423ed-7410-4daf-8b07-9dc733a8bf55"
|
||||
const val PASSIVE_SiroccoScript = "11c21afa-ff88-4e42-9f97-a1d1595b115c"
|
||||
const val PASSIVE_HallowingRites = "9c8ae47b-954e-4a17-8f35-f128c9114b61"
|
||||
const val PASSIVE_RegentsWrath = "f111f004-6548-4430-9d13-ef44ab108ae7"
|
||||
const val PASSIVE_PsalmOfFire = "PASSIVE_PsalmOfFire"
|
||||
const val PASSIVE_HallowedWeapons = "f9ac4b3e-d02d-42d4-8d9d-beb9c5d7edcb"
|
||||
const val PASSIVE_Zeal = "62c4942b-5578-422d-8d4e-d1789f4efa68"
|
||||
const val PASSIVE_HallowedGround = "bdb28984-246f-4642-84ab-9e83c02b3e2e"
|
||||
const val PASSIVE_Rootway = "46768d4a-5047-4973-b5ca-995cda25ee8d"
|
||||
const val PASSIVE_BehemothCapacity = "a210f109-d3ac-44d4-9724-601c795a2394"
|
||||
const val PASSIVE_QuitlStorage2 = "0b27b863-fce5-40e4-96c7-6df94bdd92b9"
|
||||
const val PASSIVE_Temporary = "940c04f1-df0b-4cf7-9514-09dfd9009554"
|
||||
const val PASSIVE_Stalk = "9c107bfd-0050-4670-91b8-f9a8d771225d"
|
||||
const val PASSIVE_Ambush = "9d0a9482-0303-4a15-bb88-972f6ae60a39"
|
||||
const val PASSIVE_FallenHarvest = "d209e13f-d631-40d7-90e1-d9845b51b8d4"
|
||||
const val PASSIVE_RestoreLifeblood = "fa213bc6-336c-4510-8a4b-db9ccfc54d62"
|
||||
const val PASSIVE_Transfusion = "e67a3d6d-f2bb-4622-9e4d-ea2a26af2f39"
|
||||
const val PASSIVE_HallowedRuin = "402b555a-eb8a-4065-bd25-465d190b30c7"
|
||||
const val PASSIVE_ExternalDigestion = "2563723b-4a75-4a17-a104-1f5ac3b79a06"
|
||||
const val PASSIVE_PursuitLigaments = "9f9676d5-cf6c-417d-9d08-ace400ccd39b"
|
||||
const val PASSIVE_OssifyingSwarm = "b8897247-8393-416e-b246-409a6b3263c2"
|
||||
const val PASSIVE_CastingFromBlood = "c97d1cf1-67d9-402b-9fa1-1abb9bfd7bfd"
|
||||
const val PASSIVE_QuenchingScythes = "dbf07db4-e7b6-4f81-9f8e-e5391850eead"
|
||||
const val PASSIVE_AaroxBurn = "921fe250-2b97-40c0-9765-9e6c1e766dd5"
|
||||
const val PASSIVE_EngorgedArteries = "5b742d12-f695-4948-a00c-debdcb8b3717"
|
||||
const val PASSIVE_ProjectileGestation = "e14f144f-8fa7-4cd5-bb9e-bed06e8af135"
|
||||
const val PASSIVE_GuidingAmber = "9eab6701-0f0d-4858-b8a4-14e3a5dab822"
|
||||
const val PASSIVE_GodstoneBulwark = "482189ac-713d-4870-a960-d2930961c486"
|
||||
const val PASSIVE_Invervention = "3a70d237-1530-455a-b4f8-a626d708334c"
|
||||
const val PASSIVE_BloodFrenzy = "356b6c33-a857-489c-8218-68c53d03db90"
|
||||
const val PASSIVE_MendingDecree = "25d94c3d-dba9-4f02-abf4-904269b539c6"
|
||||
const val PASSIVE_FireQuitl = "80f6b382-da1c-49a1-8235-1ea37983ea54"
|
||||
const val PASSIVE_XacalDamage = "69928f20-5332-418f-ada3-694da3f7b199"
|
||||
const val PASSIVE_XacalDefense = "PASSIVE_XacalDefense"
|
||||
|
||||
const val ABILITY_RadiantWard = "ABILITY_RadiantWard"
|
||||
const val ABILITY_Windstep = "ABILITY_Windstep"
|
||||
const val ABILITY_Intervention = "ABILITY_Intervention"
|
||||
const val ABILITY_OrdainedPassage = "ABILITY_OrdainedPassage"
|
||||
const val ABILITY_DeployMagi = "ABILITY_DeployMagi"
|
||||
const val ABILITY_DeployAbsolver = "ABILITY_DeployAbsolver"
|
||||
const val ABILITY_DeploySentinel = "ABILITY_DeploySentinel"
|
||||
const val ABILITY_Smite = "ABILITY_Smite"
|
||||
const val ABILITY_Awestrike = "ABILITY_Awestrike"
|
||||
const val ABILITY_TitheBlades = "ABILITY_TitheBlades"
|
||||
const val ABILITY_MobilizeQrath = "ABILITY_MobilizeQrath"
|
||||
const val ABILITY_Offering = "ABILITY_Offering"
|
||||
const val ABILITY_DiveBomb = "ABILITY_DiveBomb"
|
||||
const val ABILITY_DrainingEmbrace = "ABILITY_DrainingEmbrace"
|
||||
const val ABILITY_BloodPlague = "ABILITY_BloodPlague"
|
||||
const val ABILITY_DeployResinant = "ABILITY_DeployResinant"
|
||||
const val ABILITY_DeployBloodAnchor = "ABILITY_DeployBloodAnchor"
|
||||
const val ABILITY_MobilizeAru = "ABILITY_MobilizeAru"
|
||||
const val ABILITY_BloodyRebound = "ABILITY_BloodyRebound"
|
||||
const val ABILITY_RootVice = "ABILITY_RootVice"
|
||||
const val ABILITY_BirthingStorm = "ABILITY_BirthingStorm"
|
||||
const val ABILITY_DeployDreadSister = "ABILITY_DeployDreadSister"
|
||||
const val ABILITY_MorphToGodphage = "ABILITY_MorphToGodphage"
|
||||
const val ABILITY_DeepTunnel = "ABILITY_DeepTunnel"
|
||||
const val ABILITY_ObstructingSwarm = "ABILITY_ObstructingSwarm"
|
||||
const val ABILITY_Hematoma = "ABILITY_Hematoma"
|
||||
|
||||
const val VANGUARD_Zentari_Orzum = "VANGUARD_Zentari_Orzum"
|
||||
const val VANGUARD_Sceptre_Orzum = "VANGUARD_Sceptre_Orzum"
|
||||
const val VANGUARD_ArkMother_Ajari = "VANGUARD_ArkMother_Ajari"
|
||||
const val VANGUARD_Saoshin_Ajari = "VANGUARD_Saoshin_Ajari"
|
||||
const val VANGUARD_RootShepard_Atzlan = "VANGUARD_RootShepard_Atzlan"
|
||||
const val VANGUARD_Resinant_Atzlan = "VANGUARD_Resinant_Atzlan"
|
||||
const val VANGUARD_BoneStalker_Xol = "VANGUARD_BoneStalker_Xol"
|
||||
const val VANGUARD_WhiteWoodReaper_Xol = "VANGUARD_WhiteWoodReaper_Xol"
|
||||
const val VANGUARD_DreadSister_Mala = "VANGUARD_DreadSister_Mala"
|
||||
const val VANGUARD_Incubator_Mala = "VANGUARD_Incubator_Mala"
|
||||
|
||||
const val WORKER_Mote = "WORKER_Mote"
|
||||
const val WORKER_Symbiote = "WORKER_Symbiote"
|
||||
|
||||
const val UNIT_Sipari = "UNIT_Sipari"
|
||||
const val UNIT_Zephyr = "UNIT_Zephyr"
|
||||
const val UNIT_Magi = "UNIT_Magi"
|
||||
const val UNIT_Dervish = "UNIT_Dervish"
|
||||
const val UNIT_Absolver = "UNIT_Absolver"
|
||||
const val UNIT_Hallower = "UNIT_Hallower"
|
||||
const val UNIT_Castigator = "UNIT_Castigator"
|
||||
const val UNIT_Warden = "UNIT_Warden"
|
||||
const val UNIT_Sentinel = "UNIT_Sentinel"
|
||||
const val UNIT_Throne = "UNIT_Throne"
|
||||
const val UNIT_SharU = "UNIT_SharU"
|
||||
const val UNIT_MaskedHunter = "UNIT_MaskedHunter"
|
||||
const val UNIT_Bloodbound = "UNIT_Bloodbound"
|
||||
const val UNIT_BloodAnchor = "UNIT_BloodAnchor"
|
||||
const val UNIT_Xacal = "UNIT_Xacal"
|
||||
const val UNIT_RedSeer = "UNIT_RedSeer"
|
||||
const val UNIT_Godphage = "cdc0398d-0173-4c8a-808c-053192712f05"
|
||||
const val UNIT_Ichor = "ff4355f1-ac0c-4ea1-8a47-ef6791252bb9"
|
||||
const val UNIT_WraithBow = "UNIT_WraithBow"
|
||||
const val UNIT_Underspine = "UNIT_Underspine"
|
||||
const val UNIT_Aarox = "UNIT_Aarox"
|
||||
const val UNIT_Thrum = "UNIT_Thrum"
|
||||
const val UNIT_Behemoth = "3783004b-65fd-4e4e-bef0-4cf161ea2d2d"
|
||||
const val SUMMON_Quitl = "d554fb2a-eec5-45fd-bf36-a52d51e615e2"
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class EntityFactionModel : IEntityPartInterface() {
|
||||
var faction: String = IdsEntity.FACTION_QRath
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.ResourceType
|
||||
|
||||
class EntityHarvestModel : IEntityPartInterface() {
|
||||
var resource: ResourceType = ResourceType.Alloy
|
||||
var slots: Float = 0f
|
||||
var harvestedPerInterval: Float = 0f
|
||||
var harvestDelay: Float = 1f
|
||||
var totalAmount: Int = 0
|
||||
var requiresWorker: Boolean = false
|
||||
|
||||
fun isDepleted(interval: Float, startedAt: Float): Boolean {
|
||||
val lifeTime = interval - startedAt
|
||||
val totalHarvested = lifeTime * harvestedPerInterval
|
||||
return totalHarvested > totalAmount
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityHotkeyModel : IEntityPartInterface() {
|
||||
var hotkey: String = ""
|
||||
var holdSpace: Boolean = false
|
||||
var hotkeyGroup: String = ""
|
||||
|
||||
fun isSelectedHotkey(keys: List<String>): Boolean {
|
||||
return keys.contains(hotkey.uppercase())
|
||||
}
|
||||
|
||||
fun isSelectedHotkeyGroup(keys: List<String>): Boolean {
|
||||
return keys.contains(hotkeyGroup.uppercase())
|
||||
}
|
||||
|
||||
fun isSelectedHoldSpace(keys: List<String>): Boolean {
|
||||
return (keys.contains("SPACE") || keys.contains(" ")) == holdSpace
|
||||
}
|
||||
|
||||
fun isSelectedHotkeyGroupWithSpace(keys: List<String>): Boolean {
|
||||
var foundKey = false
|
||||
var foundHold = false
|
||||
for (key in keys) {
|
||||
if (key.uppercase() == hotkeyGroup.uppercase()) foundKey = true
|
||||
if (key.uppercase() == "SPACE" || key.uppercase() == " ") foundHold = true
|
||||
}
|
||||
return foundKey && foundHold == holdSpace
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdAbilityModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdArmyModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdPassiveModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdPyreSpellModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdUpgradeModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityIdVanguardModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.DescriptiveType
|
||||
|
||||
class EntityInfoModel : IEntityPartInterface() {
|
||||
var name: String = ""
|
||||
var descriptive: String = DescriptiveType.None
|
||||
var description: String = ""
|
||||
var notes: String = ""
|
||||
var flavorText: String = ""
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityMechanicModel : IEntityPartInterface() {
|
||||
var name: String = ""
|
||||
var description: String = ""
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.MovementType
|
||||
|
||||
class EntityMovementModel : IEntityPartInterface() {
|
||||
var speed: Float = 0f
|
||||
var movement: String = MovementType.Ground
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityPassiveModel : IEntityPartInterface() {
|
||||
var name: String = ""
|
||||
var description: String = ""
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityProductionModel : IEntityPartInterface() {
|
||||
var alloy: Int = 0
|
||||
var ether: Int = 0
|
||||
var pyre: Int = 0
|
||||
var energy: Int = 0
|
||||
var defensiveLayer: Int = 0
|
||||
var buildTime: Int = 0
|
||||
var cooldown: Float = 0f
|
||||
var requiresWorker: Boolean = false
|
||||
var consumesWorker: Boolean = false
|
||||
var producedBy: String? = null
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityPyreRewardModel : IEntityPartInterface() {
|
||||
var baseReward: Int = 0
|
||||
var overTimeReward: Float = 0f
|
||||
var overTimeRewardDuration: Int = 0
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.RequirementType
|
||||
|
||||
class EntityRequirementModel : IEntityPartInterface() {
|
||||
var id: String = ""
|
||||
var requirement: String = RequirementType.Production_Building
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityResearchCapacityModel : IEntityPartInterface() {
|
||||
var slots: Int = 16
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityStrategyModel : IEntityPartInterface() {
|
||||
var notes: String = ""
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntitySupplyModel : IEntityPartInterface() {
|
||||
var takes: Int = 0
|
||||
var grants: Int = 0
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityTierModel : IEntityPartInterface() {
|
||||
var tier: Float = 0f
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
class EntityTrainingCapacityModel : IEntityPartInterface() {
|
||||
var slots: Int = 16
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class EntityVanguardAddedModel : IEntityPartInterface() {
|
||||
var immortalId: String = IdsEntity.IMMORTAL_Ajari
|
||||
var replaceId: String = ""
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
|
||||
class EntityVanguardReplacedModel : IEntityPartInterface() {
|
||||
var immortalId: String = IdsEntity.IMMORTAL_Xol
|
||||
var replacedById: String = ""
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.ArmourType
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.DefenseType
|
||||
|
||||
class EntityVitalityModel : IEntityPartInterface() {
|
||||
var health: Int = 0
|
||||
var defenseLayer: Int = 0
|
||||
var lasts: Int = 0
|
||||
var defense: String = DefenseType.None
|
||||
var armor: String = ArmourType.Light
|
||||
var isEtheric: Boolean = false
|
||||
var isStructure: Boolean = false
|
||||
var energy: Int = 0
|
||||
var vision: Int = 0
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.AttackType
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.TargetType
|
||||
|
||||
class EntityWeaponModel : IEntityPartInterface() {
|
||||
var id: Int = 1
|
||||
var entityModelId: Int = 0
|
||||
var range: Int = 40
|
||||
var minimumRange: Int = 0
|
||||
var attacksPerSecond: Float = 0f
|
||||
var secondsBetweenAttacks: Float = 0f
|
||||
var cooldown: Float = 0f
|
||||
var charges: Float = 0f
|
||||
var damage: Int = 0
|
||||
var complexDamage: String = "deals 126 over 6 seconds"
|
||||
var hasSplash: Boolean = false
|
||||
var lightDamage: Int = 0
|
||||
var mediumDamage: Int = 0
|
||||
var heavyDamage: Int = 0
|
||||
var structureDamageBonus: Int = 0
|
||||
var ethericDamageBonus: Int = 0
|
||||
var targets: String = TargetType.All
|
||||
var attack: String = AttackType.DPS
|
||||
|
||||
fun damagePerSecond(): Float {
|
||||
if (secondsBetweenAttacks == 0f) return damage * attacksPerSecond
|
||||
return damage / secondsBetweenAttacks
|
||||
}
|
||||
|
||||
fun damagePerSecondLight(): Float {
|
||||
val dmg = if (lightDamage != 0) lightDamage else damage
|
||||
if (secondsBetweenAttacks == 0f) return dmg * attacksPerSecond
|
||||
return dmg / secondsBetweenAttacks
|
||||
}
|
||||
|
||||
fun damagePerSecondMedium(): Float {
|
||||
val dmg = if (mediumDamage != 0) mediumDamage else damage
|
||||
if (secondsBetweenAttacks == 0f) return dmg * attacksPerSecond
|
||||
return dmg / secondsBetweenAttacks
|
||||
}
|
||||
|
||||
fun damagePerSecondHeavy(): Float {
|
||||
val dmg = if (heavyDamage != 0) heavyDamage else damage
|
||||
if (secondsBetweenAttacks == 0f) return dmg * attacksPerSecond
|
||||
return dmg / secondsBetweenAttacks
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.parts
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
|
||||
open class IEntityPartInterface {
|
||||
var parent: EntityModel? = null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object ArmourType {
|
||||
const val Light = "Light"
|
||||
const val Medium = "Medium"
|
||||
const val Heavy = "Heavy"
|
||||
const val Etheric = "Etheric"
|
||||
const val Structure = "Structure"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object AttackType {
|
||||
const val DPS = "DPS"
|
||||
const val Charges = "Charges"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object BuildType {
|
||||
const val Eco = "Eco"
|
||||
const val Harass = "Harass"
|
||||
const val Pyre_Hunting = "Pyre_Hunting"
|
||||
const val Timing = "Timing"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object DefenseType {
|
||||
const val None = "None"
|
||||
const val Shield = "Shield"
|
||||
const val Overgrowth = "Overgrowth"
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object DescriptiveType {
|
||||
const val None = "None"
|
||||
const val Frontliner = "Frontliner"
|
||||
const val Support = "Support"
|
||||
const val Generalist = "Generalist"
|
||||
const val ZoneControl = "Zone Control"
|
||||
const val AirKiller = "Air Killer"
|
||||
const val Dislodger = "Dislodger"
|
||||
const val EliteCaster = "Elite_Caster"
|
||||
const val DamageCaster = "Damage Caster"
|
||||
const val Worker = "Worker"
|
||||
const val Skirmisher = "Skirmisher"
|
||||
const val TownHall_Starting = "Town_Hall_Starting"
|
||||
const val Stronghold = "Stronghold"
|
||||
const val Economy = "Economy"
|
||||
const val Training = "Training"
|
||||
const val Technology = "Technology"
|
||||
const val Defense = "Defense"
|
||||
const val Summon = "Summon"
|
||||
const val Upgrade = "Upgrade"
|
||||
const val Ability = "Ability"
|
||||
const val Passive = "Passive"
|
||||
const val Applies_Debuff = "Applies_Debuff"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object MovementType {
|
||||
const val Ground = "Ground"
|
||||
const val Hover = "Hover"
|
||||
const val Air = "Air"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object RequirementType {
|
||||
const val Production_Building = "Production_Building"
|
||||
const val Research_Building = "Research_Building"
|
||||
const val Research_Upgrade = "Research_Upgrade"
|
||||
const val Morph = "Morph"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
enum class ResourceType {
|
||||
Alloy,
|
||||
Ether,
|
||||
Pyre
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.entity.types
|
||||
|
||||
object TargetType {
|
||||
const val Ground = "Ground"
|
||||
const val Air = "Air"
|
||||
const val All = "All"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.feedback
|
||||
|
||||
object SeverityType {
|
||||
const val Warning = "Warning"
|
||||
const val Information = "Information"
|
||||
const val Error = "Error"
|
||||
const val Success = "Success"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.feedback
|
||||
|
||||
class ToastModel {
|
||||
var title: String = "addTitle"
|
||||
var message: String = "addMessage"
|
||||
var severityType: String = "addType"
|
||||
var age: Float = 0f
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.hotkeys
|
||||
|
||||
enum class KeyType {
|
||||
Action,
|
||||
ControlGroup,
|
||||
Army,
|
||||
Train,
|
||||
Research,
|
||||
Construct,
|
||||
Cancel,
|
||||
Advance,
|
||||
Economy,
|
||||
Pyre
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.hotkeys
|
||||
|
||||
class HotkeyModel {
|
||||
var keyText: String = ""
|
||||
var keyType: KeyType = KeyType.Action
|
||||
var positionX: Int = 0
|
||||
var positionY: Int = 0
|
||||
var isHidden: Boolean = false
|
||||
var width: Int = 1
|
||||
|
||||
fun getColor(): String {
|
||||
return when (keyType) {
|
||||
KeyType.Action -> "#404146"
|
||||
KeyType.Cancel -> "#621b1b"
|
||||
KeyType.ControlGroup -> "#443512"
|
||||
KeyType.Army -> "#443512"
|
||||
KeyType.Train -> "#124443"
|
||||
KeyType.Research -> "#221244"
|
||||
KeyType.Construct -> "#122844"
|
||||
KeyType.Pyre -> "#441212"
|
||||
KeyType.Advance -> "#23262c"
|
||||
KeyType.Economy -> "#262c23"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val keyGroups: Array<String> = arrayOf("Z", "1", "2", "X", "CONTROL", "SHIFT", "C")
|
||||
val hotKeys: Array<String> = arrayOf("`", "Q", "W", "E", "R", "A", "S", "F", "X", "V", "CAPSLOCK", "TAB")
|
||||
|
||||
fun getAll(): List<HotkeyModel> {
|
||||
return listOf(
|
||||
HotkeyModel().apply {
|
||||
keyText = "Z"; keyType = KeyType.Train; positionX = 1; positionY = 3
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "D"; keyType = KeyType.Army; positionX = 3; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "C"; keyType = KeyType.Construct; positionX = 3; positionY = 3
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "V"; keyType = KeyType.Pyre; positionX = 4; positionY = 3
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "X"; keyType = KeyType.Research; positionX = 2; positionY = 3
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "`"; keyType = KeyType.Cancel; positionX = 0; positionY = 0
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "TAB"; keyType = KeyType.Action; positionX = 0; positionY = 1
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "Q"; keyType = KeyType.Action; positionX = 1; positionY = 1
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "W"; keyType = KeyType.Action; positionX = 2; positionY = 1
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "E"; keyType = KeyType.Action; positionX = 3; positionY = 1
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "R"; keyType = KeyType.Action; positionX = 4; positionY = 1
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "CAPSLOCK"; keyType = KeyType.Action; positionX = 0; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "A"; keyType = KeyType.Action; positionX = 1; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "S"; keyType = KeyType.Action; positionX = 2; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "D"; keyType = KeyType.ControlGroup; positionX = 3; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "F"; keyType = KeyType.Action; positionX = 4; positionY = 2
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "SPACE"; keyType = KeyType.Advance; positionX = 1; positionY = 4; width = 4
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "SHIFT"; keyType = KeyType.Economy; positionX = 0; positionY = 3
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "ALT"; keyType = KeyType.Economy; positionX = 1; positionY = 5; isHidden = true
|
||||
},
|
||||
HotkeyModel().apply {
|
||||
keyText = "CONTROL"; keyType = KeyType.Economy; positionX = 0; positionY = 4
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.hotkeys
|
||||
|
||||
enum class HotKeyType {
|
||||
SPACE
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.memorytester
|
||||
|
||||
class AnswerEventArgs {
|
||||
var name: String = ""
|
||||
var isCorrect: Boolean = false
|
||||
var guess: Int = 0
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.memorytester
|
||||
|
||||
class MemoryEntityModel {
|
||||
var id: Int = 0
|
||||
var name: String = ""
|
||||
|
||||
companion object {
|
||||
val testData: List<MemoryEntityModel> = listOf(
|
||||
MemoryEntityModel().apply { id = 1; name = "Masked Hunter" },
|
||||
MemoryEntityModel().apply { id = 2; name = "Scepter" },
|
||||
MemoryEntityModel().apply { id = 3; name = "Wraith Bow" },
|
||||
MemoryEntityModel().apply { id = 4; name = "Thrum" }
|
||||
)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.memorytester
|
||||
|
||||
class MemoryQuestionModel {
|
||||
var id: Int = 0
|
||||
var memoryEntityModelId: Int = 0
|
||||
var name: String = ""
|
||||
var guess: Int = 0
|
||||
var answer: Int = 0
|
||||
var isRevealed: Boolean = false
|
||||
|
||||
companion object {
|
||||
val testData: List<MemoryQuestionModel> = listOf(
|
||||
MemoryQuestionModel().apply {
|
||||
id = 1; memoryEntityModelId = 1; name = "Range"; answer = 600; isRevealed = false
|
||||
},
|
||||
MemoryQuestionModel().apply {
|
||||
id = 2; memoryEntityModelId = 2; name = "Range"; answer = 600; isRevealed = false
|
||||
},
|
||||
MemoryQuestionModel().apply {
|
||||
id = 3; memoryEntityModelId = 3; name = "Range"; answer = 600; isRevealed = false
|
||||
},
|
||||
MemoryQuestionModel().apply {
|
||||
id = 4; memoryEntityModelId = 4; name = "Range"; answer = 600; isRevealed = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.notes
|
||||
|
||||
class NoteConnectionModel {
|
||||
var id: Int = 1
|
||||
var parentId: Int = 1
|
||||
var childId: Int = 1
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.notes
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.SearchPointModel
|
||||
|
||||
class NoteContentModel {
|
||||
var id: Int = 0
|
||||
var parentId: Int? = null
|
||||
var noteSectionModelId: Int? = null
|
||||
var href: String = ""
|
||||
var createdDate: String = ""
|
||||
var updatedDate: String = ""
|
||||
var name: String = ""
|
||||
var description: String = ""
|
||||
var content: String = ""
|
||||
var loadedContent: String = ""
|
||||
var isHidden: String = "False"
|
||||
var isPreAlpha: String = "True"
|
||||
var noteContentModels: MutableList<NoteContentModel> = mutableListOf()
|
||||
var parent: NoteContentModel? = null
|
||||
var pageOrder: Int = 0
|
||||
|
||||
fun getHeaders(): List<SearchPointModel> {
|
||||
val regex = Regex("""^#* (.*)$""", RegexOption.MULTILINE)
|
||||
val listOfMatches = regex.findAll(loadedContent)
|
||||
|
||||
return listOfMatches.map { capture ->
|
||||
var cleanUp = capture.value.lowercase()
|
||||
cleanUp = cleanUp.replace("#", "")
|
||||
cleanUp = cleanUp.replace("\"", "")
|
||||
cleanUp = cleanUp.trim()
|
||||
cleanUp = cleanUp.replace(" ", "-")
|
||||
SearchPointModel().apply {
|
||||
title = capture.value.trim()
|
||||
href = cleanUp
|
||||
}
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private fun getLink(): String {
|
||||
val link = href
|
||||
return if (parent != null) "${parent!!.getLink()}/$link" else link
|
||||
}
|
||||
|
||||
fun getNoteLink(): String {
|
||||
return "notes/${getLink()}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.notes
|
||||
|
||||
class NoteFrontMatterModel {
|
||||
var title: String = ""
|
||||
var summary: String = ""
|
||||
var createdDate: String = ""
|
||||
var updatedDate: String = ""
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.notes
|
||||
|
||||
class NoteSectionModel {
|
||||
var id: Int = 0
|
||||
var name: String = ""
|
||||
var noteContentModels: MutableList<NoteContentModel> = mutableListOf()
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.repository
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.WebPageModel
|
||||
|
||||
object WebsiteData {
|
||||
fun getPages(): List<WebPageModel> {
|
||||
return listOf(
|
||||
WebPageModel().apply {
|
||||
id = 2
|
||||
webSectionModelId = 2
|
||||
name = "Build Calculator"
|
||||
description = "Build order calculator for determining army timings"
|
||||
href = "build-calculator"
|
||||
isPrivate = "False"
|
||||
icon = "fa-solid fa-helmet-battle"
|
||||
},
|
||||
WebPageModel().apply {
|
||||
id = 1
|
||||
webSectionModelId = 2
|
||||
name = "Database"
|
||||
description = "Database of game information"
|
||||
href = "database"
|
||||
isPrivate = "False"
|
||||
icon = "fa-solid fa-clipboard-list"
|
||||
},
|
||||
WebPageModel().apply {
|
||||
id = 3
|
||||
webSectionModelId = 2
|
||||
name = "Harass Calculator"
|
||||
description = "Database of game information"
|
||||
href = "harass-calculator"
|
||||
isPrivate = "False"
|
||||
icon = "fa-solid fa-bow-arrow"
|
||||
},
|
||||
WebPageModel().apply {
|
||||
id = 4
|
||||
webSectionModelId = 2
|
||||
name = "Data Tables"
|
||||
description = "Data tables"
|
||||
href = "data-tables"
|
||||
isPrivate = "False"
|
||||
icon = "fa-solid fa-table-list"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.roadmap
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.roadmap.enums.ReleasePriorityType
|
||||
import ca.jonathanmccaffrey.igp.data.models.roadmap.enums.ReleaseStatusType
|
||||
|
||||
class ImmortalRoadMapModel {
|
||||
var name: String = ""
|
||||
var description: String = ""
|
||||
var priority: String = ReleasePriorityType.High
|
||||
var status: String = ReleaseStatusType.In_Development
|
||||
|
||||
companion object {
|
||||
val data: List<ImmortalRoadMapModel> = listOf(
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "UI Overhaul"
|
||||
description = "In the process of redoing the UI. Perhaps add 'Making Of' page for development related details, including a visual list of all components used, for ease of design reference. Ideally avoid menu bloat. Database, Build Calculator, Notes and Documentation, should be obvious main pages. Review 900px width on all pages."
|
||||
priority = ReleasePriorityType.High
|
||||
status = ReleaseStatusType.In_Development
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Build Calculator Improvements"
|
||||
description = "The Calculator will be optimized to perform faster. It needs to be updated to consider training queue limits. Also, it needs error popups added for not enough ether, not enough supply, or no more interval time."
|
||||
priority = ReleasePriorityType.High
|
||||
status = ReleaseStatusType.In_Development
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Build Calculator Pyre"
|
||||
description = "Build calculator should also handle pyre generation over time. 2 key will represent taking pyre camps. Make sure people can mark \"casted\" pyre spells as a part of the build order."
|
||||
priority = ReleasePriorityType.Medium
|
||||
status = ReleaseStatusType.Planned
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Build Comparisons"
|
||||
description = "You should be able to calculate two builds and load them against each other. Compare armies over time, to see when it would be best to strike against a certain build, and when it would be too late."
|
||||
priority = ReleasePriorityType.Medium
|
||||
status = ReleaseStatusType.Planned
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Notes"
|
||||
description = "There should be general notes on how to play Immortal. Nothing too extensive, but general faction and gameplay feel, like mentioning mechanics like Overgrowth for Aru and Wards for Q'Rath. Interesting but basic lore notes are also ideal, but all of these notes still need to be sortable in a method that feels natural, not a giant text bloat."
|
||||
priority = ReleasePriorityType.High
|
||||
status = ReleaseStatusType.In_Development
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Documentation"
|
||||
description = "There should be documents on how to use this website. Calculator, Database, etc. Ideally, these documents will be designed in a way that becomes easily maintainable with patches. (Currently, some QA document type stuff is appended to the bottom of each tool page.) Add a button to easily go from the current tool, to its matching documented."
|
||||
priority = ReleasePriorityType.Medium
|
||||
status = ReleaseStatusType.Planned
|
||||
},
|
||||
ImmortalRoadMapModel().apply {
|
||||
name = "Test Automation"
|
||||
description = "All patches should be tested via test automation, to avoid obvious bugs from getting into production. Add a informational test automation page to the Development section."
|
||||
priority = ReleasePriorityType.Medium
|
||||
status = ReleaseStatusType.Planned
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.roadmap.enums
|
||||
|
||||
object ReleasePriorityType {
|
||||
const val High = "High"
|
||||
const val Medium = "Medium"
|
||||
const val Low = "Low"
|
||||
const val Very_Low = "Very_Low"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.roadmap.enums
|
||||
|
||||
object ReleaseStatusType {
|
||||
const val In_Development = "In_Development"
|
||||
const val Done = "Done"
|
||||
const val Future_Possibility = "Future_Possibility"
|
||||
const val Planned = "Planned"
|
||||
const val Cancelled = "Cancelled"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
class SearchPointModel {
|
||||
var title: String = ""
|
||||
var summary: String = ""
|
||||
var tags: String = ""
|
||||
var pointType: String = ""
|
||||
var href: String = ""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
object SupportedWebSizes {
|
||||
const val Tablet = "479px"
|
||||
const val Desktop = "1024px"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.enums.WebDeploymentType
|
||||
|
||||
object WebDeploymentModel {
|
||||
var deploymentType: WebDeploymentType = WebDeploymentType.Private
|
||||
|
||||
fun get(): List<String> {
|
||||
return if (deploymentType == WebDeploymentType.Immortal) getImmortal() else emptyList()
|
||||
}
|
||||
|
||||
private fun getImmortal(): List<String> {
|
||||
return listOf(
|
||||
"",
|
||||
"build-calculator",
|
||||
"comparison-charts",
|
||||
"database"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.enums.WebSectionType
|
||||
|
||||
class WebDescriptionModel {
|
||||
var name: String = "Add Name"
|
||||
var description: String = "Add description"
|
||||
var parent: String = WebSectionType.None
|
||||
var isPrivate: Boolean = true
|
||||
|
||||
companion object {
|
||||
val list: MutableList<WebDescriptionModel> = mutableListOf()
|
||||
|
||||
fun getPages(forSection: String): List<WebDescriptionModel> {
|
||||
return list.filter { it.parent == forSection }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
class WebPageModel {
|
||||
var id: Int = 0
|
||||
var webSectionModelId: Int? = null
|
||||
var name: String = "Add name"
|
||||
var description: String = "Add description"
|
||||
var href: String? = null
|
||||
var isPrivate: String = "True"
|
||||
var icon: String = ""
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website
|
||||
|
||||
class WebSectionModel {
|
||||
var id: Int = 0
|
||||
var name: String = "Add name"
|
||||
var description: String = "Add description"
|
||||
var order: Int = 0
|
||||
var isPrivate: String = "True"
|
||||
var icon: String = "fa-icons"
|
||||
var onlyIcon: Boolean = false
|
||||
var webPageModels: MutableList<WebPageModel> = mutableListOf()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website.enums
|
||||
|
||||
enum class NavSelectionType {
|
||||
None,
|
||||
Section,
|
||||
Page
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website.enums
|
||||
|
||||
object NavigationStateType {
|
||||
const val Default = "Default"
|
||||
const val Hovering_Menu = "Hovering_Menu"
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website.enums
|
||||
|
||||
enum class WebDeploymentType {
|
||||
Private,
|
||||
Public,
|
||||
Immortal
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website.enums
|
||||
|
||||
object WebPageType {
|
||||
// TODO Deprecated
|
||||
val None = "725d1adb-d5c8-4e51-bafb-09c86a94d0b0"
|
||||
val IMMORTAL_About = "16e56a46-e593-4de5-a2ff-272b41a28d99"
|
||||
val IMMORTAL_BuildCalculator = "c3abee8c-6b10-426d-8a7f-9042e536c007"
|
||||
val IMMORTAL_MemoryTester = "1234"
|
||||
val IMMORTAL_ChartComparision = "72ff145b-cfe0-454d-ae8f-ee977007eb73"
|
||||
val IMMORTAL_Database = "2602b6ff-24c8-4924-ac59-3d7ad9dbca6b"
|
||||
val IMMORTAL_HarassCalculator = "617547c2-c89a-4fa9-b063-5240d46d37b0"
|
||||
val IMMORTAL_Notes = "47fbdc7e-97e7-4046-8c91-23f80b87fb86"
|
||||
val IMMORTAL_KeyMapping = "315118a1-1d94-4237-a254-76de4ede845a"
|
||||
val IMMORTAL_RoadMap = "119ddb93-ac4c-4481-9b89-91111201c543"
|
||||
val IMMORTAL_Documentation = "f1a0a435-90ba-4cb3-8ae4-e27e1a249aa1"
|
||||
val IMMORTAL_MakingOf = "532c08ed-c9ac-4425-b882-b5501127a567"
|
||||
val IMMORTAL_Contact = "37dcbee4-53d9-4cbb-997c-445c2536dde8"
|
||||
val IMMORTAL_ChangeLog = "36d459b4-4126-42f8-a391-222af8291c9c"
|
||||
val IMMORTAL_Agile = "29a152d2-744a-4567-ba6a-68538c6462ae"
|
||||
val IMMORTAL_Streams = "7f375283-83fa-44cf-8fe1-4b8cbd45007e"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ca.jonathanmccaffrey.igp.data.models.website.enums
|
||||
|
||||
object WebSectionType {
|
||||
val None = "28eefe79-3808-48da-8665-3eab5aebca1d"
|
||||
val ImmortalGeneral = "1a7dce11-57ff-453e-abac-6eeab01b9a61"
|
||||
val ImmortalTools = "c68afaa1-23b6-4ead-9622-797781bb4575"
|
||||
val ImmortalResources = "3baddebc-e570-4855-946e-296b823411d6"
|
||||
val ImmortalDevelopment = "df411a6f-2389-404b-b4fb-a86ebb764ecc"
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package ca.jonathanmccaffrey.igp.di
|
||||
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.BuildOrderService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.EconomyComparisonService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.EconomyService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.EntityFilterService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.EntityService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.ImmortalSelectionService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.KeyService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.MemoryTesterService
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.TimingService
|
||||
import ca.jonathanmccaffrey.igp.services.website.DataCollectionService
|
||||
import ca.jonathanmccaffrey.igp.services.website.EntityDialogService
|
||||
import ca.jonathanmccaffrey.igp.services.website.MyDialogService
|
||||
import ca.jonathanmccaffrey.igp.services.website.NavigationService
|
||||
import ca.jonathanmccaffrey.igp.services.website.PermissionService
|
||||
import ca.jonathanmccaffrey.igp.services.website.SearchService
|
||||
import ca.jonathanmccaffrey.igp.services.website.StorageService
|
||||
import ca.jonathanmccaffrey.igp.services.website.ToastService
|
||||
import ca.jonathanmccaffrey.igp.services.development.NoteService
|
||||
import android.content.Context
|
||||
|
||||
object ServiceLocator {
|
||||
fun initialize(context: Context) {
|
||||
toastService = ToastService()
|
||||
storageService = StorageService(context, toastService)
|
||||
permissionService = PermissionService(storageService)
|
||||
dataCollectionService = DataCollectionService(storageService)
|
||||
navigationService = NavigationService()
|
||||
entityDialogService = EntityDialogService()
|
||||
myDialogService = MyDialogService()
|
||||
entityFilterService = EntityFilterService()
|
||||
entityService = EntityService()
|
||||
timingService = TimingService(storageService)
|
||||
buildOrderService = BuildOrderService(toastService, timingService)
|
||||
economyService = EconomyService()
|
||||
keyService = KeyService()
|
||||
memoryTesterService = MemoryTesterService()
|
||||
economyComparisonService = EconomyComparisonService()
|
||||
noteService = NoteService(context)
|
||||
searchService = SearchService(noteService)
|
||||
immortalSelectionService = ImmortalSelectionService(storageService)
|
||||
}
|
||||
|
||||
lateinit var toastService: ToastService
|
||||
lateinit var searchService: SearchService
|
||||
lateinit var permissionService: PermissionService
|
||||
lateinit var storageService: StorageService
|
||||
lateinit var dataCollectionService: DataCollectionService
|
||||
lateinit var navigationService: NavigationService
|
||||
lateinit var entityDialogService: EntityDialogService
|
||||
lateinit var myDialogService: MyDialogService
|
||||
lateinit var entityFilterService: EntityFilterService
|
||||
lateinit var entityService: EntityService
|
||||
lateinit var immortalSelectionService: ImmortalSelectionService
|
||||
lateinit var buildOrderService: BuildOrderService
|
||||
lateinit var economyService: EconomyService
|
||||
lateinit var timingService: TimingService
|
||||
lateinit var keyService: KeyService
|
||||
lateinit var memoryTesterService: MemoryTesterService
|
||||
lateinit var economyComparisonService: EconomyComparisonService
|
||||
lateinit var noteService: NoteService
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
package ca.jonathanmccaffrey.igp.services
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.buildorder.BuildToCompareModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.economy.EconomyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.feedback.ToastModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.memorytester.MemoryEntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.memorytester.MemoryQuestionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteConnectionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteContentModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteSectionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.SearchPointModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.website.enums.NavSelectionType
|
||||
import ca.jonathanmccaffrey.igp.services.immortal.MemoryTesterEvent
|
||||
import ca.jonathanmccaffrey.igp.services.website.DialogContents
|
||||
import ca.jonathanmccaffrey.igp.services.website.EntityFilterEvent
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
typealias EntityFilterAction = (EntityFilterEvent) -> Unit
|
||||
typealias MemoryAction = (MemoryTesterEvent) -> Unit
|
||||
|
||||
interface IToastService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun addToast(toast: ToastModel)
|
||||
fun removeToast(toast: ToastModel)
|
||||
fun hasToasts(): Boolean
|
||||
fun getToasts(): List<ToastModel>
|
||||
fun ageToasts()
|
||||
fun clearAllToasts()
|
||||
}
|
||||
|
||||
interface IDataCollectionService {
|
||||
fun sendEvent(eventName: String)
|
||||
}
|
||||
|
||||
interface IStorageService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun <T> getValue(key: String, default: T): T
|
||||
fun <T> setValue(key: String, value: T)
|
||||
|
||||
suspend fun load()
|
||||
}
|
||||
|
||||
interface IPermissionService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun getIsStorageEnabled(): Boolean
|
||||
fun getIsDataCollectionEnabled(): Boolean
|
||||
|
||||
fun setIsStorageEnabled(isEnabled: Boolean)
|
||||
fun setIsDataCollectionEnabled(isEnabled: Boolean)
|
||||
}
|
||||
|
||||
interface ISearchService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
var searchPoints: MutableList<SearchPointModel>
|
||||
val searches: MutableMap<String, MutableList<SearchPointModel>>
|
||||
var isVisible: Boolean
|
||||
|
||||
fun search(entityId: String)
|
||||
suspend fun load()
|
||||
fun isLoaded(): Boolean
|
||||
fun show()
|
||||
fun hide()
|
||||
}
|
||||
|
||||
interface IMyDialogService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
var isVisible: Boolean
|
||||
fun show(dialogContents: DialogContents)
|
||||
fun getDialogContents(): DialogContents
|
||||
fun hide()
|
||||
}
|
||||
|
||||
interface IEconomyComparisonService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
val buildsToCompare: MutableList<BuildToCompareModel>
|
||||
|
||||
fun changeNumberOfTownHalls(forPlayer: Int, toCount: Int)
|
||||
fun changeTownHallTiming(forPlayer: Int, forTownHall: Int, toTiming: Int)
|
||||
fun getTownHallCount(forPlayer: Int): Int
|
||||
fun getTownHallBuildTime(forPlayer: Int, forTownHall: Int): Int
|
||||
fun getTownHallBuildTimes(forPlayer: Int): List<Int>
|
||||
fun changeFaction(forPlayer: Int, toFaction: String)
|
||||
fun getFaction(forPlayer: Int): String
|
||||
fun changeColor(forPlayer: Int, toColor: String)
|
||||
fun getColor(forPlayer: Int): String
|
||||
}
|
||||
|
||||
interface IEntityDialogService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun addDialog(entityId: String)
|
||||
fun closeDialog()
|
||||
fun backDialog()
|
||||
fun getEntityId(): String?
|
||||
fun hasDialog(): Boolean
|
||||
fun hasHistory(): Boolean
|
||||
}
|
||||
|
||||
interface INoteService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
var noteContentModels: MutableList<NoteContentModel>
|
||||
var noteConnectionModels: MutableList<NoteConnectionModel>
|
||||
var noteSectionModels: MutableList<NoteSectionModel>
|
||||
|
||||
fun update()
|
||||
suspend fun load()
|
||||
fun isLoaded(): Boolean
|
||||
}
|
||||
|
||||
interface INavigationService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun changeNavigationSectionId(newState: Int)
|
||||
fun getNavigationSectionId(): Int
|
||||
fun changeNavigationState(newState: String)
|
||||
fun getNavigationState(): String
|
||||
fun back()
|
||||
fun selectSection(webSectionType: Int)
|
||||
fun selectPage(pageType: Int, webPageType: kotlin.reflect.KClass<*>)
|
||||
|
||||
fun getNavSelectionType(): NavSelectionType
|
||||
fun getWebPageId(): Int
|
||||
fun getWebSectionId(): Int
|
||||
fun getRenderType(): kotlin.reflect.KClass<*>?
|
||||
}
|
||||
|
||||
interface IBuildComparisonService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun setBuilds(buildToCompareModel: BuildToCompareModel)
|
||||
fun get(): BuildToCompareModel
|
||||
fun buildOrderAsYaml(): String
|
||||
fun asJson(): String
|
||||
fun loadJson(data: String): Boolean
|
||||
}
|
||||
|
||||
interface ITimingService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
var buildingInputDelay: Int
|
||||
var waitTime: Int
|
||||
var waitTo: Int
|
||||
fun getAttackTime(): Int
|
||||
fun setAttackTime(timing: Int)
|
||||
fun getTravelTime(): Int
|
||||
fun setTravelTime(timing: Int)
|
||||
}
|
||||
|
||||
interface IEconomyService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun getOverTime(): List<EconomyModel>
|
||||
fun getEconomy(atInterval: Int): EconomyModel
|
||||
suspend fun calculate(buildOrder: IBuildOrderService, timing: ITimingService, fromInterval: Int)
|
||||
}
|
||||
|
||||
interface IEntityFilterService {
|
||||
val onChange: StateFlow<EntityFilterEvent>
|
||||
|
||||
fun getFactionType(): String
|
||||
fun getImmortalType(): String
|
||||
fun getEntityType(): String
|
||||
fun getSearchText(): String
|
||||
fun getFactionChoices(): List<String>
|
||||
fun getImmortalChoices(): List<String>
|
||||
fun getEntityChoices(): List<String>
|
||||
fun selectFactionType(factionType: String): Boolean
|
||||
fun selectImmortalType(immortalType: String): Boolean
|
||||
fun selectEntityType(entityType: String): Boolean
|
||||
fun enterSearchText(searchText: String): Boolean
|
||||
}
|
||||
|
||||
interface IEntityService {
|
||||
fun getEntities(): List<EntityModel>
|
||||
}
|
||||
|
||||
interface IEntityDisplayService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun defaultChoices(): List<String>
|
||||
fun getDisplayType(): String
|
||||
fun setDisplayType(displayType: String)
|
||||
}
|
||||
|
||||
interface IImmortalSelectionService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun getFaction(): String
|
||||
fun getImmortal(): String
|
||||
fun selectFaction(faction: String): Boolean
|
||||
fun selectImmortal(immortal: String): Boolean
|
||||
}
|
||||
|
||||
interface IKeyService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
fun getAllPressedKeys(): List<String>
|
||||
fun getHotkey(): String?
|
||||
fun getHotkeyGroup(): String
|
||||
fun isHoldingSpace(): Boolean
|
||||
fun addPressedKey(key: String): Boolean
|
||||
fun removePressedKey(key: String): Boolean
|
||||
}
|
||||
|
||||
interface IMemoryTesterService {
|
||||
val onChange: StateFlow<MemoryTesterEvent>
|
||||
|
||||
fun getEntities(): List<MemoryEntityModel>
|
||||
fun getQuestions(): List<MemoryQuestionModel>
|
||||
fun generateQuiz()
|
||||
fun update(question: MemoryQuestionModel)
|
||||
fun verify()
|
||||
}
|
||||
|
||||
interface IBuildOrderService {
|
||||
val onChange: StateFlow<Unit>
|
||||
|
||||
val startedOrders: Map<Int, List<EntityModel>>
|
||||
val completedOrders: Map<Int, List<EntityModel>>
|
||||
val depletedOrders: Map<Int, List<EntityModel>>
|
||||
val uniqueCompletedTimes: Map<String, Int>
|
||||
val supplyCountTimes: Map<Int, Int>
|
||||
|
||||
fun add(entity: EntityModel, withEconomy: IEconomyService): Boolean
|
||||
fun add(entity: EntityModel, atInterval: Int)
|
||||
fun addWait(forInterval: Int): Boolean
|
||||
fun addWaitTo(interval: Int): Boolean
|
||||
fun setName(name: String)
|
||||
fun getName(): String
|
||||
fun setNotes(notes: String)
|
||||
fun getNotes(): String
|
||||
fun deprecatedSetColor(color: String)
|
||||
fun getColor(): String
|
||||
fun willMeetRequirements(entity: EntityModel): Int?
|
||||
fun willMeetSupply(entity: EntityModel): Int?
|
||||
fun getOrders(): Map<Int, List<EntityModel>>
|
||||
fun getCompletedBefore(interval: Int): List<EntityModel>
|
||||
fun getUndepletedHarvestPointsCompletedBefore(interval: Int): List<EntityModel>
|
||||
fun removeLast()
|
||||
fun reset()
|
||||
fun getLastRequestInterval(): Int
|
||||
fun buildOrderAsYaml(): String
|
||||
fun asJson(): String
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package ca.jonathanmccaffrey.igp.services.development
|
||||
|
||||
import android.content.Context
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteConnectionModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteContentModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.notes.NoteSectionModel
|
||||
import ca.jonathanmccaffrey.igp.services.INoteService
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
class NoteService(
|
||||
private val context: Context
|
||||
) : INoteService {
|
||||
|
||||
private var isLoaded = false
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
override var noteContentModels: MutableList<NoteContentModel> = mutableListOf()
|
||||
override var noteConnectionModels: MutableList<NoteConnectionModel> = mutableListOf()
|
||||
override var noteSectionModels: MutableList<NoteSectionModel> = mutableListOf()
|
||||
var noteContentModelsByPageOrder: MutableList<NoteContentModel> = mutableListOf()
|
||||
|
||||
override fun isLoaded(): Boolean = isLoaded
|
||||
|
||||
override suspend fun load() {
|
||||
if (isLoaded) return
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
noteContentModels = loadNoteContents()
|
||||
noteConnectionModels = loadNoteConnections()
|
||||
noteSectionModels = loadNoteSections()
|
||||
|
||||
isLoaded = true
|
||||
sortSQL()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
_onChange.value = Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
private fun contentById(id: Int): NoteContentModel? {
|
||||
for (data in noteContentModels)
|
||||
if (data.id == id) return data
|
||||
return null
|
||||
}
|
||||
|
||||
private fun sortSQL() {
|
||||
for (connection in noteConnectionModels) {
|
||||
contentById(connection.parentId)?.noteContentModels?.add(contentById(connection.childId)!!)
|
||||
contentById(connection.childId)?.parent = contentById(connection.parentId)
|
||||
}
|
||||
|
||||
for (content in noteContentModels) {
|
||||
if (content.noteSectionModelId != null) {
|
||||
for (section in noteSectionModels) {
|
||||
if (section.id == content.noteSectionModelId) {
|
||||
section.noteContentModels.add(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byPageOrder()
|
||||
}
|
||||
|
||||
private fun byPageOrder() {
|
||||
noteContentModelsByPageOrder = mutableListOf()
|
||||
var order = 1
|
||||
|
||||
for (note in noteContentModels) {
|
||||
if (note.parent != null) continue
|
||||
|
||||
note.pageOrder = order++
|
||||
noteContentModelsByPageOrder.add(note)
|
||||
|
||||
fun getAllChildren(docs: NoteContentModel) {
|
||||
for (doc in docs.noteContentModels) {
|
||||
doc.pageOrder = order++
|
||||
noteContentModelsByPageOrder.add(doc)
|
||||
if (doc.noteContentModels.isNotEmpty()) getAllChildren(doc)
|
||||
}
|
||||
}
|
||||
|
||||
getAllChildren(note)
|
||||
}
|
||||
|
||||
noteContentModelsByPageOrder = noteContentModelsByPageOrder
|
||||
.sortedBy { it.pageOrder }
|
||||
.toMutableList()
|
||||
}
|
||||
|
||||
private fun readAssetText(fileName: String): String? {
|
||||
return try {
|
||||
context.assets.open(fileName).bufferedReader().use { it.readText() }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNoteContents(): MutableList<NoteContentModel> {
|
||||
val json = readAssetText("generated/NoteContentModels.json") ?: return mutableListOf()
|
||||
return try {
|
||||
val jsonArray = JSONArray(json)
|
||||
val result = mutableListOf<NoteContentModel>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val obj = jsonArray.getJSONObject(i)
|
||||
result.add(NoteContentModel().apply {
|
||||
id = obj.optInt("id")
|
||||
parentId = if (obj.isNull("parentId")) null else obj.optInt("parentId")
|
||||
noteSectionModelId = if (obj.isNull("noteSectionModelId")) null else obj.optInt("noteSectionModelId")
|
||||
href = obj.optString("href", "")
|
||||
createdDate = obj.optString("createdDate", "")
|
||||
updatedDate = obj.optString("updatedDate", "")
|
||||
name = obj.optString("name", "")
|
||||
description = obj.optString("description", "")
|
||||
content = obj.optString("content", "")
|
||||
loadedContent = obj.optString("loadedContent", "")
|
||||
isHidden = obj.optString("isHidden", "False")
|
||||
isPreAlpha = obj.optString("isPreAlpha", "True")
|
||||
})
|
||||
}
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
mutableListOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNoteConnections(): MutableList<NoteConnectionModel> {
|
||||
val json = readAssetText("generated/NoteConnectionModels.json") ?: return mutableListOf()
|
||||
return try {
|
||||
val jsonArray = JSONArray(json)
|
||||
val result = mutableListOf<NoteConnectionModel>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val obj = jsonArray.getJSONObject(i)
|
||||
result.add(NoteConnectionModel().apply {
|
||||
id = obj.optInt("id", 1)
|
||||
parentId = obj.optInt("parentId", 1)
|
||||
childId = obj.optInt("childId", 1)
|
||||
})
|
||||
}
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
mutableListOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNoteSections(): MutableList<NoteSectionModel> {
|
||||
val json = readAssetText("generated/NoteSectionModels.json") ?: return mutableListOf()
|
||||
return try {
|
||||
val jsonArray = JSONArray(json)
|
||||
val result = mutableListOf<NoteSectionModel>()
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val obj = jsonArray.getJSONObject(i)
|
||||
result.add(NoteSectionModel().apply {
|
||||
id = obj.optInt("id")
|
||||
name = obj.optString("name", "")
|
||||
})
|
||||
}
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
mutableListOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.buildorder.BuildOrderModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.buildorder.TrainingCapacityUsedModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.EntityType
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.DescriptiveType
|
||||
import ca.jonathanmccaffrey.igp.data.models.feedback.SeverityType
|
||||
import ca.jonathanmccaffrey.igp.data.models.feedback.ToastModel
|
||||
import ca.jonathanmccaffrey.igp.services.IBuildOrderService
|
||||
import ca.jonathanmccaffrey.igp.services.IEconomyService
|
||||
import ca.jonathanmccaffrey.igp.services.ITimingService
|
||||
import ca.jonathanmccaffrey.igp.services.IToastService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.json.JSONObject
|
||||
|
||||
class BuildOrderService(
|
||||
private val toastService: IToastService,
|
||||
private val timingService: ITimingService
|
||||
) : IBuildOrderService {
|
||||
|
||||
private val buildOrder = BuildOrderModel()
|
||||
private var lastInterval: Int = 0
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
override val startedOrders: Map<Int, List<EntityModel>> get() = buildOrder.startedOrders
|
||||
override val completedOrders: Map<Int, List<EntityModel>> get() = buildOrder.completedOrders
|
||||
override val depletedOrders: Map<Int, List<EntityModel>> get() = buildOrder.depletedOrders
|
||||
override val uniqueCompletedTimes: Map<String, Int> get() = buildOrder.uniqueCompletedTimes
|
||||
override val supplyCountTimes: Map<Int, Int> get() = buildOrder.supplyCountTimes
|
||||
|
||||
init {
|
||||
reset()
|
||||
}
|
||||
|
||||
override fun getLastRequestInterval(): Int = lastInterval
|
||||
|
||||
override fun getOrders(): Map<Int, List<EntityModel>> = buildOrder.startedOrders
|
||||
|
||||
override fun add(entity: EntityModel, atInterval: Int) {
|
||||
if (!buildOrder.startedOrders.containsKey(atInterval))
|
||||
buildOrder.startedOrders[atInterval] = mutableListOf()
|
||||
|
||||
val production = entity.production()
|
||||
val completedTime = atInterval + (production?.buildTime ?: 0)
|
||||
|
||||
if (!buildOrder.completedOrders.containsKey(completedTime))
|
||||
buildOrder.completedOrders[completedTime] = mutableListOf()
|
||||
|
||||
buildOrder.startedOrders[atInterval]!!.add(entity.clone())
|
||||
buildOrder.completedOrders[completedTime]!!.add(entity.clone())
|
||||
|
||||
buildOrder.uniqueCompletedTimes.putIfAbsent(entity.dataType, atInterval)
|
||||
|
||||
if (buildOrder.uniqueCompletedCount.putIfAbsent(entity.dataType, 1) != null)
|
||||
buildOrder.uniqueCompletedCount[entity.dataType] = buildOrder.uniqueCompletedCount[entity.dataType]!! + 1
|
||||
|
||||
if (!buildOrder.uniqueCompleted.containsKey(entity.dataType))
|
||||
buildOrder.uniqueCompleted[entity.dataType] = mutableListOf()
|
||||
|
||||
if (entity.production()?.producedBy != null)
|
||||
buildOrder.trainingCapacityUsed.add(
|
||||
TrainingCapacityUsedModel().apply {
|
||||
startingUsageTime = atInterval
|
||||
stopUsageTime = completedTime
|
||||
usedSlots = entity.supply()?.takes ?: 1
|
||||
usedBuilding = entity.production()!!.producedBy ?: ""
|
||||
}
|
||||
)
|
||||
|
||||
buildOrder.uniqueCompleted[entity.dataType]!!.add(entity)
|
||||
|
||||
if (entity.supply() != null && entity.supply()!!.takes > 0)
|
||||
buildOrder.currentSupplyUsed += entity.supply()!!.takes
|
||||
if (entity.supply() != null && entity.supply()!!.grants > 0)
|
||||
buildOrder.supplyCountTimes[buildOrder.supplyCountTimes.keys.last() + entity.supply()!!.grants] = completedTime
|
||||
|
||||
if (atInterval > lastInterval) lastInterval = atInterval
|
||||
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun addWait(forInterval: Int): Boolean {
|
||||
if (forInterval < 0) {
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
severityType = SeverityType.Error
|
||||
title = "Wait"
|
||||
message = "This should never happen."
|
||||
}
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
lastInterval += forInterval
|
||||
|
||||
if (!buildOrder.startedOrders.containsKey(lastInterval))
|
||||
buildOrder.startedOrders[lastInterval] = mutableListOf()
|
||||
|
||||
if (!buildOrder.completedOrders.containsKey(lastInterval))
|
||||
buildOrder.completedOrders[lastInterval] = mutableListOf()
|
||||
|
||||
_onChange.value = Unit
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addWaitTo(interval: Int): Boolean {
|
||||
if (interval <= lastInterval) {
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
severityType = SeverityType.Error
|
||||
title = "Logic Error"
|
||||
message = "You cannot wait to a time that has already elapsed."
|
||||
}
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
lastInterval = interval
|
||||
|
||||
if (!buildOrder.startedOrders.containsKey(lastInterval))
|
||||
buildOrder.startedOrders[lastInterval] = mutableListOf()
|
||||
|
||||
if (!buildOrder.completedOrders.containsKey(lastInterval))
|
||||
buildOrder.completedOrders[lastInterval] = mutableListOf()
|
||||
|
||||
_onChange.value = Unit
|
||||
return true
|
||||
}
|
||||
|
||||
override fun willMeetRequirements(entity: EntityModel): Int? {
|
||||
val requirements = entity.requirements()
|
||||
if (requirements.isEmpty()) return 0
|
||||
|
||||
var metTime = 0
|
||||
for (requiredEntity in requirements) {
|
||||
val completedTime = buildOrder.uniqueCompletedTimes[requiredEntity.id]
|
||||
if (completedTime != null) {
|
||||
if (completedTime > metTime) metTime = completedTime
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return metTime
|
||||
}
|
||||
|
||||
override fun willMeetSupply(entity: EntityModel): Int? {
|
||||
val supply = entity.supply()
|
||||
if (supply == null || supply.takes == 0) return 0
|
||||
|
||||
for ((supplyAt, time) in buildOrder.supplyCountTimes) {
|
||||
if (supply.takes + buildOrder.currentSupplyUsed <= supplyAt)
|
||||
return time
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun add(entity: EntityModel, withEconomy: IEconomyService): Boolean {
|
||||
var atInterval = lastInterval
|
||||
|
||||
if (!handleSupply(entity, atInterval)) return false
|
||||
val supplyAdjustedInterval = adjustForSupply(entity, atInterval) ?: return false
|
||||
atInterval = supplyAdjustedInterval
|
||||
|
||||
val reqAdjustedInterval = adjustForRequirements(entity, atInterval) ?: return false
|
||||
atInterval = reqAdjustedInterval
|
||||
|
||||
val economyAdjustedInterval = handleEconomy(entity, withEconomy, atInterval) ?: return false
|
||||
atInterval = economyAdjustedInterval
|
||||
|
||||
val trainingAdjustedInterval = handleTrainingQueue(entity, atInterval) ?: return false
|
||||
atInterval = trainingAdjustedInterval
|
||||
|
||||
add(entity, atInterval)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun removeLast() {
|
||||
if (buildOrder.startedOrders.keys.size <= 1) return
|
||||
|
||||
if (buildOrder.startedOrders.isEmpty()) {
|
||||
buildOrder.startedOrders.remove(buildOrder.startedOrders.keys.last())
|
||||
buildOrder.completedOrders.remove(buildOrder.completedOrders.keys.last())
|
||||
lastInterval = buildOrder.startedOrders.keys.last()
|
||||
return
|
||||
}
|
||||
|
||||
val lastStarted = buildOrder.startedOrders.keys.last()
|
||||
val lastCompleted = buildOrder.completedOrders.keys.last()
|
||||
|
||||
var entityRemoved: EntityModel? = null
|
||||
|
||||
if (buildOrder.startedOrders[lastStarted]!!.isNotEmpty()) {
|
||||
entityRemoved = buildOrder.startedOrders[lastStarted]!!.removeLast()
|
||||
buildOrder.completedOrders[lastCompleted]!!.removeLast()
|
||||
}
|
||||
|
||||
if (buildOrder.startedOrders[lastStarted]!!.isEmpty())
|
||||
buildOrder.startedOrders.remove(lastStarted)
|
||||
if (buildOrder.completedOrders[lastCompleted]!!.isEmpty())
|
||||
buildOrder.completedOrders.remove(lastCompleted)
|
||||
|
||||
lastInterval = if (buildOrder.startedOrders.keys.isNotEmpty())
|
||||
buildOrder.startedOrders.keys.last()
|
||||
else
|
||||
0
|
||||
|
||||
if (entityRemoved != null) {
|
||||
if (entityRemoved.supply()?.grants ?: 0 > 0)
|
||||
buildOrder.supplyCountTimes.remove(buildOrder.supplyCountTimes.keys.last())
|
||||
|
||||
if (entityRemoved.supply()?.takes ?: 0 > 0)
|
||||
buildOrder.currentSupplyUsed -= entityRemoved.supply()!!.takes
|
||||
|
||||
buildOrder.uniqueCompletedCount[entityRemoved.dataType] =
|
||||
buildOrder.uniqueCompletedCount[entityRemoved.dataType]!! - 1
|
||||
if (buildOrder.uniqueCompletedCount[entityRemoved.dataType] == 0)
|
||||
buildOrder.uniqueCompletedTimes.remove(entityRemoved.dataType)
|
||||
|
||||
buildOrder.uniqueCompleted[entityRemoved.dataType]!!.removeLast()
|
||||
|
||||
if (entityRemoved.production() != null
|
||||
&& entityRemoved.production()!!.producedBy != null
|
||||
&& entityRemoved.supply() != null
|
||||
&& entityRemoved.supply()!!.takes > 0
|
||||
) {
|
||||
buildOrder.trainingCapacityUsed.removeLast()
|
||||
}
|
||||
|
||||
if (entityRemoved.info().descriptive == DescriptiveType.Worker) {
|
||||
removeLast()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun asJson(): String {
|
||||
return JSONObject().toString(2)
|
||||
}
|
||||
|
||||
override fun buildOrderAsYaml(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun getCompletedBefore(interval: Int): List<EntityModel> {
|
||||
val result = mutableListOf<EntityModel>()
|
||||
for ((time, orders) in buildOrder.startedOrders) {
|
||||
for (order in orders) {
|
||||
val buildTime = order.production()?.buildTime ?: 0
|
||||
if (time + buildTime <= interval)
|
||||
result.add(order)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getUndepletedHarvestPointsCompletedBefore(interval: Int): List<EntityModel> {
|
||||
val result = mutableListOf<EntityModel>()
|
||||
for ((time, orders) in buildOrder.startedOrders) {
|
||||
for (order in orders) {
|
||||
val buildTime = order.production()?.buildTime ?: 0
|
||||
val completedAt = time + buildTime
|
||||
if (completedAt <= interval
|
||||
&& order.harvest() != null
|
||||
&& !order.harvest()!!.isDepleted(interval.toFloat(), completedAt.toFloat())
|
||||
) {
|
||||
result.add(order)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun setName(name: String) {
|
||||
buildOrder.name = name
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getName(): String = buildOrder.name
|
||||
|
||||
override fun setNotes(notes: String) {
|
||||
buildOrder.notes = notes
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getNotes(): String = buildOrder.notes
|
||||
|
||||
override fun deprecatedSetColor(color: String) {
|
||||
}
|
||||
|
||||
override fun getColor(): String = ""
|
||||
|
||||
override fun reset() {
|
||||
lastInterval = 0
|
||||
buildOrder.initialize(IdsEntity.FACTION_Aru)
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
fun willMeetTrainingQueue(entity: EntityModel): Int? {
|
||||
val supply = entity.supply()
|
||||
val production = entity.production()
|
||||
|
||||
var checkedInterval = lastInterval
|
||||
|
||||
if (supply == null || production == null || supply.takes == 0) return 1
|
||||
|
||||
val producedBy = production.producedBy ?: return 1
|
||||
|
||||
val uniqueCompleted = buildOrder.uniqueCompleted[producedBy] ?: return null
|
||||
|
||||
var shortestIncrement = Int.MAX_VALUE
|
||||
var didDelay = false
|
||||
|
||||
val trainingSlots = uniqueCompleted.sumOf { it.supply()?.grants ?: 0 }
|
||||
|
||||
while (true) {
|
||||
var usedSlots = 0
|
||||
for (used in buildOrder.trainingCapacityUsed) {
|
||||
if (checkedInterval >= used.startingUsageTime && checkedInterval < used.stopUsageTime) {
|
||||
usedSlots += used.usedSlots
|
||||
val duration = used.stopUsageTime - used.startingUsageTime
|
||||
if (duration < shortestIncrement) shortestIncrement = duration
|
||||
}
|
||||
}
|
||||
|
||||
if (usedSlots + supply.takes <= trainingSlots) {
|
||||
if (didDelay)
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
title = "Waited"
|
||||
severityType = SeverityType.Information
|
||||
message = "Had to wait ${checkedInterval - lastInterval}s for Training Queue."
|
||||
}
|
||||
)
|
||||
return checkedInterval
|
||||
}
|
||||
|
||||
checkedInterval += shortestIncrement
|
||||
didDelay = true
|
||||
|
||||
if (shortestIncrement == Int.MAX_VALUE) return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleEconomy(entity: EntityModel, withEconomy: IEconomyService, atInterval: Int): Int? {
|
||||
val production = entity.production() ?: return atInterval
|
||||
var adjustedInterval = atInterval
|
||||
|
||||
val economyOverTime = withEconomy.getOverTime()
|
||||
for (interval in adjustedInterval until economyOverTime.size) {
|
||||
val economyAtSecond = economyOverTime[interval]
|
||||
if (economyAtSecond.alloy >= production.alloy
|
||||
&& economyAtSecond.ether >= production.ether
|
||||
&& economyAtSecond.pyre >= production.pyre
|
||||
) {
|
||||
adjustedInterval = interval
|
||||
if (entity.entityType != EntityType.Army)
|
||||
adjustedInterval += timingService.buildingInputDelay
|
||||
return adjustedInterval
|
||||
}
|
||||
}
|
||||
|
||||
if (economyOverTime.isNotEmpty()) {
|
||||
if (economyOverTime.last().ether < production.ether)
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
title = "Not Enough Ether"
|
||||
message = "Build more ether extractors!"
|
||||
severityType = SeverityType.Error
|
||||
}
|
||||
)
|
||||
|
||||
if (economyOverTime.last().alloy < production.alloy)
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
title = "Not Enough Alloy"
|
||||
message = "Build more bases!"
|
||||
severityType = SeverityType.Error
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun handleSupply(entity: EntityModel, atInterval: Int): Boolean {
|
||||
val minSupplyInterval = willMeetSupply(entity)
|
||||
if (minSupplyInterval == null) {
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
title = "Supply Cap Reached"
|
||||
message = "Build more supply!"
|
||||
severityType = SeverityType.Error
|
||||
}
|
||||
)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun adjustForSupply(entity: EntityModel, atInterval: Int): Int? {
|
||||
val minSupplyInterval = willMeetSupply(entity) ?: return null
|
||||
return if (minSupplyInterval > atInterval) minSupplyInterval else atInterval
|
||||
}
|
||||
|
||||
private fun adjustForRequirements(entity: EntityModel, atInterval: Int): Int? {
|
||||
val minRequirementInterval = willMeetRequirements(entity) ?: return null
|
||||
return if (minRequirementInterval > atInterval) minRequirementInterval else atInterval
|
||||
}
|
||||
|
||||
private fun handleTrainingQueue(entity: EntityModel, atInterval: Int): Int? {
|
||||
val minTrainingQueueInterval = willMeetTrainingQueue(entity)
|
||||
if (minTrainingQueueInterval == null) {
|
||||
toastService.addToast(
|
||||
ToastModel().apply {
|
||||
title = "Invalid"
|
||||
message = "Invalid Training Queue error"
|
||||
severityType = SeverityType.Error
|
||||
}
|
||||
)
|
||||
return null
|
||||
}
|
||||
return if (minTrainingQueueInterval > atInterval) minTrainingQueueInterval else atInterval
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.buildorder.BuildToCompareModel
|
||||
import ca.jonathanmccaffrey.igp.services.IBuildComparisonService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.json.JSONObject
|
||||
|
||||
class DeprecatedBuildComparisonService : IBuildComparisonService {
|
||||
|
||||
private var buildToCompare = BuildToCompareModel()
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
override fun setBuilds(buildToCompareModel: BuildToCompareModel) {
|
||||
buildToCompare = buildToCompareModel
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun get(): BuildToCompareModel = buildToCompare
|
||||
|
||||
override fun asJson(): String {
|
||||
// Stub - would use kotlinx.serialization or Gson
|
||||
return JSONObject().toString(2)
|
||||
}
|
||||
|
||||
override fun loadJson(data: String): Boolean {
|
||||
return try {
|
||||
// Stub - would deserialize with kotlinx.serialization or Gson
|
||||
hydratedLoadedJson()
|
||||
_onChange.value = Unit
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildOrderAsYaml(): String {
|
||||
// Stub - YAML serialization not available on Android by default
|
||||
return ""
|
||||
}
|
||||
|
||||
private fun hydratedLoadedJson() {
|
||||
}
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.buildorder.BuildToCompareModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.economy.EconomyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.ResourceType
|
||||
import ca.jonathanmccaffrey.igp.services.IEconomyComparisonService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlin.math.min
|
||||
|
||||
class EconomyComparisonService : IEconomyComparisonService {
|
||||
|
||||
private val intervalMax = 1024
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
override val buildsToCompare: MutableList<BuildToCompareModel> = mutableListOf(
|
||||
BuildToCompareModel().apply {
|
||||
setNumberOfTownHallExpansions(0)
|
||||
faction = IdsEntity.FACTION_Aru
|
||||
chartColor = "green"
|
||||
},
|
||||
BuildToCompareModel().apply {
|
||||
setNumberOfTownHallExpansions(0)
|
||||
faction = IdsEntity.FACTION_Aru
|
||||
chartColor = "red"
|
||||
}
|
||||
)
|
||||
|
||||
init {
|
||||
val e0 = calculateEconomy(buildsToCompare[0])
|
||||
buildsToCompare[0].economyOverTimeModel = e0.toMutableList()
|
||||
|
||||
val e1 = calculateEconomy(buildsToCompare[1])
|
||||
buildsToCompare[1].economyOverTimeModel = e1.toMutableList()
|
||||
}
|
||||
|
||||
override fun changeNumberOfTownHalls(forPlayer: Int, toCount: Int) {
|
||||
if (buildsToCompare[forPlayer].getNumberOfTownHallExpansions() == toCount) return
|
||||
|
||||
buildsToCompare[forPlayer].setNumberOfTownHallExpansions(toCount)
|
||||
calculateBuildOrder(buildsToCompare[forPlayer])
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun changeTownHallTiming(forPlayer: Int, forTownHall: Int, toTiming: Int) {
|
||||
if (buildsToCompare[forPlayer].timeToBuildTownHall[forTownHall] == toTiming) return
|
||||
|
||||
buildsToCompare[forPlayer].timeToBuildTownHall[forTownHall] = toTiming
|
||||
calculateBuildOrder(buildsToCompare[forPlayer])
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getTownHallCount(forPlayer: Int): Int =
|
||||
buildsToCompare[forPlayer].getNumberOfTownHallExpansions()
|
||||
|
||||
override fun getTownHallBuildTime(forPlayer: Int, forTownHall: Int): Int =
|
||||
buildsToCompare[forPlayer].timeToBuildTownHall[forTownHall]
|
||||
|
||||
override fun getTownHallBuildTimes(forPlayer: Int): List<Int> =
|
||||
buildsToCompare[forPlayer].timeToBuildTownHall
|
||||
|
||||
override fun changeFaction(forPlayer: Int, toFaction: String) {
|
||||
if (buildsToCompare[forPlayer].faction == toFaction) return
|
||||
buildsToCompare[forPlayer].faction = toFaction
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getFaction(forPlayer: Int): String =
|
||||
buildsToCompare[forPlayer].faction
|
||||
|
||||
override fun changeColor(forPlayer: Int, toColor: String) {
|
||||
if (buildsToCompare[forPlayer].chartColor == toColor) return
|
||||
buildsToCompare[forPlayer].chartColor = toColor
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getColor(forPlayer: Int): String =
|
||||
buildsToCompare[forPlayer].chartColor
|
||||
|
||||
private fun calculateBuildOrder(buildToCompare: BuildToCompareModel) {
|
||||
for (time in buildToCompare.timeToBuildTownHall) {
|
||||
val townHall = buildToCompare.getTownHallEntity
|
||||
val townHallMining2 = buildToCompare.getTownHallMining2Entity
|
||||
|
||||
addToBuildOrder(townHall, buildToCompare, time)
|
||||
addToBuildOrder(townHallMining2, buildToCompare, time + townHall.production()!!.buildTime)
|
||||
}
|
||||
|
||||
val economy = calculateEconomy(buildToCompare)
|
||||
buildToCompare.economyOverTimeModel = economy.toMutableList()
|
||||
}
|
||||
|
||||
private fun addToBuildOrder(entityModel: EntityModel, buildToCompare: BuildToCompareModel, atInterval: Int) {
|
||||
val buildOrder = buildToCompare.buildOrderModel
|
||||
|
||||
if (!buildOrder.startedOrders.containsKey(atInterval))
|
||||
buildOrder.startedOrders[atInterval] = mutableListOf()
|
||||
|
||||
val production = entityModel.production()
|
||||
val completedTime = atInterval + (production?.buildTime ?: 0)
|
||||
|
||||
if (!buildOrder.completedOrders.containsKey(completedTime))
|
||||
buildOrder.completedOrders[completedTime] = mutableListOf()
|
||||
|
||||
buildOrder.startedOrders[atInterval]!!.add(entityModel.clone())
|
||||
buildOrder.completedOrders[completedTime]!!.add(entityModel.clone())
|
||||
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
private fun calculateEconomy(buildToCompare: BuildToCompareModel, fromInterval: Int = 0): List<EconomyModel> {
|
||||
var from = fromInterval
|
||||
if (from == 0) from = 1
|
||||
|
||||
val buildOrder = buildToCompare.buildOrderModel
|
||||
val buildEconomyOverTime = buildToCompare.economyOverTimeModel.toMutableList()
|
||||
|
||||
while (buildEconomyOverTime.size < intervalMax) {
|
||||
buildEconomyOverTime.add(EconomyModel().apply { interval = buildEconomyOverTime.size - 1 })
|
||||
}
|
||||
|
||||
for (interval in from until intervalMax) {
|
||||
buildEconomyOverTime[interval] = EconomyModel()
|
||||
val economyAtSecond = buildEconomyOverTime[interval]
|
||||
|
||||
if (interval > 0) {
|
||||
economyAtSecond.alloy = buildEconomyOverTime[interval - 1].alloy
|
||||
economyAtSecond.ether = buildEconomyOverTime[interval - 1].ether
|
||||
economyAtSecond.pyre = buildEconomyOverTime[interval - 1].pyre
|
||||
economyAtSecond.workerCount = buildEconomyOverTime[interval - 1].workerCount
|
||||
economyAtSecond.busyWorkerCount = buildEconomyOverTime[interval - 1].busyWorkerCount
|
||||
economyAtSecond.creatingWorkerCount = buildEconomyOverTime[interval - 1].creatingWorkerCount
|
||||
economyAtSecond.harvestPoints = buildEconomyOverTime[interval - 1].harvestPoints.toMutableList()
|
||||
economyAtSecond.creatingWorkerDelays = buildEconomyOverTime[interval - 1].creatingWorkerDelays.toMutableList()
|
||||
}
|
||||
|
||||
economyAtSecond.interval = interval
|
||||
|
||||
var freeWorkers = (economyAtSecond.workerCount - economyAtSecond.busyWorkerCount).toFloat()
|
||||
var workersNeeded = 0
|
||||
|
||||
economyAtSecond.harvestPoints = buildOrder.getHarvestersCompletedBefore(interval).toMutableList()
|
||||
|
||||
economyAtSecond.pyre += 1
|
||||
|
||||
for (entity in economyAtSecond.harvestPoints) {
|
||||
val harvester = entity.harvest() ?: continue
|
||||
if (harvester.requiresWorker) {
|
||||
if (harvester.resource == ResourceType.Alloy) {
|
||||
val usedWorkers = min(harvester.slots, freeWorkers.toFloat())
|
||||
economyAtSecond.alloy += harvester.harvestedPerInterval * usedWorkers
|
||||
freeWorkers -= usedWorkers
|
||||
if (usedWorkers < harvester.slots) workersNeeded += 1
|
||||
}
|
||||
} else {
|
||||
when (harvester.resource) {
|
||||
ResourceType.Ether -> economyAtSecond.ether += harvester.harvestedPerInterval * harvester.slots
|
||||
ResourceType.Alloy -> economyAtSecond.alloy += harvester.harvestedPerInterval * harvester.slots
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (economyAtSecond.creatingWorkerCount > 0) {
|
||||
var i = 0
|
||||
while (i < economyAtSecond.creatingWorkerDelays.size) {
|
||||
if (economyAtSecond.creatingWorkerDelays[i] > 0) {
|
||||
if (economyAtSecond.alloy > 2.5f) {
|
||||
economyAtSecond.alloy -= 2.5f
|
||||
economyAtSecond.creatingWorkerDelays[i]--
|
||||
}
|
||||
} else {
|
||||
economyAtSecond.creatingWorkerCount -= 1
|
||||
economyAtSecond.workerCount += 1
|
||||
economyAtSecond.creatingWorkerDelays.removeAt(i)
|
||||
i--
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if (workersNeeded > economyAtSecond.creatingWorkerCount) {
|
||||
economyAtSecond.creatingWorkerCount += 1
|
||||
economyAtSecond.creatingWorkerDelays.add(50)
|
||||
}
|
||||
|
||||
if (buildOrder.startedOrders.containsKey(interval)) {
|
||||
for (order in buildOrder.startedOrders[interval]!!) {
|
||||
val foundEntity = EntityModel.getDictionary()[order.dataType]!!
|
||||
val production = foundEntity.production()
|
||||
if (production != null) {
|
||||
economyAtSecond.alloy -= production.alloy
|
||||
economyAtSecond.ether -= production.ether
|
||||
economyAtSecond.pyre -= production.pyre
|
||||
if (production.requiresWorker) economyAtSecond.busyWorkerCount += 1
|
||||
if (production.consumesWorker) economyAtSecond.workerCount -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buildOrder.completedOrders.containsKey(interval)) {
|
||||
for (newEntity in buildOrder.completedOrders[interval]!!) {
|
||||
economyAtSecond.harvestPoints.add(newEntity)
|
||||
val production = newEntity.production()
|
||||
if (production != null && production.requiresWorker) economyAtSecond.busyWorkerCount -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buildEconomyOverTime
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.economy.EconomyModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.types.ResourceType
|
||||
import ca.jonathanmccaffrey.igp.services.IBuildOrderService
|
||||
import ca.jonathanmccaffrey.igp.services.IEconomyService
|
||||
import ca.jonathanmccaffrey.igp.services.ITimingService
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlin.math.min
|
||||
|
||||
class EconomyService : IEconomyService {
|
||||
private var buildEconomyOverTime: MutableList<EconomyModel>? = null
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
override fun getOverTime(): List<EconomyModel> = buildEconomyOverTime ?: emptyList()
|
||||
|
||||
override suspend fun calculate(buildOrder: IBuildOrderService, timing: ITimingService, fromInterval: Int) {
|
||||
var from = fromInterval
|
||||
if (from == 0) from = 1
|
||||
|
||||
if (buildEconomyOverTime == null) {
|
||||
buildEconomyOverTime = mutableListOf()
|
||||
for (interval in 0 until timing.getAttackTime()) {
|
||||
buildEconomyOverTime!!.add(EconomyModel().apply { this.interval = interval })
|
||||
}
|
||||
}
|
||||
|
||||
if (buildEconomyOverTime!!.size > timing.getAttackTime()) {
|
||||
buildEconomyOverTime = buildEconomyOverTime!!.subList(0, timing.getAttackTime()).toMutableList()
|
||||
}
|
||||
|
||||
while (buildEconomyOverTime!!.size < timing.getAttackTime()) {
|
||||
buildEconomyOverTime!!.add(EconomyModel().apply { interval = buildEconomyOverTime!!.size - 1 })
|
||||
}
|
||||
|
||||
for (interval in from until timing.getAttackTime()) {
|
||||
buildEconomyOverTime!![interval] = EconomyModel()
|
||||
val economyAtSecond = buildEconomyOverTime!![interval]
|
||||
|
||||
carryOverEconomyFromPreviousInterval(interval, economyAtSecond)
|
||||
setupCurrentInterval(buildOrder, economyAtSecond, interval)
|
||||
addPassivePyreGain(interval, economyAtSecond)
|
||||
|
||||
val freeWorkers = economyAtSecond.workerCount - economyAtSecond.busyWorkerCount.toFloat()
|
||||
val workersNeeded = addFundsFromHarvestPoints(economyAtSecond, freeWorkers)
|
||||
var remainingWorkersNeeded = workersNeeded
|
||||
remainingWorkersNeeded -= calculateCreatingWorkerCosts(economyAtSecond)
|
||||
makeNeededNewWorkersRequests(remainingWorkersNeeded, economyAtSecond)
|
||||
subtractFundsOnRequestedOrders(buildOrder, interval, economyAtSecond)
|
||||
handleAddingNewHarvestPointsAndWorkersToEconomy(buildOrder, interval, economyAtSecond)
|
||||
}
|
||||
|
||||
_onChange.value = Unit
|
||||
}
|
||||
|
||||
override fun getEconomy(atInterval: Int): EconomyModel {
|
||||
val list = buildEconomyOverTime ?: return EconomyModel()
|
||||
return if (atInterval >= list.size) list.last() else list[atInterval]
|
||||
}
|
||||
|
||||
private fun setupCurrentInterval(
|
||||
buildOrder: IBuildOrderService,
|
||||
economyAtSecond: EconomyModel,
|
||||
interval: Int
|
||||
) {
|
||||
economyAtSecond.interval = interval
|
||||
economyAtSecond.harvestPoints = buildOrder
|
||||
.getUndepletedHarvestPointsCompletedBefore(interval + 1)
|
||||
.toMutableList()
|
||||
}
|
||||
|
||||
private fun handleAddingNewHarvestPointsAndWorkersToEconomy(
|
||||
buildOrder: IBuildOrderService,
|
||||
interval: Int,
|
||||
economyAtSecond: EconomyModel
|
||||
) {
|
||||
val completedAtInterval = buildOrder.completedOrders[interval] ?: return
|
||||
|
||||
for (newEntity in completedAtInterval) {
|
||||
val entity = newEntity.clone()
|
||||
economyAtSecond.harvestPoints.add(entity)
|
||||
|
||||
val production = newEntity.production()
|
||||
if (production != null && production.requiresWorker) economyAtSecond.busyWorkerCount -= 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun subtractFundsOnRequestedOrders(
|
||||
buildOrder: IBuildOrderService,
|
||||
interval: Int,
|
||||
economyAtSecond: EconomyModel
|
||||
) {
|
||||
val ordersAtTime = buildOrder.startedOrders[interval] ?: return
|
||||
|
||||
for (order in ordersAtTime) {
|
||||
val foundEntity = EntityModel.getDictionary()[order.dataType] ?: continue
|
||||
val production = foundEntity.production() ?: continue
|
||||
|
||||
economyAtSecond.alloy -= production.alloy
|
||||
economyAtSecond.ether -= production.ether
|
||||
economyAtSecond.pyre -= production.pyre
|
||||
|
||||
if (production.requiresWorker) economyAtSecond.busyWorkerCount += 1
|
||||
if (production.consumesWorker) economyAtSecond.workerCount -= 1
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeNeededNewWorkersRequests(workersNeeded: Int, economyAtSecond: EconomyModel) {
|
||||
if (workersNeeded <= economyAtSecond.creatingWorkerCount) return
|
||||
economyAtSecond.creatingWorkerCount += 1
|
||||
economyAtSecond.creatingWorkerDelays.add(20)
|
||||
}
|
||||
|
||||
private fun calculateCreatingWorkerCosts(economyAtSecond: EconomyModel): Int {
|
||||
var createdWorkers = 0
|
||||
if (economyAtSecond.creatingWorkerCount <= 0) return createdWorkers
|
||||
|
||||
var i = 0
|
||||
while (i < economyAtSecond.creatingWorkerDelays.size) {
|
||||
if (economyAtSecond.creatingWorkerDelays[i] > 0) {
|
||||
if (economyAtSecond.alloy > 2.5f) {
|
||||
economyAtSecond.alloy -= 2.5f
|
||||
economyAtSecond.creatingWorkerDelays[i]--
|
||||
}
|
||||
} else {
|
||||
economyAtSecond.creatingWorkerCount -= 1
|
||||
economyAtSecond.workerCount += 1
|
||||
createdWorkers++
|
||||
economyAtSecond.creatingWorkerDelays.removeAt(i)
|
||||
i--
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return createdWorkers
|
||||
}
|
||||
|
||||
private fun addFundsFromHarvestPoints(economyAtSecond: EconomyModel, freeWorkers: Float): Int {
|
||||
var workersNeeded = 0
|
||||
var remainingFreeWorkers = freeWorkers
|
||||
|
||||
for (entity in economyAtSecond.harvestPoints) {
|
||||
val harvesterPoint = entity.harvest() ?: continue
|
||||
if (harvesterPoint.requiresWorker) {
|
||||
if (harvesterPoint.resource == ResourceType.Alloy) {
|
||||
val usedWorkers = min(harvesterPoint.slots, remainingFreeWorkers)
|
||||
economyAtSecond.alloy += harvesterPoint.harvestedPerInterval * usedWorkers
|
||||
economyAtSecond.alloyIncome += harvesterPoint.harvestedPerInterval * usedWorkers
|
||||
remainingFreeWorkers -= usedWorkers
|
||||
if (usedWorkers < harvesterPoint.slots) workersNeeded += 1
|
||||
}
|
||||
} else {
|
||||
when (harvesterPoint.resource) {
|
||||
ResourceType.Ether -> {
|
||||
economyAtSecond.ether += harvesterPoint.harvestedPerInterval * harvesterPoint.slots
|
||||
economyAtSecond.etherIncome += harvesterPoint.harvestedPerInterval * harvesterPoint.slots
|
||||
}
|
||||
ResourceType.Alloy -> {
|
||||
economyAtSecond.alloy += harvesterPoint.harvestedPerInterval * harvesterPoint.slots
|
||||
economyAtSecond.alloyIncome += harvesterPoint.harvestedPerInterval * harvesterPoint.slots
|
||||
}
|
||||
ResourceType.Pyre -> { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workersNeeded
|
||||
}
|
||||
|
||||
private fun addPassivePyreGain(interval: Int, economyAtSecond: EconomyModel) {
|
||||
if (interval % 3 == 0) economyAtSecond.pyre += 1
|
||||
}
|
||||
|
||||
private fun carryOverEconomyFromPreviousInterval(interval: Int, economyAtSecond: EconomyModel) {
|
||||
if (interval <= 0) return
|
||||
|
||||
val previous = buildEconomyOverTime!![interval - 1]
|
||||
economyAtSecond.alloy = previous.alloy
|
||||
economyAtSecond.ether = previous.ether
|
||||
economyAtSecond.pyre = previous.pyre
|
||||
economyAtSecond.workerCount = previous.workerCount
|
||||
economyAtSecond.busyWorkerCount = previous.busyWorkerCount
|
||||
economyAtSecond.creatingWorkerCount = previous.creatingWorkerCount
|
||||
economyAtSecond.harvestPoints = previous.harvestPoints.toMutableList()
|
||||
economyAtSecond.creatingWorkerDelays = previous.creatingWorkerDelays.toMutableList()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.services.IEntityDisplayService
|
||||
import ca.jonathanmccaffrey.igp.services.IStorageService
|
||||
import ca.jonathanmccaffrey.igp.services.website.StorageKeys
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
object EntityViewType {
|
||||
const val Detailed = "Detailed"
|
||||
const val Plain = "Plain"
|
||||
}
|
||||
|
||||
class EntityDisplayService(
|
||||
storageService: IStorageService
|
||||
) : IEntityDisplayService {
|
||||
|
||||
private var displayType: String
|
||||
|
||||
private val _onChange = MutableStateFlow(Unit)
|
||||
override val onChange: StateFlow<Unit> = _onChange
|
||||
|
||||
init {
|
||||
displayType = if (storageService.getValue(StorageKeys.IsPlainView, false)) {
|
||||
EntityViewType.Plain
|
||||
} else {
|
||||
EntityViewType.Detailed
|
||||
}
|
||||
}
|
||||
|
||||
override fun defaultChoices(): List<String> = listOf(EntityViewType.Detailed, EntityViewType.Plain)
|
||||
|
||||
override fun getDisplayType(): String = displayType
|
||||
|
||||
override fun setDisplayType(displayType: String) {
|
||||
this.displayType = displayType
|
||||
_onChange.value = Unit
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.EntityType
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.data.IdsEntity
|
||||
import ca.jonathanmccaffrey.igp.services.IEntityFilterService
|
||||
import ca.jonathanmccaffrey.igp.services.website.EntityFilterEvent
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class EntityFilterService : IEntityFilterService {
|
||||
|
||||
private val entityChoices = mutableListOf<String>()
|
||||
|
||||
private val factionChoices = mutableListOf(
|
||||
IdsEntity.Any, IdsEntity.FACTION_QRath, IdsEntity.FACTION_Aru
|
||||
)
|
||||
|
||||
private val immortalChoices = mutableListOf<String>()
|
||||
private var entityType: String = EntityType.Army
|
||||
private var searchText = ""
|
||||
private var selectedFaction: String = IdsEntity.Any
|
||||
private var selectedImmortal: String = IdsEntity.Any
|
||||
|
||||
private val _onChange = MutableStateFlow(EntityFilterEvent.OnRefreshFaction)
|
||||
override val onChange: StateFlow<EntityFilterEvent> = _onChange
|
||||
|
||||
init {
|
||||
refreshImmortalChoices()
|
||||
refreshEntityChoices()
|
||||
}
|
||||
|
||||
override fun getEntityType(): String = entityType
|
||||
|
||||
override fun getFactionType(): String = selectedFaction
|
||||
|
||||
override fun getImmortalType(): String = selectedImmortal
|
||||
|
||||
override fun selectFactionType(factionType: String): Boolean {
|
||||
if (selectedFaction == factionType) {
|
||||
selectedFaction = IdsEntity.None
|
||||
selectedImmortal = IdsEntity.None
|
||||
refreshImmortalChoices()
|
||||
refreshEntityChoices()
|
||||
_onChange.value = EntityFilterEvent.OnRefreshFaction
|
||||
return true
|
||||
}
|
||||
|
||||
selectedFaction = factionType
|
||||
selectedImmortal = IdsEntity.Any
|
||||
refreshImmortalChoices()
|
||||
refreshEntityChoices()
|
||||
_onChange.value = EntityFilterEvent.OnRefreshFaction
|
||||
return true
|
||||
}
|
||||
|
||||
override fun selectImmortalType(immortalType: String): Boolean {
|
||||
if (selectedImmortal == immortalType) {
|
||||
selectedImmortal = IdsEntity.None
|
||||
_onChange.value = EntityFilterEvent.OnRefreshImmortal
|
||||
return true
|
||||
}
|
||||
|
||||
selectedImmortal = immortalType
|
||||
_onChange.value = EntityFilterEvent.OnRefreshImmortal
|
||||
return true
|
||||
}
|
||||
|
||||
override fun selectEntityType(entityType: String): Boolean {
|
||||
if (this.entityType == entityType) return false
|
||||
this.entityType = entityType
|
||||
_onChange.value = EntityFilterEvent.OnRefreshEntity
|
||||
return true
|
||||
}
|
||||
|
||||
override fun enterSearchText(searchText: String): Boolean {
|
||||
if (this.searchText == searchText) return false
|
||||
this.searchText = searchText
|
||||
_onChange.value = EntityFilterEvent.OnRefreshSearch
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getFactionChoices(): List<String> = factionChoices
|
||||
|
||||
override fun getImmortalChoices(): List<String> = immortalChoices
|
||||
|
||||
override fun getEntityChoices(): List<String> = entityChoices
|
||||
|
||||
override fun getSearchText(): String = searchText
|
||||
|
||||
private fun refreshImmortalChoices() {
|
||||
immortalChoices.clear()
|
||||
|
||||
if (selectedFaction == IdsEntity.FACTION_QRath || selectedFaction == IdsEntity.Any) {
|
||||
immortalChoices.add(IdsEntity.IMMORTAL_Orzum)
|
||||
immortalChoices.add(IdsEntity.IMMORTAL_Ajari)
|
||||
}
|
||||
|
||||
if (selectedFaction == IdsEntity.FACTION_Aru || selectedFaction == IdsEntity.Any) {
|
||||
immortalChoices.add(IdsEntity.IMMORTAL_Atzlan)
|
||||
immortalChoices.add(IdsEntity.IMMORTAL_Mala)
|
||||
immortalChoices.add(IdsEntity.IMMORTAL_Xol)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshEntityChoices() {
|
||||
entityChoices.clear()
|
||||
|
||||
if (selectedFaction == IdsEntity.FACTION_QRath || selectedFaction == IdsEntity.FACTION_Aru ||
|
||||
selectedFaction == IdsEntity.Any
|
||||
) {
|
||||
entityChoices.add(EntityType.Army)
|
||||
entityChoices.add(EntityType.Immortal)
|
||||
entityChoices.add(EntityType.Passive)
|
||||
entityChoices.add(EntityType.Building)
|
||||
entityChoices.add(EntityType.Tech)
|
||||
entityChoices.add(EntityType.Ability)
|
||||
entityChoices.add(EntityType.Pyre_Spell)
|
||||
entityChoices.add(EntityType.Worker)
|
||||
}
|
||||
|
||||
if (selectedFaction == IdsEntity.Any) entityChoices.add(EntityType.Any)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package ca.jonathanmccaffrey.igp.services.immortal
|
||||
|
||||
import ca.jonathanmccaffrey.igp.data.models.entity.EntityModel
|
||||
import ca.jonathanmccaffrey.igp.services.IEntityService
|
||||
|
||||
class EntityService : IEntityService {
|
||||
override fun getEntities(): List<EntityModel> {
|
||||
throw NotImplementedError("EntityService not implemented")
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user