diff --git a/game/plugin/skills/mining/build.gradle b/game/plugin/skills/mining/build.gradle index c301b216..71bc9020 100644 --- a/game/plugin/skills/mining/build.gradle +++ b/game/plugin/skills/mining/build.gradle @@ -3,6 +3,7 @@ plugin { authors = [ "Graham", "Mikey`", + "Major", "WH:II:DOW", "Requa", "Clifton", diff --git a/game/plugin/skills/mining/src/gem.kt b/game/plugin/skills/mining/src/gem.kt index 6414bfe6..6f8fa2e7 100644 --- a/game/plugin/skills/mining/src/gem.kt +++ b/game/plugin/skills/mining/src/gem.kt @@ -1,12 +1,13 @@ 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) -} +enum class Gem(val id: Int) { // TODO add gem drop chances + UNCUT_SAPPHIRE(1623), + UNCUT_EMERALD(1605), + UNCUT_RUBY(1619), + UNCUT_DIAMOND(1617); -val GEMS = Gem.values() - -fun lookupGem(id: Int): Gem? = GEMS.find { it.id == id } + companion object { + private val GEMS = Gem.values().associateBy({ it.id }, { it }) + fun lookup(id: Int): Gem? = GEMS[id] + } +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/mining.plugin.kts b/game/plugin/skills/mining/src/mining.plugin.kts index c7d34db2..2c380f1c 100644 --- a/game/plugin/skills/mining/src/mining.plugin.kts +++ b/game/plugin/skills/mining/src/mining.plugin.kts @@ -12,17 +12,33 @@ import org.apollo.game.plugin.api.findObject import org.apollo.game.plugin.api.mining import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.skills.mining.Ore -import org.apollo.game.plugin.skills.mining.PICKAXES import org.apollo.game.plugin.skills.mining.Pickaxe -import org.apollo.game.plugin.skills.mining.lookupOreRock import org.apollo.net.message.Message -import java.util.Optional +import java.util.Objects -class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { +on { ObjectActionMessage::class } + .where { option == Actions.MINING } + .then { player -> + Ore.fromRock(id)?.let { ore -> + MiningAction.start(this, player, ore) + } + } - fun getObject(world: World): Optional { +on { ObjectActionMessage::class } + .where { option == Actions.PROSPECTING } + .then { player -> + val ore = Ore.fromRock(id) + + if (ore != null) { + ProspectingAction.start(this, player, ore) + } + } + +data class MiningTarget(val objectId: Int, val position: Position, val ore: Ore) { + + fun getObject(world: World): GameObject? { val region = world.regionRepository.fromPosition(position) - return region.findObject(position, objectId) + return region.findObject(position, objectId).orElse(null) } fun isSuccessful(mob: Player): Boolean { @@ -41,27 +57,22 @@ class MiningAction( ) : AsyncDistancedAction(PULSES, true, player, target.position, ORE_SIZE) { companion object { - private val PULSES = 0 - private val ORE_SIZE = 1 - - fun pickaxeFor(player: Player): Pickaxe? { - return PICKAXES - .filter { it.level <= player.mining.current } - .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } - .sortedByDescending { it.level } - .firstOrNull() - } + private const val PULSES = 0 + private const val ORE_SIZE = 1 /** * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. */ fun start(message: ObjectActionMessage, player: Player, ore: Ore) { - val pickaxe = pickaxeFor(player) - if (pickaxe != null) { - val action = MiningAction(player, pickaxe, MiningTarget(message.id, message.position, ore)) - player.startAction(action) - } else { + val pickaxe = Pickaxe.bestFor(player) + + if (pickaxe == null) { player.sendMessage("You do not have a pickaxe for which you have the level to use.") + } else { + val target = MiningTarget(message.id, message.position, ore) + val action = MiningAction(player, pickaxe, target) + + player.startAction(action) } message.terminate() @@ -83,7 +94,7 @@ class MiningAction( wait(tool.pulses) val obj = target.getObject(mob.world) - if (!obj.isPresent) { + if (obj == null) { stop() } @@ -94,25 +105,46 @@ class MiningAction( } if (mob.inventory.add(target.ore.id)) { - val oreName = Definitions.item(target.ore.id)?.name?.toLowerCase() + val oreName = Definitions.item(target.ore.id)!!.name.toLowerCase() mob.sendMessage("You manage to mine some $oreName") mob.mining.experience += target.ore.exp - mob.world.expireObject(obj.get(), target.ore.objects[target.objectId]!!, target.ore.respawn) + mob.world.expireObject(obj!!, target.ore.objects[target.objectId]!!, target.ore.respawn) stop() } } } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MiningAction + return mob == other.mob && target == other.target + } + + override fun hashCode(): Int = Objects.hash(mob, target) + } class ExpiredProspectingAction( mob: Player, position: Position -) : DistancedAction(PROSPECT_PULSES, true, mob, position, ORE_SIZE) { +) : DistancedAction(DELAY, true, mob, position, ORE_SIZE) { companion object { - private val PROSPECT_PULSES = 0 - private val ORE_SIZE = 1 + private const val DELAY = 0 + private const val ORE_SIZE = 1 + + /** + * Starts a [ExpiredProspectingAction] for the specified [Player], terminating the [Message] that triggered it. + */ + fun start(message: ObjectActionMessage, player: Player) { + val action = ExpiredProspectingAction(player, message.position) + player.startAction(action) + + message.terminate() + } } override fun executeAction() { @@ -120,17 +152,27 @@ class ExpiredProspectingAction( stop() } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExpiredProspectingAction + return mob == other.mob && position == other.position + } + + override fun hashCode(): Int = Objects.hash(mob, position) + } class ProspectingAction( player: Player, position: Position, private val ore: Ore -) : AsyncDistancedAction(PROSPECT_PULSES, true, player, position, ORE_SIZE) { +) : AsyncDistancedAction(DELAY, true, player, position, ORE_SIZE) { companion object { - private val PROSPECT_PULSES = 3 - private val ORE_SIZE = 1 + private const val DELAY = 3 + private const val ORE_SIZE = 1 /** * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. @@ -141,7 +183,6 @@ class ProspectingAction( message.terminate() } - } override fun action(): ActionBlock = { @@ -151,27 +192,24 @@ class ProspectingAction( wait() val oreName = Definitions.item(ore.id)?.name?.toLowerCase() - mob.sendMessage("This rock contains $oreName") + mob.sendMessage("This rock contains $oreName.") stop() } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ProspectingAction + return mob == other.mob && position == other.position && ore == other.ore + } + + override fun hashCode(): Int = Objects.hash(mob, position, ore) + } -on { ObjectActionMessage::class } - .where { option == 1 } - .then { - val ore = lookupOreRock(id) - if (ore != null) { - MiningAction.start(this, it, ore) - } - } - -on { ObjectActionMessage::class } - .where { option == 2 } - .then { - val ore = lookupOreRock(id) - if (ore != null) { // TODO send expired action if rock is expired - ProspectingAction.start(this, it, ore) - } - } +private object Actions { + const val MINING = 1 + const val PROSPECTING = 2 +} \ No newline at end of file diff --git a/game/plugin/skills/mining/src/ore.kt b/game/plugin/skills/mining/src/ore.kt index 90001fdc..e272b182 100644 --- a/game/plugin/skills/mining/src/ore.kt +++ b/game/plugin/skills/mining/src/ore.kt @@ -1,155 +1,154 @@ package org.apollo.game.plugin.skills.mining -import com.google.common.collect.Maps.asMap - /* Thanks to Mikey` for helping to find some of the item/object IDs, minimum levels and experiences. Thanks to Clifton for helping to find some of the expired object IDs. */ - -val CLAY_OBJECTS = mapOf( - 2108 to 450, - 2109 to 451, - 14904 to 14896, - 14905 to 14897 -) - -val COPPER_OBJECTS = mapOf( - 11960 to 11555, - 11961 to 11556, - 11962 to 11557, - 11936 to 11552, - 11937 to 11553, - 11938 to 11554, - 2090 to 450, - 2091 to 451, - 14906 to 14898, - 14907 to 14899, - 14856 to 14832, - 14857 to 14833, - 14858 to 14834 -) - -val TIN_OBJECTS = mapOf( - 11597 to 11555, - 11958 to 11556, - 11959 to 11557, - 11933 to 11552, - 11934 to 11553, - 11935 to 11554, - 2094 to 450, - 2095 to 451, - 14092 to 14894, - 14903 to 14895 -) - -val IRON_OBJECTS = mapOf( - 11954 to 11555, - 11955 to 11556, - 11956 to 11557, - 2092 to 450, - 2093 to 451, - 14900 to 14892, - 14901 to 14893, - 14913 to 14915, - 14914 to 14916 -) - -val COAL_OBJECTS = mapOf( - 11963 to 11555, - 11964 to 11556, - 11965 to 11557, - 11930 to 11552, - 11931 to 11553, - 11932 to 11554, - 2096 to 450, - 2097 to 451, - 14850 to 14832, - 14851 to 14833, - 14852 to 14834 -) - -val SILVER_OBJECTS = mapOf ( - 11948 to 11555, - 11949 to 11556, - 11950 to 11557, - 2100 to 450, - 2101 to 451 -) - -val GOLD_OBJECTS = mapOf( - 11951 to 11555, - 11952 to 11556, - 11953 to 11557, - 2098 to 450, - 2099 to 451 -) - -val MITHRIL_OBJECTS = mapOf( - 11945 to 11555, - 11946 to 11556, - 11947 to 11557, - 11942 to 11552, - 11943 to 11553, - 11944 to 11554, - 2102 to 450, - 2103 to 451, - 14853 to 14832, - 14854 to 14833, - 14855 to 14834 -) - -val ADAMANT_OBJECTS = mapOf( - 11939 to 11552, - 11940 to 11553, - 11941 to 11554, - 2104 to 450, - 2105 to 451, - 14862 to 14832, - 14863 to 14833, - 14864 to 14834 -) - -val RUNITE_OBJECTS = mapOf( - 2106 to 450, - 2107 to 451, - 14859 to 14832, - 14860 to 14833, - 14861 to 14834 -) - - /** * 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) -} +enum class Ore( + val objects: Map, + val id: Int, + val level: Int, + val exp: Double, + val respawn: Int, + val chance: Double, + val chanceOffset: Boolean = false +) { + CLAY(CLAY_OBJECTS, id = 434, level = 1, exp = 5.0, respawn = 1, chance = 0.0085, chanceOffset = true), + COPPER(COPPER_OBJECTS, id = 436, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), + TIN(TIN_OBJECTS, id = 438, level = 1, exp = 17.5, respawn = 4, chance = 0.0085, chanceOffset = true), + IRON(IRON_OBJECTS, id = 440, level = 15, exp = 35.0, respawn = 9, chance = 0.0085, chanceOffset = true), + COAL(COAL_OBJECTS, id = 453, level = 30, exp = 50.0, respawn = 50, chance = 0.004), + GOLD(GOLD_OBJECTS, id = 444, level = 40, exp = 65.0, respawn = 100, chance = 0.003), + SILVER(SILVER_OBJECTS, id = 442, level = 20, exp = 40.0, respawn = 100, chance = 0.0085), + MITHRIL(MITHRIL_OBJECTS, id = 447, level = 55, exp = 80.0, respawn = 200, chance = 0.002), + ADAMANT(ADAMANT_OBJECTS, id = 449, level = 70, exp = 95.0, respawn = 800, chance = 0.001), + RUNITE(RUNITE_OBJECTS, id = 451, level = 85, exp = 125.0, respawn = 1_200, chance = 0.0008); -val ORES = enumValues() + companion object { + private val ORE_ROCKS = Ore.values().flatMap { ore -> ore.objects.map { Pair(it.key, ore) } }.toMap() + private val EXPIRED_ORE = Ore.values().flatMap { ore -> ore.objects.map { Pair(it.value, ore) } }.toMap() -fun lookupOre(id: Int): Ore? = ORES.find { it.id == id } + fun fromRock(id: Int): Ore? = ORE_ROCKS[id] + fun fromExpiredRock(id: Int): Ore? = EXPIRED_ORE[id] -fun lookupOreRock(id: Int): Ore? { - for (ore in enumValues()) { - for (rock in ore.objects) { - if (rock.key == id) { - return ore - } - } } - return null } +// Maps from regular rock id to expired rock id. + +val CLAY_OBJECTS = mapOf( + 2108 to 450, + 2109 to 451, + 14904 to 14896, + 14905 to 14897 +) + +val COPPER_OBJECTS = mapOf( + 11960 to 11555, + 11961 to 11556, + 11962 to 11557, + 11936 to 11552, + 11937 to 11553, + 11938 to 11554, + 2090 to 450, + 2091 to 451, + 14906 to 14898, + 14907 to 14899, + 14856 to 14832, + 14857 to 14833, + 14858 to 14834 +) + +val TIN_OBJECTS = mapOf( + 11597 to 11555, + 11958 to 11556, + 11959 to 11557, + 11933 to 11552, + 11934 to 11553, + 11935 to 11554, + 2094 to 450, + 2095 to 451, + 14092 to 14894, + 14903 to 14895 +) + +val IRON_OBJECTS = mapOf( + 11954 to 11555, + 11955 to 11556, + 11956 to 11557, + 2092 to 450, + 2093 to 451, + 14900 to 14892, + 14901 to 14893, + 14913 to 14915, + 14914 to 14916 +) + +val COAL_OBJECTS = mapOf( + 11963 to 11555, + 11964 to 11556, + 11965 to 11557, + 11930 to 11552, + 11931 to 11553, + 11932 to 11554, + 2096 to 450, + 2097 to 451, + 14850 to 14832, + 14851 to 14833, + 14852 to 14834 +) + +val SILVER_OBJECTS = mapOf( + 11948 to 11555, + 11949 to 11556, + 11950 to 11557, + 2100 to 450, + 2101 to 451 +) + +val GOLD_OBJECTS = mapOf( + 11951 to 11555, + 11952 to 11556, + 11953 to 11557, + 2098 to 450, + 2099 to 451 +) + +val MITHRIL_OBJECTS = mapOf( + 11945 to 11555, + 11946 to 11556, + 11947 to 11557, + 11942 to 11552, + 11943 to 11553, + 11944 to 11554, + 2102 to 450, + 2103 to 451, + 14853 to 14832, + 14854 to 14833, + 14855 to 14834 +) + +val ADAMANT_OBJECTS = mapOf( + 11939 to 11552, + 11940 to 11553, + 11941 to 11554, + 2104 to 450, + 2105 to 451, + 14862 to 14832, + 14863 to 14833, + 14864 to 14834 +) + +val RUNITE_OBJECTS = mapOf( + 2106 to 450, + 2107 to 451, + 14859 to 14832, + 14860 to 14833, + 14861 to 14834 +) \ No newline at end of file diff --git a/game/plugin/skills/mining/src/pickaxe.kt b/game/plugin/skills/mining/src/pickaxe.kt index 4b5f0faa..a669f492 100644 --- a/game/plugin/skills/mining/src/pickaxe.kt +++ b/game/plugin/skills/mining/src/pickaxe.kt @@ -1,23 +1,27 @@ package org.apollo.game.plugin.skills.mining -import org.apollo.game.model.Animation; +import org.apollo.game.model.Animation +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.mining -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) +enum class Pickaxe(val id: Int, val level: Int, animation: Int, val pulses: Int) { + BRONZE(id = 1265, level = 1, animation = 625, pulses = 8), + ITRON(id = 1267, level = 1, animation = 626, pulses = 7), + STEEL(id = 1269, level = 1, animation = 627, pulses = 6), + MITHRIL(id = 1273, level = 21, animation = 629, pulses = 5), + ADAMANT(id = 1271, level = 31, animation = 628, pulses = 4), + RUNE(id = 1275, level = 41, animation = 624, pulses = 3); + + val animation = Animation(animation) + + companion object { + private val PICKAXES = Pickaxe.values().sortedByDescending { it.level } + + fun bestFor(player: Player): Pickaxe? { + return PICKAXES.asSequence() + .filter { it.level <= player.mining.current } + .filter { player.equipment.contains(it.id) || player.inventory.contains(it.id) } + .firstOrNull() + } + } } - -val PICKAXES = Pickaxe.values() - - - -fun getPickaxes(): Array { - return PICKAXES -} - -fun lookupPickaxe(id: Int): Pickaxe? = PICKAXES.find { it.id == id } -