From 5e86ea2d040295d4d48d543a51330d5c69ee4f6a Mon Sep 17 00:00:00 2001 From: bushtail Date: Thu, 7 Jul 2022 12:59:10 +0000 Subject: [PATCH] Refactored mining Converted to content API Corrected the prospecting text of gem rocks Corrected the full-inventory text when mining gem rocks --- Server/src/main/kotlin/api/ContentAPI.kt | 13 ++ .../skill/gather/mining/MiningSkillPulse.kt | 118 +++++++++--------- .../skill/gather/mining/ProspectListener.kt | 12 +- Server/src/main/kotlin/rs09/tools/Globals.kt | 19 +++ 4 files changed, 102 insertions(+), 60 deletions(-) diff --git a/Server/src/main/kotlin/api/ContentAPI.kt b/Server/src/main/kotlin/api/ContentAPI.kt index b7e64eb69..a42ba4cfe 100644 --- a/Server/src/main/kotlin/api/ContentAPI.kt +++ b/Server/src/main/kotlin/api/ContentAPI.kt @@ -1513,6 +1513,19 @@ fun dumpBeastOfBurden(player: Player) { } } +/** + * Gets the player's familiar boost in the given skill + * + * @param player The player who owns the familiar. + * @param skill The skill to check boost of. + * @return The amount of skill boost gained from the player's familiar. + * + * @author bushtail + */ +fun getFamiliarBoost(player : Player, skill : Int) : Int { + return player.familiarManager.getBoost(skill) +} + /** * Converts an item into its noted representation. * diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt index 3333b3a14..5bd0718fd 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/MiningSkillPulse.kt @@ -3,7 +3,6 @@ package rs09.game.node.entity.skill.gather.mining import api.* import api.events.ResourceProducedEvent import core.cache.def.impl.ItemDefinition -import core.game.container.impl.EquipmentContainer import core.game.content.dialogue.FacialExpression import core.game.content.global.SkillingPets import core.game.node.Node @@ -15,29 +14,30 @@ import core.game.node.entity.skill.Skills import core.game.node.entity.skill.gather.SkillingTool import core.game.node.entity.skill.gather.mining.MiningNode import core.game.node.item.ChanceItem -import core.game.node.item.Item import core.game.node.scenery.Scenery import core.game.node.scenery.SceneryBuilder import core.game.system.task.Pulse import core.game.world.map.Location import core.game.world.update.flag.context.Animation import core.tools.RandomFunction -import core.tools.StringUtils import org.rs09.consts.Items +import org.rs09.consts.NPCs import rs09.game.node.entity.player.info.stats.STATS_BASE import rs09.game.node.entity.player.info.stats.STATS_ROCKS import rs09.game.node.entity.skill.skillcapeperks.SkillcapePerks +import rs09.tools.stringtools.* /** * Mining skill pulse - * @author ceik + * @author Ceikry + * @author bushtail -> maintenance July 2022 */ class MiningSkillPulse(private val player: Player, private val node: Node) : Pulse(1, player, node) { private var resource: MiningNode? = null private var isMiningEssence = false private var isMiningGems = false private var ticks = 0 - protected var resetAnimation = true + private var resetAnimation = true // Perfect Gold Ore in Witchhaven Dungeon (Family Crest) private val perfectGoldOreLocations = listOf( @@ -49,7 +49,7 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul fun message(type: Int) { if (type == 0) { - player.packetDispatch.sendMessage("You swing your pickaxe at the rock...") + sendMessage(player, "You swing your pickaxe at the rock...") } } @@ -63,7 +63,7 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul override fun stop() { if (resetAnimation) { - player.animate(Animation(-1, Animator.Priority.HIGH)) + animate(player, Animation(-1, Animator.Priority.HIGH)) } super.stop() message(1) @@ -72,15 +72,14 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul override fun start() { resource = MiningNode.forId(node.id) if (MiningNode.isEmpty(node.id)) { - player.packetDispatch.sendMessage("This rock contains no ore.") + sendMessage(player, "This rock contains no ore.") } if (resource == null) { return } if (resource!!.id == 2099 && !perfectGoldOreLocations.contains(node.location) ) { - // Perfect Gold Ore Id's outside of Witchhaven - // are replaced with a normal gold rock. + // Perfect Gold Ore IDs outside Witchhaven are replaced with a normal gold rock. resource = MiningNode.forId(2098) } if (resource!!.id == 2491) { @@ -96,23 +95,27 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul } fun checkRequirements(): Boolean { - if (player.skills.getLevel(Skills.MINING) < resource!!.getLevel()) { - player.packetDispatch.sendMessage("You need a mining level of " + resource!!.getLevel() + " to mine this rock.") + if (getDynLevel(player, Skills.MINING) < resource!!.level) { + sendMessage(player, "You need a mining level of ${resource!!.level} to mine this rock.") return false } if (SkillingTool.getPickaxe(player) == null) { - player.packetDispatch.sendMessage("You do not have a pickaxe to use.") + sendMessage(player, "You do not have a pickaxe to use.") return false } - if (player.inventory.freeSlots() < 1) { - player.dialogueInterpreter.sendDialogue("Your inventory is too full to hold any more " + ItemDefinition.forId(resource!!.getReward()).name.toLowerCase() + ".") + if (freeSlots(player) == 0) { + if(resource!!.identifier == 13.toByte()) { + sendDialogue(player,"Your inventory is too full to hold any more gems.") + return false + } + sendDialogue(player,"Your inventory is too full to hold any more ${ItemDefinition.forId(resource!!.reward).name.lowercase()}.") return false } return true } fun animate() { - player.animate(SkillingTool.getPickaxe(player).animation) + animate(player, SkillingTool.getPickaxe(player).animation) } fun reward(): Boolean { @@ -120,16 +123,16 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul return false } if (node.id == 10041) { - player.dialogueInterpreter.sendDialogues(2574, FacialExpression.FURIOUS, if (RandomFunction.random(2) == 1) "You'll blow my cover! I'm meant to be hidden!" else "Will you stop that?") + sendNPCDialogue(player, NPCs.BANK_GUARD_2574,if (RandomFunction.random(2) == 1) "You'll blow my cover! I'm meant to be hidden!" else "Will you stop that?", FacialExpression.FURIOUS) return true } if (!checkReward()) { return false } - //actual reward calculations - var reward = resource!!.getReward() - var rewardAmount = 0 + // Reward logic + var reward = resource!!.reward + var rewardAmount : Int if (reward > 0) { reward = calculateReward(reward) // calculate rewards rewardAmount = calculateRewardAmount(reward) // calculate amount @@ -137,61 +140,65 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul player.dispatch(ResourceProducedEvent(reward, rewardAmount, node)) SkillingPets.checkPetDrop(player, SkillingPets.GOLEM) // roll for pet - //add experience - val experience = resource!!.getExperience() * rewardAmount - player.skills.addExperience(Skills.MINING, experience, true) + // Reward mining experience + val experience = resource!!.experience * rewardAmount + rewardXP(player, Skills.MINING, experience) - //Handle bracelet of clay + // If player is wearing Bracelet of Clay, soften if(reward == Items.CLAY_434){ - val bracelet = player.equipment.get(EquipmentContainer.SLOT_HANDS) + val bracelet = getItemFromEquipment(player, EquipmentSlot.HANDS) if(bracelet != null && bracelet.id == Items.BRACELET_OF_CLAY_11074){ if(bracelet.charge > 28) bracelet.charge = 28 bracelet.charge-- reward = Items.SOFT_CLAY_1761 - player.sendMessage("Your bracelet of clay softens the clay for you.") + sendMessage(player, "Your bracelet of clay softens the clay for you.") if(bracelet.charge <= 0){ - player.sendMessage("Your bracelet of clay crumbles to dust.") - player.equipment.remove(bracelet) + if(removeItem(player, bracelet)) { + sendMessage(player, "Your bracelet of clay crumbles to dust.") + } } } } + val rewardName = getItemName(reward).lowercase() - //send the message for the resource reward + // Send the message for the resource reward if (isMiningGems) { - val gemName = ItemDefinition.forId(reward).name.toLowerCase() - player.sendMessage("You get " + (if (StringUtils.isPlusN(gemName)) "an" else "a") + " " + gemName + ".") + sendMessage(player, "You get ${prependArticle(rewardName)}.") } else { - player.packetDispatch.sendMessage("You get some " + ItemDefinition.forId(reward).name.toLowerCase() + ".") + sendMessage(player, "You get some ${rewardName.lowercase()}.") } - //give the reward - player.inventory.add(Item(reward, rewardAmount)) - var rocksMined = player.getAttribute("$STATS_BASE:$STATS_ROCKS",0) - player.setAttribute("/save:$STATS_BASE:$STATS_ROCKS",++rocksMined) - //calculate bonus gem for mining + // Give the mining reward, increment 'rocks mined' attribute + if(addItem(player, reward, rewardAmount)) { + var rocksMined = getAttribute(player, "$STATS_BASE:$STATS_ROCKS", 0) + setAttribute(player, "/save:$STATS_BASE:$STATS_ROCKS", ++rocksMined) + } + + // Calculate bonus gem chance while mining if (!isMiningEssence) { var chance = 282 var altered = false - if (Item(player.equipment.getId(12)).name.toLowerCase().contains("ring of wealth") || inEquipment(player, Items.RING_OF_THE_STAR_SPRITE_14652)) { + val ring = getItemFromEquipment(player, EquipmentSlot.RING) + if (ring != null && ring.name.lowercase().contains("ring of wealth") || inEquipment(player, Items.RING_OF_THE_STAR_SPRITE_14652)) { chance = (chance / 1.5).toInt() altered = true } - val necklace = player.equipment[EquipmentContainer.SLOT_AMULET] + val necklace = getItemFromEquipment(player, EquipmentSlot.AMULET) if (necklace != null && necklace.id in 1705..1713) { chance = (chance / 1.5).toInt() altered = true } if (RandomFunction.roll(chance)) { val gem = GEM_REWARDS.random() - player.packetDispatch.sendMessage("You find a " + gem.name + "!") - if (!player.inventory.add(gem, player)) { - player.packetDispatch.sendMessage("You do not have enough space in your inventory, so you drop the gem on the floor.") + sendMessage(player,"You find a ${gem.name}!") + if (!addItem(player, gem.id)) { + sendMessage(player,"You do not have enough space in your inventory, so you drop the gem on the floor.") } } } - //transform to depleted version - if (!isMiningEssence && resource!!.getRespawnRate() != 0) { + // Transform ore to depleted version + if (!isMiningEssence && resource!!.respawnRate != 0) { SceneryBuilder.replace(node as Scenery, Scenery(resource!!.emptyId, node.getLocation(), node.type, node.rotation), resource!!.respawnDuration) node.setActive(false) return true @@ -203,28 +210,28 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul private fun calculateRewardAmount(reward: Int): Int { var amount = 1 - //checks for varrock armor from varrock diary and rolls chance at extra ore + // If player is wearing Varrock armour from diary, roll chance at extra ore if (!isMiningEssence && player.achievementDiaryManager.getDiary(DiaryType.VARROCK).level != -1) { when (reward) { Items.CLAY_434, Items.COPPER_ORE_436, Items.TIN_ORE_438, Items.LIMESTONE_3211, Items.BLURITE_ORE_668, Items.IRON_ORE_440, Items.ELEMENTAL_ORE_2892, Items.SILVER_ORE_442, Items.COAL_453 -> if (player.achievementDiaryManager.armour >= 0 && RandomFunction.random(100) <= 10) { amount += 1 - player.sendMessage("The Varrock armour allows you to mine an additional ore.") + sendMessage(player,"The Varrock armour allows you to mine an additional ore.") } Items.GOLD_ORE_444, Items.GRANITE_500G_6979, Items.GRANITE_2KG_6981, Items.GRANITE_5KG_6983, Items.MITHRIL_ORE_447 -> if (player.achievementDiaryManager.armour >= 1 && RandomFunction.random(100) <= 10) { amount += 1 - player.sendMessage("The Varrock armour allows you to mine an additional ore.") + sendMessage(player, "The Varrock armour allows you to mine an additional ore.") } Items.ADAMANTITE_ORE_449 -> if (player.achievementDiaryManager.armour >= 2 && RandomFunction.random(100) <= 10) { amount += 1 - player.sendMessage("The Varrock armour allows you to mine an additional ore.") + sendMessage(player, "The Varrock armour allows you to mine an additional ore.") } } } - //check for bonus ore from shooting star buff + // If player has mining boost from Shooting Star, roll chance at extra ore if (player.hasActiveState("shooting-star")) { if (RandomFunction.getRandom(5) == 3) { - player.packetDispatch.sendMessage("...you manage to mine a second ore thanks to the Star Sprite.") + sendMessage(player, "...you manage to mine a second ore thanks to the Star Sprite.") amount += 1 } } @@ -237,8 +244,8 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul if (resource == MiningNode.SANDSTONE || resource == MiningNode.GRANITE) { val value = RandomFunction.randomize(if (resource == MiningNode.GRANITE) 3 else 4) reward += value shl 1 - player.skills.addExperience(Skills.MINING, value * 10.toDouble(), true) - } else if (isMiningEssence && player.skills.getLevel(Skills.MINING) >= 30) { + rewardXP(player, Skills.MINING, value * 10.toDouble()) + } else if (isMiningEssence && getDynLevel(player, Skills.MINING) >= 30) { reward = 7936 } else if (isMiningGems) { reward = RandomFunction.rollWeightedChanceTable(MiningNode.gemRockGems).id @@ -251,14 +258,13 @@ class MiningSkillPulse(private val player: Player, private val node: Node) : Pul * @return `True` if so. */ private fun checkReward(): Boolean { - val skill = Skills.MINING - val level = 1 + player.skills.getLevel(skill) + player.familiarManager.getBoost(skill) - val hostRatio = Math.random() * (100.0 * resource!!.getRate()) + val level = 1 + getDynLevel(player, Skills.MINING) + getFamiliarBoost(player, Skills.MINING) + val hostRatio = Math.random() * (100.0 * resource!!.rate) var toolRatio = SkillingTool.getPickaxe(player).ratio if(SkillcapePerks.isActive(SkillcapePerks.PRECISION_MINER,player)){ toolRatio += 0.075 } - val clientRatio = Math.random() * ((level - resource!!.getLevel()) * (1.0 + toolRatio)) + val clientRatio = Math.random() * ((level - resource!!.level) * (1.0 + toolRatio)) return hostRatio < clientRatio } diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/ProspectListener.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/ProspectListener.kt index e5ee3ff98..1f8216ce5 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/ProspectListener.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/gather/mining/ProspectListener.kt @@ -1,8 +1,8 @@ package rs09.game.node.entity.skill.gather.mining import api.* -import core.game.node.entity.skill.gather.SkillingResource import core.game.node.entity.skill.gather.mining.MiningNode +import core.game.node.item.Item import core.game.system.task.Pulse import rs09.game.interaction.InteractionListener @@ -14,11 +14,13 @@ class ProspectListener : InteractionListener { override fun defineListeners() { on(SCENERY, "prospect") { player, node -> - val rock = SkillingResource.forId(node.id) + val rock = MiningNode.forId(node.asScenery().id) + if(rock == null) { sendMessage(player, "There is no ore currently available in this rock.") return@on true } + /** Check if the rock contains gems */ if(MiningNode.forId(node.id).identifier == 13.toByte()) { sendMessage(player,"You examine the rock for ores...") @@ -29,14 +31,16 @@ class ProspectListener : InteractionListener { return true } }) + return@on true } + /** If it doesn't contain gems */ else { sendMessage(player,"You examine the rock for ores...") /** Get the name of the rock's reward and sends a message to the player */ player.pulseManager.run(object : Pulse(3) { override fun pulse(): Boolean { - sendMessage(player, "This rock contains ${itemDefinition(rock.reward).name.toLowerCase()}.") + sendMessage(player, "This rock contains ${Item(rock.reward).name.lowercase()}.") return true } }) @@ -44,4 +48,4 @@ class ProspectListener : InteractionListener { return@on true } } -} \ No newline at end of file +} diff --git a/Server/src/main/kotlin/rs09/tools/Globals.kt b/Server/src/main/kotlin/rs09/tools/Globals.kt index 16b460d3d..238cb28f1 100644 --- a/Server/src/main/kotlin/rs09/tools/Globals.kt +++ b/Server/src/main/kotlin/rs09/tools/Globals.kt @@ -39,3 +39,22 @@ fun String.shuffle(): String{ } return new } + +/** + * Prepends 'a' or 'an' to a noun depending on whether it starts with a vowel. + * @author bushtail + * @param noun the noun to check grammar rules against. + * @return either 'a $noun' or 'an $noun' depending on the first letter. + */ +fun prependArticle(noun : String) : String { + if(noun == null) return noun + val exceptions = hashMapOf("unicorn" to "a", "herb" to "an", "hour" to "an") + if(exceptions.contains(noun.lowercase())) { + return "${exceptions[noun.lowercase()]} $noun" + } + return when(noun[0]) { + 'a', 'e', 'i', 'o', 'u' -> "an $noun" + else -> "a $noun" + } +} +