aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/features/misc/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/features/misc/items')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt146
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/items/GlowingDroppedItems.kt68
2 files changed, 202 insertions, 12 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
index 464b45762..ced04d3be 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValue.kt
@@ -1,34 +1,38 @@
package at.hannibal2.skyhanni.features.misc.items
import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.config.ConfigManager
import at.hannibal2.skyhanni.events.ConfigLoadEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.RenderItemTooltipEvent
+import at.hannibal2.skyhanni.test.command.CopyErrorCommand
+import at.hannibal2.skyhanni.utils.*
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName_old
import at.hannibal2.skyhanni.utils.ItemUtils.getItemName
+import at.hannibal2.skyhanni.utils.ItemUtils.getItemRarityOrNull
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
-import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.ItemUtils.name
import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList
import at.hannibal2.skyhanni.utils.LorenzUtils.onToggle
import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc
-import at.hannibal2.skyhanni.utils.NEUInternalName
import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName
import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull
import at.hannibal2.skyhanni.utils.NEUItems.getPrice
import at.hannibal2.skyhanni.utils.NEUItems.getPriceOrNull
-import at.hannibal2.skyhanni.utils.NumberUtil
+import at.hannibal2.skyhanni.utils.NEUItems.manager
import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
-import at.hannibal2.skyhanni.utils.OSUtils
import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems
+import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.GemstoneSlotType
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getAbilityScrolls
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getArmorDye
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getAttributes
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getDrillUpgrades
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getDungeonStarCount
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getEnchantments
+import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getFarmingForDummiesCount
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getGemstones
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getHelmetSkin
@@ -49,10 +53,16 @@ import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.hasWoodSingularity
import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.isRecombobulated
import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import com.google.gson.JsonObject
+import com.google.gson.reflect.TypeToken
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent
+import io.github.moulberry.notenoughupdates.recipes.Ingredient
import io.github.moulberry.notenoughupdates.util.Constants
import net.minecraft.init.Items
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.io.File
+import java.util.*
import kotlin.math.roundToLong
object EstimatedItemValue {
@@ -60,6 +70,22 @@ object EstimatedItemValue {
private var display = emptyList<List<Any>>()
private val cache = mutableMapOf<ItemStack, List<List<Any>>>()
private var lastToolTipTime = 0L
+ private var gemstoneUnlockCosts = HashMap<NEUInternalName, HashMap<String, List<String>>>()
+
+ @SubscribeEvent
+ fun onRepoReload(event: RepositoryReloadEvent) {
+ val data = manager.getJsonFromFile(File(manager.repoLocation, "constants/gemstonecosts.json"))
+
+ if (data != null)
+ // item_internal_names -> gemstone_slots -> ingredients_array
+ gemstoneUnlockCosts =
+ ConfigManager.gson.fromJson(
+ data,
+ object : TypeToken<HashMap<NEUInternalName, HashMap<String, List<String>>>>() {}.type
+ )
+ else
+ LorenzUtils.error("Gemstone Slot Unlock Costs failed to load")
+ }
@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent.ChestBackgroundRenderEvent) {
@@ -188,6 +214,7 @@ object EstimatedItemValue {
// dynamic
totalPrice += addAbilityScrolls(stack, list)
totalPrice += addDrillUpgrades(stack, list)
+ totalPrice += addGemstoneSlotUnlockCost(stack, list)
totalPrice += addGemstones(stack, list)
totalPrice += addEnchantments(stack, list)
return Pair(totalPrice, basePrice)
@@ -257,22 +284,63 @@ object EstimatedItemValue {
val rawReforgeName = stack.getReforgeName() ?: return 0.0
for ((rawInternalName, values) in Constants.REFORGESTONES.entrySet()) {
- val stone = values.asJsonObject
- val reforgeName = stone.get("reforgeName").asString
+ val stoneJson = values.asJsonObject
+ val reforgeName = stoneJson.get("reforgeName").asString
if (rawReforgeName == reforgeName.lowercase() || rawReforgeName == rawInternalName.lowercase()) {
val internalName = rawInternalName.asInternalName()
- val price = internalName.getPrice()
- val name = internalName.getItemName()
+ val reforgeStonePrice = internalName.getPrice()
+ val reforgeStoneName = internalName.getItemName()
+
+ val reforgeCosts = stoneJson.get("reforgeCosts").asJsonObject
+ val applyCost = getReforgeStoneApplyCost(stack, reforgeCosts, internalName) ?: return 0.0
+
val realReforgeName = if (reforgeName.equals("Warped")) "Hyper" else reforgeName
list.add("§7Reforge: §9$realReforgeName")
- list.add(" §7($name §6" + NumberUtil.format(price) + "§7)")
- return price
+ list.add(" §7Stone $reforgeStoneName §7(§6" + NumberUtil.format(reforgeStonePrice) + "§7)")
+ list.add(" §7Apply cost: (§6" + NumberUtil.format(applyCost) + "§7)")
+ return reforgeStonePrice + applyCost
}
}
return 0.0
}
+ private fun getReforgeStoneApplyCost(
+ stack: ItemStack,
+ reforgeCosts: JsonObject,
+ reforgeStone: NEUInternalName
+ ): Int? {
+ var itemRarity = stack.getItemRarityOrNull() ?: return null
+
+ // Catch cases of special or very special
+ if (itemRarity > LorenzRarity.MYTHIC) {
+ itemRarity = LorenzRarity.LEGENDARY
+ } else {
+ if (stack.isRecombobulated()) {
+ val oneBelow = itemRarity.oneBelow(logError = false)
+ if (oneBelow == null) {
+ CopyErrorCommand.logErrorState(
+ "Wrong item rarity detected in estimated item value for item ${stack.name}",
+ "Recombobulated item is common: ${stack.getInternalName()}, name:${stack.name}"
+ )
+ return null
+ }
+ itemRarity = oneBelow
+ }
+ }
+ val rarityName = itemRarity.name
+ if (!reforgeCosts.has(rarityName)) {
+ val reforgesFound = reforgeCosts.entrySet().map { it.key }
+ CopyErrorCommand.logErrorState(
+ "Can not calculate reforge cost for item ${stack.name}",
+ "item rarity '$itemRarity' is not in NEU repo reforge cost for reforge stone$reforgeStone ($reforgesFound)"
+ )
+ return null
+ }
+
+ return reforgeCosts[rarityName].asInt
+ }
+
private fun addRecomb(stack: ItemStack, list: MutableList<String>): Double {
if (!stack.isRecombobulated()) return 0.0
@@ -383,8 +451,8 @@ object EstimatedItemValue {
private fun addSilex(stack: ItemStack, list: MutableList<String>): Double {
val tier = stack.getSilexCount() ?: return 0.0
- val internalName = stack.getInternalName_old()
- val maxTier = if (internalName == "STONK_PICKAXE") 4 else 5
+ val internalName = stack.getInternalName()
+ val maxTier = if (internalName == "STONK_PICKAXE".asInternalName()) 4 else 5
val wtfHardcodedSilex = "SIL_EX".asInternalName()
val price = wtfHardcodedSilex.getPrice() * tier
@@ -641,4 +709,58 @@ object EstimatedItemValue {
}
return totalPrice
}
+
+ private fun addGemstoneSlotUnlockCost(stack: ItemStack, list: MutableList<String>): Double {
+ val internalName = stack.getInternalName()
+
+ // item have to contains gems.unlocked_slots NBT array for unlocked slot detection
+ val unlockedSlots =
+ stack.getExtraAttributes()?.getCompoundTag("gems")?.getTag("unlocked_slots")?.toString() ?: return 0.0
+
+ // TODO detection for old items which doesnt have gems.unlocked_slots NBT array
+// if (unlockedSlots == "null") return 0.0
+
+ val priceMap = mutableMapOf<String, Double>()
+ if (gemstoneUnlockCosts.isEmpty()) return 0.0
+
+ if (internalName !in gemstoneUnlockCosts) {
+ CopyErrorCommand.logErrorState(
+ "Could not find gemstone slot price for ${stack.name}",
+ "EstimatedItemValue has no gemstoneUnlockCosts for $internalName"
+ )
+ return 0.0
+ }
+
+ var totalPrice = 0.0
+ val slots = gemstoneUnlockCosts[internalName] ?: return 0.0
+ for (slot in slots) {
+ if (!unlockedSlots.contains(slot.key)) continue
+
+ val previousTotal = totalPrice
+ for (ingredients in slot.value) {
+ val ingredient = Ingredient(manager, ingredients)
+
+ totalPrice += if (ingredient.isCoins) {
+ ingredient.count
+ } else {
+ getPrice(ingredient.internalItemId) * ingredient.count
+ }
+ }
+
+ val splitSlot = slot.key.split("_") // eg. SAPPHIRE_1
+ val colorCode = GemstoneSlotType.getColorCode(splitSlot[0])
+ val formattedPrice = NumberUtil.format(totalPrice - previousTotal)
+
+ // eg. SAPPHIRE_1 -> Sapphire Slot 2
+ val displayName = splitSlot[0].lowercase(Locale.ENGLISH).replaceFirstChar(Char::uppercase) + " Slot" +
+ // If the slot index is 0, we don't need to specify
+ if (splitSlot[1] != "0") " " + (splitSlot[1].toInt() + 1) else ""
+
+ priceMap[" §$colorCode $displayName §7(§6$formattedPrice§7)"] = totalPrice - previousTotal
+ }
+
+ list.add("§7Gemstone Slot Unlock Cost: §6" + NumberUtil.format(totalPrice))
+ list += priceMap.sortedDesc().keys
+ return totalPrice
+ }
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/items/GlowingDroppedItems.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/items/GlowingDroppedItems.kt
new file mode 100644
index 000000000..ac83276a1
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/items/GlowingDroppedItems.kt
@@ -0,0 +1,68 @@
+package at.hannibal2.skyhanni.features.misc.items
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.events.RenderEntityOutlineEvent
+import at.hannibal2.skyhanni.utils.ItemUtils.getItemRarityOrNull
+import at.hannibal2.skyhanni.utils.ItemUtils.name
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.equalsOneOf
+import net.minecraft.entity.Entity
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraft.entity.item.EntityItem
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+class GlowingDroppedItems {
+
+ private val config get() = SkyHanniMod.feature.misc.glowingDroppedItems
+
+ /**
+ * List of SkyBlock locations where we might see items in showcases
+ */
+ private val showcaseItemLocations = setOf(
+ "The End",
+ "Jerry's Workshop"
+ )
+
+ @SubscribeEvent
+ fun onRenderEntityOutlines(event: RenderEntityOutlineEvent) {
+ if (isEnabled() && event.type === RenderEntityOutlineEvent.Type.XRAY) {
+ event.queueEntitiesToOutline(getEntityOutlineColor)
+ }
+ }
+
+ private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled
+
+ private val getEntityOutlineColor: (entity: Entity) -> Int? = { entity ->
+ if (entity is EntityItem && !shouldHideShowcaseItem(entity)) {
+ val rarity = entity.entityItem.getItemRarityOrNull()
+
+ if (config.highlightFishingBait || entity.entityItem.name?.endsWith(" Bait") != true) {
+ rarity?.color?.toColor()?.rgb
+ } else null
+ } else null
+ }
+
+ private fun isShowcaseArea() =
+ showcaseItemLocations.contains(LorenzUtils.skyBlockArea) ||
+ LorenzUtils.skyBlockIsland.equalsOneOf(
+ IslandType.HUB,
+ IslandType.PRIVATE_ISLAND,
+ IslandType.PRIVATE_ISLAND_GUEST
+ )
+
+ private fun shouldHideShowcaseItem(entity: EntityItem): Boolean {
+ if (!isShowcaseArea() || config.highlightShowcase) return false
+
+ for (entityArmorStand in entity.worldObj.getEntitiesWithinAABB(
+ EntityArmorStand::class.java,
+ entity.entityBoundingBox
+ )) {
+ if (entityArmorStand.isInvisible) {
+ return true
+ }
+ }
+
+ return false
+ }
+} \ No newline at end of file