aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin
diff options
context:
space:
mode:
authorRoman / Linnea Gräf <roman.graef@gmail.com>2022-12-09 13:19:54 +0100
committerGitHub <noreply@github.com>2022-12-09 23:19:54 +1100
commit337b77aa50db6b4a159795827623d36acccbdcc4 (patch)
tree07b107d9925de565e78bf02a1526881bd05b1519 /src/main/kotlin
parentac74ab8c13cf486cf36cb911f0a723908b0c5072 (diff)
downloadNotEnoughUpdates-337b77aa50db6b4a159795827623d36acccbdcc4.tar.gz
NotEnoughUpdates-337b77aa50db6b4a159795827623d36acccbdcc4.tar.bz2
NotEnoughUpdates-337b77aa50db6b4a159795827623d36acccbdcc4.zip
Katting (#447)
Co-authored-by: nea <romangraef@gmail.com> Co-authored-by: nea <roman.graef@gmail.com> Co-authored-by: nea <nea@nea.moe> Co-authored-by: nea <romangraef@loves.dicksinhisan.us> Co-authored-by: nea <roman.graef@grb-online.net> Co-authored-by: nea <hello@nea89.moe> Co-authored-by: nea <roman.graef@stud.tu-darmstadt.de>
Diffstat (limited to 'src/main/kotlin')
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/recipes/KatRecipe.kt164
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinJsonUtils.kt31
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/PetLeveling.kt111
3 files changed, 306 insertions, 0 deletions
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/recipes/KatRecipe.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/recipes/KatRecipe.kt
new file mode 100644
index 00000000..c4b64969
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/recipes/KatRecipe.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+package io.github.moulberry.notenoughupdates.recipes
+
+import com.google.gson.JsonObject
+import com.google.gson.JsonPrimitive
+import io.github.moulberry.notenoughupdates.NEUManager
+import io.github.moulberry.notenoughupdates.core.util.GuiElementSlider
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay.Pet
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe
+import io.github.moulberry.notenoughupdates.util.ItemUtils
+import io.github.moulberry.notenoughupdates.util.PetLeveling
+import io.github.moulberry.notenoughupdates.util.Utils
+import io.github.moulberry.notenoughupdates.util.toJsonArray
+import net.minecraft.client.Minecraft
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.util.ResourceLocation
+import java.time.Duration
+import kotlin.math.PI
+import kotlin.math.cos
+import kotlin.math.roundToInt
+import kotlin.math.sin
+
+data class KatRecipe(
+ val manager: NEUManager,
+ val inputPet: Ingredient,
+ val outputPet: Ingredient,
+ val items: List<Ingredient>,
+ val coins: Long,
+ val time: Duration,
+) : NeuRecipe {
+ var inputLevel = 1
+ val radius get() = 50 / 2
+ val circleCenter get() = 33 + 110 / 2 to 19 + 110 / 2
+ val textPosition get() = circleCenter.first to circleCenter.second + 90 / 2
+ val sliderPos get() = 40 to 15
+ val levelTextPos
+ get() = sliderPos.first - 4 - Minecraft.getMinecraft().fontRendererObj.getStringWidth("100") to
+ sliderPos.second + 16 / 2 - Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT / 2
+
+ val levelSlider = GuiElementSlider(0, 0, 100, 1F, 100F, 1F, inputLevel.toFloat()) { inputLevel = it.toInt() }
+ val coinsAdjustedForLevel: Int
+ get() = (coins.toInt() * (1 - 0.003F * (getOutputPetForCurrentLevel()?.petLevel?.currentLevel ?: 0))).toInt()
+ private val basicIngredients = items.toSet() + setOf(inputPet, Ingredient.coinIngredient(manager, coins.toInt()))
+ override fun getIngredients(): Set<Ingredient> = basicIngredients
+
+ override fun getOutputs(): Set<Ingredient> {
+ return setOf(outputPet)
+ }
+
+ fun getInputPetForCurrentLevel(): Pet? {
+ return PetInfoOverlay.getPetFromStack(inputPet.itemStack.tagCompound)?.also {
+ val petLeveling = PetLeveling.getPetLevelingForPet(it.petType, it.rarity)
+ it.petLevel = petLeveling.getPetLevel(petLeveling.getPetExpForLevel(inputLevel).toDouble())
+ }
+ }
+
+ fun getOutputPetForCurrentLevel(): Pet? {
+ return PetInfoOverlay.getPetFromStack(outputPet.itemStack.tagCompound)?.also {
+ val petLeveling = PetLeveling.getPetLevelingForPet(it.petType, it.rarity)
+ it.petLevel = petLeveling.getPetLevel(getInputPetForCurrentLevel()?.petLevel?.expTotal?.toDouble() ?: 0.0)
+ }
+ }
+
+ private fun positionOnCircle(i: Int, max: Int): Pair<Int, Int> {
+ val radians = PI * 2 * i / max
+ val offsetX = cos(radians) * radius
+ val offsetY = sin(radians) * radius
+ return (circleCenter.first + offsetX).roundToInt() to (circleCenter.second + offsetY).roundToInt()
+ }
+
+ override fun drawExtraInfo(gui: GuiItemRecipe, mouseX: Int, mouseY: Int) {
+ levelSlider.x = gui.guiLeft + sliderPos.first
+ levelSlider.y = gui.guiTop + sliderPos.second
+ levelSlider.render()
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ "$inputLevel",
+ gui.guiLeft + levelTextPos.first,
+ gui.guiTop + levelTextPos.second,
+ 0xFF0000
+ )
+ Utils.drawStringCentered(
+ Utils.prettyTime(time),
+ Minecraft.getMinecraft().fontRendererObj,
+ gui.guiLeft + textPosition.first.toFloat(), gui.guiTop + textPosition.second.toFloat(),
+ false, 0xff00ff
+ )
+ GlStateManager.color(1F, 1F, 1F, 1F)
+ }
+
+ override fun genericMouseInput(mouseX: Int, mouseY: Int) {
+ levelSlider.mouseInput(mouseX, mouseY)
+ }
+
+ override fun getSlots(): List<RecipeSlot> {
+ val advancedIngredients = items.map { it.itemStack } + listOf(
+ ItemUtils.createPetItemstackFromPetInfo(getInputPetForCurrentLevel()),
+ Ingredient.coinIngredient(
+ manager,
+ coinsAdjustedForLevel
+ ).itemStack
+ )
+ return advancedIngredients.mapIndexed { index, itemStack ->
+ val (x, y) = positionOnCircle(index, advancedIngredients.size)
+ RecipeSlot(x - 18 / 2, y - 18 / 2, itemStack)
+ } + listOf(
+ RecipeSlot(
+ circleCenter.first - 9,
+ circleCenter.second - 9,
+ ItemUtils.createPetItemstackFromPetInfo(getOutputPetForCurrentLevel())
+ )
+ )
+ }
+
+ override fun getType(): RecipeType = RecipeType.KAT_UPGRADE
+
+ override fun hasVariableCost(): Boolean = false
+
+ override fun serialize(): JsonObject {
+ return JsonObject().apply {
+ addProperty("type", type.id)
+ addProperty("coins", coins)
+ addProperty("input", inputPet.serialize())
+ addProperty("output", outputPet.serialize())
+ addProperty("time", time.seconds)
+ add("items", items.map { JsonPrimitive(it.serialize()) }.toJsonArray())
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun parseRecipe(manager: NEUManager, recipe: JsonObject, output: JsonObject): NeuRecipe {
+ return KatRecipe(
+ manager,
+ Ingredient(manager, recipe["input"].asString),
+ Ingredient(manager, recipe["output"].asString),
+ recipe["items"]?.asJsonArray?.map { Ingredient(manager, it.asString) } ?: emptyList(),
+ recipe["coins"].asLong,
+ Duration.ofSeconds(recipe["time"].asLong)
+ )
+ }
+ }
+
+ override fun getBackground(): ResourceLocation {
+ return ResourceLocation("notenoughupdates:textures/gui/katting_tall.png")
+ }
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinJsonUtils.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinJsonUtils.kt
new file mode 100644
index 00000000..95b6f1ac
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinJsonUtils.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import com.google.gson.JsonArray
+import com.google.gson.JsonElement
+
+
+fun Iterable<JsonElement>.toJsonArray(): JsonArray = JsonArray().also {
+ for (jsonElement in this) {
+ it.add(jsonElement)
+ }
+}
+
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/PetLeveling.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/PetLeveling.kt
new file mode 100644
index 00000000..e7d29642
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/PetLeveling.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 Linnea Gräf
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import com.google.gson.JsonObject
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay.Rarity
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+object PetLeveling {
+
+ data class ExpLadder(
+ val individualLevelCost: List<Long>,
+ ) {
+ val cumulativeLevelCost = individualLevelCost.runningFold(0F) { a, b -> a + b }.map { it.toLong() }
+ fun getPetLevel(currentExp: Double): PetLevel {
+ val currentOneIndexedLevel = cumulativeLevelCost.indexOfLast { it <= currentExp } + 1
+ val expForNextLevel = if (currentOneIndexedLevel > individualLevelCost.size) { // Max leveled pet
+ individualLevelCost.last()
+ } else {
+ individualLevelCost[currentOneIndexedLevel - 1]
+ }
+ val expInCurrentLevel =
+ if (currentOneIndexedLevel >= cumulativeLevelCost.size)
+ currentExp.toFloat() - cumulativeLevelCost.last()
+ else
+ (expForNextLevel - (cumulativeLevelCost[currentOneIndexedLevel] - currentExp.toFloat())).coerceAtLeast(0F)
+ return PetLevel(
+ currentLevel = currentOneIndexedLevel,
+ maxLevel = cumulativeLevelCost.size,
+ expRequiredForNextLevel = expForNextLevel,
+ expRequiredForMaxLevel = cumulativeLevelCost.last(),
+ expInCurrentLevel = expInCurrentLevel,
+ expTotal = currentExp.toFloat()
+ )
+ }
+
+ fun getPetExpForLevel(level: Int): Long {
+ if (level < 2) return 0L
+ if (level >= cumulativeLevelCost.size) return cumulativeLevelCost.last()
+ return cumulativeLevelCost[level - 1]
+ }
+ }
+
+ data class PetLevel(
+ val currentLevel: Int,
+ val maxLevel: Int,
+ val expRequiredForNextLevel: Long,
+ val expRequiredForMaxLevel: Long,
+ val expInCurrentLevel: Float,
+ var expTotal: Float,
+ ) {
+ val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
+ }
+
+ private data class Key(val petIdWithoutRarity: String, val rarity: Rarity)
+
+ private val cache = mutableMapOf<Key, ExpLadder>()
+
+ @SubscribeEvent
+ fun onRepoReload(event: RepositoryReloadEvent) {
+ cache.clear()
+ }
+
+ var petConstants: JsonObject? = null
+
+ @JvmStatic
+ fun getPetLevelingForPet(petIdWithoutRarity: String, rarity: Rarity): ExpLadder {
+ return cache.computeIfAbsent(Key(petIdWithoutRarity, rarity)) {
+ getPetLevelingForPet0(
+ petIdWithoutRarity,
+ rarity
+ )
+ }
+ }
+
+ internal fun getPetLevelingForPet0(petIdWithoutRarity: String, rarity: Rarity): ExpLadder {
+ val petConstants = this.petConstants ?: Constants.PETS
+ var levels = petConstants["pet_levels"].asJsonArray.map { it.asLong }.toMutableList()
+ val customLeveling = petConstants["custom_pet_leveling"].asJsonObject[petIdWithoutRarity]
+ val offset = petConstants["pet_rarity_offset"].asJsonObject[rarity.name].asInt
+ var maxLevel = 100
+ if (customLeveling is JsonObject) {
+ val customLevels by lazy { customLeveling["pet_levels"].asJsonArray.map { it.asLong } }
+ when (customLeveling["type"]?.asInt ?: 0) {
+ 1 -> levels.addAll(customLevels)
+ 2 -> levels = customLevels.toMutableList()
+ }
+ maxLevel = customLeveling["max_level"]?.asInt ?: maxLevel
+ }
+ return ExpLadder(levels.drop(offset).take(maxLevel))
+ }
+
+}