From a54485e2637127070507802fdf6a5b45c8646e61 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Thu, 17 Aug 2017 21:29:15 -0800 Subject: [PATCH] Finish up porting mining plugin to Kotlin --- game/src/plugins/skills/mining/meta.toml | 4 +- game/src/plugins/skills/mining/src/gem.kt | 16 +- .../skills/mining/src/mining.plugin.kts | 195 ++++++++++++++++++ game/src/plugins/skills/mining/src/ore.kt | 53 +++-- game/src/plugins/skills/mining/src/pickaxe.kt | 36 ++-- .../src/plugins/skills/mining/src/respawn.kts | 6 - 6 files changed, 257 insertions(+), 53 deletions(-) delete mode 100644 game/src/plugins/skills/mining/src/respawn.kts diff --git a/game/src/plugins/skills/mining/meta.toml b/game/src/plugins/skills/mining/meta.toml index 162162ac..0cf7d9ae 100644 --- a/game/src/plugins/skills/mining/meta.toml +++ b/game/src/plugins/skills/mining/meta.toml @@ -1,4 +1,4 @@ -name = "Mining Skill" +name = "mining-skill" package = "org.apollo.game.plugin.skills.mining" authors = [ "Graham", @@ -11,4 +11,4 @@ authors = [ [config] srcDir = "src/" -testDir = "test/" \ No newline at end of file +testDir = "test/" diff --git a/game/src/plugins/skills/mining/src/gem.kt b/game/src/plugins/skills/mining/src/gem.kt index e3b0de56..6414bfe6 100644 --- a/game/src/plugins/skills/mining/src/gem.kt +++ b/game/src/plugins/skills/mining/src/gem.kt @@ -1,10 +1,12 @@ +package org.apollo.game.plugin.skills.mining +enum class Gem(val id: Int, val chance: Int) { + UNCUT_SAPPHIRE(1623, 0), + UNCUT_EMERALD(1605, 0), + UNCUT_RUBY(1619, 0), + UNCUT_DIAMOND(1617, 0) +} -data class Gem(id: Int, chance: Int) +val GEMS = Gem.values() -val GEMS = Array( - Gem(1623, 0), // uncut sapphire - Gem(1605, 0), // uncut emerald - Gem(1619, 0), // uncut ruby - Gem(1617, 0) // uncut diamond -) \ No newline at end of file +fun lookupGem(id: Int): Gem? = GEMS.find { it.id == id } diff --git a/game/src/plugins/skills/mining/src/mining.plugin.kts b/game/src/plugins/skills/mining/src/mining.plugin.kts index 3a71de22..a0cd3e40 100644 --- a/game/src/plugins/skills/mining/src/mining.plugin.kts +++ b/game/src/plugins/skills/mining/src/mining.plugin.kts @@ -1,5 +1,200 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.cache.def.ObjectDefinition import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +import org.apollo.game.model.Animation +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Entity import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.entity.Player import org.apollo.game.model.entity.Skill +import org.apollo.game.model.entity.obj.StaticGameObject +import org.apollo.game.plugin.skills.mining.* +import org.apollo.game.scheduling.ScheduledTask +import org.apollo.game.scheduling.Scheduler +import java.util.* +import kotlin.properties.Delegates + +class MiningAction(val player: Player, val objectID: Int, val p: Position, val ore: Ore) : DistancedAction(PULSES, true, player, p, ORE_SIZE) { + + companion object { + private val PULSES = 0 + private val ORE_SIZE = 1; + } + + private var counter: Int = 0 + private var started: Boolean = false + private val rand: Random = Random() + + override fun executeAction() { + val level = mob.skillSet.getSkill(Skill.MINING).currentLevel + val pickaxe = findPickaxe() + //check that our pick can mine the ore + if (pickaxe == null || level < pickaxe.level) { + mob.sendMessage("You do not have a pickaxe for which you have the level to use.") + stop() + return + } + + //check that we can mine the ore + if (level < ore.level) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + return + } + + //start the process of mining + if (started) { + if (counter == 0) { + if (!miningSuccessful(ore.chance, ore.chanceOffset, level)) { + mine(pickaxe) + return //We did not mine the ore... Keep going + } + //Check inv capacity + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return + } + if (mob.inventory.add(ore.id)) { + //TODO: Use lookup from utils once it has a lookup function for IDs + val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase(); + mob.sendMessage("You managed to mine some " + oreName + ".") + mob.skillSet.addExperience(Skill.MINING, ore.exp) + //Expire ore + var rockEntity: StaticGameObject? = null + val region = mob.world.regionRepository.fromPosition(position) + val entities = region.getEntities(position) + for (entity: Entity in entities) { + if (entity is StaticGameObject) { + if (entity.id == objectID) { + rockEntity = entity + } + } + } + if (rockEntity == null) { //Mining entity not found at location... + stop() + return + } + //Get ID of exipred ore + val expiredObjectID = ore.objects.get(objectID); + val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, rockEntity!!.type, rockEntity!!.orientation) + //add task to remove normal ore and replace with depleted + mob.world.schedule(object: ScheduledTask(0, true) { + override fun execute() { + //Replace normal ore with expired ore + region.removeEntity(rockEntity); + region.addEntity(expiredRockEntity) + this.stop() //Makes task run once + } + }) + //add task to respawn normal ore + mob.world.schedule(object: ScheduledTask(ore.respawn, false) { + override fun execute() { + //Replace expired ore with normal ore + region.removeEntity(expiredRockEntity) + region.addEntity(rockEntity); + this.stop() //Makes task run once + } + }) + } //If we did not add to inv, the action will still stop + stop(); //Force this action to stop after we are done + } + counter -= 1 + } else { + started = true + mine(pickaxe) + } + } + + private fun findPickaxe(): Pickaxe? { + for (pick in getPickaxes()) { + if (pick!!.level > mob.skillSet.getSkill(Skill.MINING).currentLevel) { + continue; + } + val weaponSlot = mob.equipment.get(EquipmentConstants.WEAPON) + if (weaponSlot != null && weaponSlot.id == pick.id) { + return pick; + } else if (mob.inventory.contains(pick.id)) { + return pick; + } + } + return null; + } + + private fun mine(pickaxe: Pickaxe) { + mob.sendMessage("You swing your pick at the rock.") + mob.playAnimation(pickaxe.animation) + counter = pickaxe.pulses + mob.turnTo(position) + } + + /** + * Returns the chance of mining being successful. + * Algorithm comes from: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + */ + private fun miningSuccessful(oreChance: Double, oreChanceOffset: Boolean, playerLevel: Int): Boolean { + val percent: Double + if (oreChanceOffset) { + percent = (oreChance * playerLevel + 1) * 100 + } else { + percent = (oreChance * playerLevel) * 100 + } + return rand.nextInt(100) < percent; + } +} + +class ExpiredProspectingAction : DistancedAction { + + constructor(mob: Player, position: Position) : super(PROSPECT_PULSES, true, mob, position, ORE_SIZE) + + companion object { + private val PROSPECT_PULSES = 0 + private val ORE_SIZE = 1; + } + + override fun executeAction() { + mob.sendMessage("There is currently no ore available in this rock.") + stop(); + } +} + +class ProspectingAction(val m: Player, val p: Position, val ore: Ore) : DistancedAction(PROSPECT_PULSES, true, m, p, ORE_SIZE) { + + companion object { + private val PROSPECT_PULSES = 3 + private val ORE_SIZE = 1; + } + + var started = false; + + override fun executeAction() { + if (started) { + val oreName = ItemDefinition.lookup(ore.id).name.toLowerCase() + mob.sendMessage("This rock contains " + oreName + ".") + stop(); + } else { + started = true + mob.sendMessage("You examine the rock for ores...") + mob.turnTo(position) + } + } +} + +on {ObjectActionMessage::class} + .where {option == 1} + .then { + if (lookupOreRock(id) != null) { + it.startAction(MiningAction(it, id, this.position, lookupOreRock(id)!!)) + } + } + +on {ObjectActionMessage::class} + .where {option == 2} + .then { + if (lookupOreRock(id) != null) { + it.startAction(ProspectingAction(it, this.position, lookupOreRock(id)!!)) + } + } diff --git a/game/src/plugins/skills/mining/src/ore.kt b/game/src/plugins/skills/mining/src/ore.kt index 35b05a4f..8a67cd80 100644 --- a/game/src/plugins/skills/mining/src/ore.kt +++ b/game/src/plugins/skills/mining/src/ore.kt @@ -1,4 +1,6 @@ +package org.apollo.game.plugin.skills.mining +import com.google.common.collect.Maps.asMap /* Thanks to Mikey` for helping @@ -7,33 +9,41 @@ Thanks to Clifton for helping to find some of the expired object IDs. */ -data class Ore(id: Int, objects: Map, level: Int, exp: Float, respawn: Int) -val ORE_OBJECTS = Array( - Ore(434, CLAY_OBJECTS, 1, 5, 3), // clay - Ore(436, COPPER_OBJECTS, 1, 17.5, 6), // copper - Ore(438, TIN_OBJECTS, 1, 17.5, 6), // tin - Ore(440, IRON_OBJECTS, 15, 35, 16), // iron - Ore(453, COAL_OBJECTS, 30, 50, 100), // coal - Ore(444, GOLD_OBJECTS, 40, 65, 200), // gold - Ore(442, SILVER_OBJECTS, 20, 40, 200), // silver - Ore(447, MITHRIL_OBJECTS, 55, 80, 400), // mithril - Ore(449, ADAMANT_OBJECTS, 70, 95, 800), // adamant - Ore(451, RUNITE_OBJECTS, 85, 125, 2500) // runite -) +/** + * Chance values thanks to: http://runescape.wikia.com/wiki/Talk:Mining#Mining_success_rate_formula + * Respawn times and xp thanks to: http://oldschoolrunescape.wikia.com/wiki/ + */ +enum class Ore(val id: Int, val objects: Map, val level: Int, val exp: Double, val respawn: Int, val chance: Double, val chanceOffset: Boolean) { + CLAY(434, CLAY_OBJECTS, 1, 5.0, 1, 0.0085, true), + COPPER(436, COPPER_OBJECTS, 1, 17.5, 4, 0.0085, true), + TIN(438, TIN_OBJECTS, 1, 17.5, 4, 0.0085, true), + IRON(440, IRON_OBJECTS, 15, 35.0, 9, 0.0085, true), + COAL(453, COAL_OBJECTS, 30, 50.0, 50, 0.004, false), + GOLD(444, GOLD_OBJECTS, 40, 65.0, 100, 0.003, false), + SILVER(442, SILVER_OBJECTS, 20, 40.0, 100, 0.0085, false), + MITHRIL(447, MITHRIL_OBJECTS, 55, 80.0, 200, 0.002, false), + ADAMANT(449, ADAMANT_OBJECTS, 70, 95.0, 800, 0.001, false), + RUNITE(451, RUNITE_OBJECTS, 85, 125.0, 1200, 0.0008, false) +} -val ORES = asMap() -val EXPIRED_ORES = asMap() +val ORES = Ore.values() -for (ore in ORE_OBJECTS) { - for (key in ore.objects.keys) { - ORES.put(key, ore) - EXPIRED_ORES.put(ore.objects.(get), true) +fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } + +fun lookupOreRock(id: Int): Ore? { + for (ore in ORES) { + for (rock in ore.objects) { + if (rock.key == id) { + return ore + } + } } + return null } val CLAY_OBJECTS = mapOf( - 2180 to 450, + 2108 to 450, 2109 to 451, 14904 to 14896, 14905 to 14897 @@ -141,4 +151,5 @@ val RUNITE_OBJECTS = mapOf( 14859 to 14832, 14860 to 14833, 14861 to 14834 -) \ No newline at end of file +) + diff --git a/game/src/plugins/skills/mining/src/pickaxe.kt b/game/src/plugins/skills/mining/src/pickaxe.kt index dccf2caf..4b5f0faa 100644 --- a/game/src/plugins/skills/mining/src/pickaxe.kt +++ b/game/src/plugins/skills/mining/src/pickaxe.kt @@ -1,21 +1,23 @@ +package org.apollo.game.plugin.skills.mining + import org.apollo.game.model.Animation; -data class Pickaxe(id: Int, level: Int, animation: Animation, pulses: Int) +enum class Pickaxe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { + RUNE(1275, 41, Animation(624), 3), + ADAMANT(1271, 31, Animation(628), 4), + MITHRIL(1273, 21, Animation(629), 5), + STEEL(1269, 1, Animation(627), 6), + ITRON(1267, 1, Animation(626), 7), + BRONZE(1265, 1, Animation(625), 8) +} -val PICKAXES = Array( - Pickaxe(1265, 1, 625, 8), // bronze - Pickaxe(1267, 1, 626, 7), // iron - Pickaxe(1269, 1, 627, 6), // steel - Pickaxe(1273, 21, 629, 5), // mithril - Pickaxe(1271, 31, 628, 4), // adamant - Pickaxe(1275, 41, 624, 3) // rune -) +val PICKAXES = Pickaxe.values() + + + +fun getPickaxes(): Array { + return PICKAXES +} + +fun lookupPickaxe(id: Int): Pickaxe? = PICKAXES.find { it.id == id } -val PICKAXE_IDS: IntArray = intArrayOf( - 1275, // rune - 1271 // adamant - 1273, // mithril - 1269, // steel - 1267, // iron - 1265, // bronze -) \ No newline at end of file diff --git a/game/src/plugins/skills/mining/src/respawn.kts b/game/src/plugins/skills/mining/src/respawn.kts deleted file mode 100644 index 5ff37104..00000000 --- a/game/src/plugins/skills/mining/src/respawn.kts +++ /dev/null @@ -1,6 +0,0 @@ - - - -fun respawn_pulses(base: Int, players: Int) { - return base - players * base / (world.playerRepository.size() * 2); -} \ No newline at end of file