Corrected rune essence mining behavior and speeds

Also corrected various mining messages across many rock types to be authentic
This commit is contained in:
Kennynes 2025-11-25 13:16:47 +00:00 committed by Ryan
parent 6241ff9ce5
commit 56986ad6bc
2 changed files with 64 additions and 23 deletions

View file

@ -13,6 +13,9 @@ import core.game.world.GameWorld
import core.game.world.repository.Repository
import core.tools.colorize
// TODO: Shooting stars should roll for bonus gems while mining
// See: https://youtu.be/6OqZ2TGc6fM?si=U8nB5IDQREhWXApD
/**
* The pulse used to handle mining shooting stars.
*/
@ -53,7 +56,7 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
ShootingStarPlugin.getStoreFile()["isDiscovered"] = star.isDiscovered
return player.skills.getLevel(Skills.MINING) >= star.miningLevel
}
if (player.skills.getLevel(Skills.MINING) < star.miningLevel) {
player.dialogueInterpreter.sendDialogue("You need a Mining level of at least " + star.miningLevel + " in order to mine this layer.")
return false
@ -130,7 +133,7 @@ class ShootingStarMiningPulse(player: Player?, node: Scenery?, val star: Shootin
override fun message(type: Int) {
when (type) {
0 -> player.packetDispatch.sendMessage("You swing your pickaxe at the rock...")
0 -> player.packetDispatch.sendMessage("You swing your pickaxe at the rock.")
}
}

View file

@ -26,11 +26,11 @@ import org.rs09.consts.Items
class MiningListener : InteractionListener {
override fun defineListeners() {
defineInteraction(
IntType.SCENERY,
MiningNode.values().map { it.id }.toIntArray(),
"mine",
persistent = true, allowedDistance = 1,
handler = ::handleMining
IntType.SCENERY,
MiningNode.values().map { it.id }.toIntArray(),
"mine",
persistent = true, allowedDistance = 1,
handler = ::handleMining
)
}
private val GEM_REWARDS = arrayOf(ChanceItem(1623, 1, DropFrequency.COMMON), ChanceItem(1621, 1, DropFrequency.COMMON), ChanceItem(1619, 1, DropFrequency.UNCOMMON), ChanceItem(1617, 1, DropFrequency.RARE))
@ -38,25 +38,25 @@ class MiningListener : InteractionListener {
private fun handleMining(player: Player, node: Node, state: Int) : Boolean {
val resource = MiningNode.forId(node.id)
val tool = SkillingTool.getPickaxe(player)
val isEssence = resource.id == 2491
val isEssence = resource == MiningNode.RUNE_ESSENCE
val isGems = resource.identifier == MiningNode.GEM_ROCK_0.identifier
if (!finishedMoving(player))
return true
if (state == 0) {
if (!checkRequirements(player, resource, node)) {
player.scripts.reset()
return true
}
if (!checkRequirements(player, resource, node)) {
player.scripts.reset()
return true
}
anim(player, tool)
sendMessage(player, "You swing your pickaxe at the rock...")
return delayScript(player, getDelay(resource))
sendMessage(player, "You swing your pickaxe at the rock.")
return delayScript(player, getDelay(resource, tool))
}
anim(player, tool)
if (!checkReward(player, resource, tool))
return delayScript(player, getDelay(resource))
return delayScript(player, getDelay(resource, tool))
// Reward logic
var reward = resource!!.reward
@ -94,13 +94,23 @@ class MiningListener : InteractionListener {
if (reward == Items.GOLD_ORE_444 && inBorders(player, familyCrestGoldOreArea)) {
reward = Items.PERFECT_GOLD_ORE_446
}
val rewardName = getItemName(reward).lowercase()
// Prepare reward name - gems stay lowercase without "Uncut", others are lowercase
val rewardName = if (isGems) {
getItemName(reward).replace("Uncut ", "").lowercase()
} else {
getItemName(reward).substringBefore(" (").lowercase().removeSuffix(" ore")
}
// Send the message for the resource reward
if (isGems) {
sendMessage(player, "You get ${prependArticle(rewardName)}.")
} else {
sendMessage(player, "You get some ${rewardName.lowercase()}.")
val withArticle = prependArticle(rewardName) // "an emerald" or "a red topaz"
val parts = withArticle.split(" ", limit = 2) // ["an", "emerald"] or ["a", "red topaz"]
val article = parts[0] // "an" or "a"
val gemName = parts[1].replaceFirstChar { it.uppercase() } // "Emerald" or "Red topaz"
sendMessage(player, "You just mined $article $gemName!")
} else if (!isEssence) {
sendMessage(player, "You manage to mine some ${rewardName}.")
}
// Give the mining reward, increment 'rocks mined' attribute
@ -124,7 +134,7 @@ class MiningListener : InteractionListener {
}
if (RandomFunction.roll(chance)) {
val gem = GEM_REWARDS.random()
sendMessage(player,"You find a ${gem.name}!")
sendMessage(player,"You just found ${prependArticle(gem.name.replace("Uncut ", "").lowercase())}!")
if (freeSlots(player) == 0) {
sendMessage(player,"You do not have enough space in your inventory, so you drop the gem on the floor.")
}
@ -138,6 +148,14 @@ class MiningListener : InteractionListener {
node.setActive(false)
return true
}
// For essence, check inventory and continue mining
if (isEssence) {
if (freeSlots(player) == 0) {
return true
}
return delayScript(player, getDelay(resource, tool))
}
}
return true
}
@ -189,6 +207,10 @@ class MiningListener : InteractionListener {
}
private fun checkReward(player: Player, resource: MiningNode?, tool: SkillingTool): Boolean {
// Essence mining always succeeds
if (resource == MiningNode.RUNE_ESSENCE) {
return true
}
val level = 1 + getDynLevel(player, Skills.MINING) + getFamiliarBoost(player, Skills.MINING)
val hostRatio = Math.random() * (100.0 * resource!!.rate)
var toolRatio = tool.ratio
@ -199,8 +221,20 @@ class MiningListener : InteractionListener {
return hostRatio < clientRatio
}
fun getDelay(resource: MiningNode) : Int {
return if (resource.id == 2491) 3 else 4
fun getDelay(resource: MiningNode, tool: SkillingTool) : Int {
if (resource == MiningNode.RUNE_ESSENCE) { // Essence mining - speed varies by pickaxe
return when (tool) {
SkillingTool.BRONZE_PICKAXE -> 7
SkillingTool.IRON_PICKAXE -> 6
SkillingTool.STEEL_PICKAXE -> 5
SkillingTool.MITHRIL_PICKAXE -> 4
SkillingTool.ADAMANT_PICKAXE -> 3
SkillingTool.RUNE_PICKAXE -> 2
SkillingTool.INFERNO_ADZE2 -> if (RandomFunction.random(2) == 0) 1 else 2 //https://www.youtube.com/watch?v=9XhjSdJ4qro
else -> 4 // fallback
}
}
return 4 // normal rocks
}
fun anim(player: Player, tool: SkillingTool) {
@ -222,9 +256,13 @@ class MiningListener : InteractionListener {
sendDialogue(player,"Your inventory is too full to hold any more gems.")
return false
}
if (resource == MiningNode.RUNE_ESSENCE) {
sendDialogue(player,"Your inventory is too full to hold any more essence.")
return false
}
sendDialogue(player,"Your inventory is too full to hold any more ${ItemDefinition.forId(resource!!.reward).name.lowercase()}.")
return false
}
return node.isActive
}
}
}