Fix nitpicks in Mining plugin

Also adds equals() and hashcode() implementations to the various
Mining actions.
This commit is contained in:
Major
2018-03-28 16:50:43 +01:00
parent 173623b76b
commit 6941fc9de0
5 changed files with 257 additions and 214 deletions
+1
View File
@@ -3,6 +3,7 @@ plugin {
authors = [ authors = [
"Graham", "Graham",
"Mikey`", "Mikey`",
"Major",
"WH:II:DOW", "WH:II:DOW",
"Requa", "Requa",
"Clifton", "Clifton",
+10 -9
View File
@@ -1,12 +1,13 @@
package org.apollo.game.plugin.skills.mining package org.apollo.game.plugin.skills.mining
enum class Gem(val id: Int, val chance: Int) { enum class Gem(val id: Int) { // TODO add gem drop chances
UNCUT_SAPPHIRE(1623, 0), UNCUT_SAPPHIRE(1623),
UNCUT_EMERALD(1605, 0), UNCUT_EMERALD(1605),
UNCUT_RUBY(1619, 0), UNCUT_RUBY(1619),
UNCUT_DIAMOND(1617, 0) UNCUT_DIAMOND(1617);
companion object {
private val GEMS = Gem.values().associateBy({ it.id }, { it })
fun lookup(id: Int): Gem? = GEMS[id]
}
} }
val GEMS = Gem.values()
fun lookupGem(id: Int): Gem? = GEMS.find { it.id == id }
+84 -46
View File
@@ -12,17 +12,33 @@ import org.apollo.game.plugin.api.findObject
import org.apollo.game.plugin.api.mining import org.apollo.game.plugin.api.mining
import org.apollo.game.plugin.api.rand import org.apollo.game.plugin.api.rand
import org.apollo.game.plugin.skills.mining.Ore 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.Pickaxe
import org.apollo.game.plugin.skills.mining.lookupOreRock
import org.apollo.net.message.Message 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<GameObject> { 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) val region = world.regionRepository.fromPosition(position)
return region.findObject(position, objectId) return region.findObject(position, objectId).orElse(null)
} }
fun isSuccessful(mob: Player): Boolean { fun isSuccessful(mob: Player): Boolean {
@@ -41,27 +57,22 @@ class MiningAction(
) : AsyncDistancedAction<Player>(PULSES, true, player, target.position, ORE_SIZE) { ) : AsyncDistancedAction<Player>(PULSES, true, player, target.position, ORE_SIZE) {
companion object { companion object {
private val PULSES = 0 private const val PULSES = 0
private val ORE_SIZE = 1 private const 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()
}
/** /**
* Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it.
*/ */
fun start(message: ObjectActionMessage, player: Player, ore: Ore) { fun start(message: ObjectActionMessage, player: Player, ore: Ore) {
val pickaxe = pickaxeFor(player) val pickaxe = Pickaxe.bestFor(player)
if (pickaxe != null) {
val action = MiningAction(player, pickaxe, MiningTarget(message.id, message.position, ore)) if (pickaxe == null) {
player.startAction(action)
} else {
player.sendMessage("You do not have a pickaxe for which you have the level to use.") 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() message.terminate()
@@ -83,7 +94,7 @@ class MiningAction(
wait(tool.pulses) wait(tool.pulses)
val obj = target.getObject(mob.world) val obj = target.getObject(mob.world)
if (!obj.isPresent) { if (obj == null) {
stop() stop()
} }
@@ -94,25 +105,46 @@ class MiningAction(
} }
if (mob.inventory.add(target.ore.id)) { 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.sendMessage("You manage to mine some $oreName")
mob.mining.experience += target.ore.exp 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() 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( class ExpiredProspectingAction(
mob: Player, mob: Player,
position: Position position: Position
) : DistancedAction<Player>(PROSPECT_PULSES, true, mob, position, ORE_SIZE) { ) : DistancedAction<Player>(DELAY, true, mob, position, ORE_SIZE) {
companion object { companion object {
private val PROSPECT_PULSES = 0 private const val DELAY = 0
private val ORE_SIZE = 1 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() { override fun executeAction() {
@@ -120,17 +152,27 @@ class ExpiredProspectingAction(
stop() 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( class ProspectingAction(
player: Player, player: Player,
position: Position, position: Position,
private val ore: Ore private val ore: Ore
) : AsyncDistancedAction<Player>(PROSPECT_PULSES, true, player, position, ORE_SIZE) { ) : AsyncDistancedAction<Player>(DELAY, true, player, position, ORE_SIZE) {
companion object { companion object {
private val PROSPECT_PULSES = 3 private const val DELAY = 3
private val ORE_SIZE = 1 private const val ORE_SIZE = 1
/** /**
* Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it. * Starts a [MiningAction] for the specified [Player], terminating the [Message] that triggered it.
@@ -141,7 +183,6 @@ class ProspectingAction(
message.terminate() message.terminate()
} }
} }
override fun action(): ActionBlock = { override fun action(): ActionBlock = {
@@ -151,27 +192,24 @@ class ProspectingAction(
wait() wait()
val oreName = Definitions.item(ore.id)?.name?.toLowerCase() val oreName = Definitions.item(ore.id)?.name?.toLowerCase()
mob.sendMessage("This rock contains $oreName") mob.sendMessage("This rock contains $oreName.")
stop() 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
} }
on { ObjectActionMessage::class } override fun hashCode(): Int = Objects.hash(mob, position, ore)
.where { option == 1 }
.then {
val ore = lookupOreRock(id)
if (ore != null) {
MiningAction.start(this, it, ore)
}
} }
on { ObjectActionMessage::class } private object Actions {
.where { option == 2 } const val MINING = 1
.then { const val PROSPECTING = 2
val ore = lookupOreRock(id)
if (ore != null) { // TODO send expired action if rock is expired
ProspectingAction.start(this, it, ore)
}
} }
+35 -36
View File
@@ -1,13 +1,46 @@
package org.apollo.game.plugin.skills.mining package org.apollo.game.plugin.skills.mining
import com.google.common.collect.Maps.asMap
/* /*
Thanks to Mikey` <http://www.rune-server.org/members/mikey%60/> for helping Thanks to Mikey` <http://www.rune-server.org/members/mikey%60/> for helping
to find some of the item/object IDs, minimum levels and experiences. to find some of the item/object IDs, minimum levels and experiences.
Thanks to Clifton <http://www.rune-server.org/members/clifton/> for helping Thanks to Clifton <http://www.rune-server.org/members/clifton/> for helping
to find some of the expired object IDs. to find some of the expired object IDs.
*/ */
/**
* 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 objects: Map<Int, Int>,
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);
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 fromRock(id: Int): Ore? = ORE_ROCKS[id]
fun fromExpiredRock(id: Int): Ore? = EXPIRED_ORE[id]
}
}
// Maps from regular rock id to expired rock id.
val CLAY_OBJECTS = mapOf( val CLAY_OBJECTS = mapOf(
2108 to 450, 2108 to 450,
@@ -119,37 +152,3 @@ val RUNITE_OBJECTS = mapOf(
14860 to 14833, 14860 to 14833,
14861 to 14834 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<Int, Int>, 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 = enumValues<Ore>()
fun lookupOre(id: Int): Ore? = ORES.find { it.id == id }
fun lookupOreRock(id: Int): Ore? {
for (ore in enumValues<Ore>()) {
for (rock in ore.objects) {
if (rock.key == id) {
return ore
}
}
}
return null
}
+22 -18
View File
@@ -1,23 +1,27 @@
package org.apollo.game.plugin.skills.mining 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) { enum class Pickaxe(val id: Int, val level: Int, animation: Int, val pulses: Int) {
RUNE(1275, 41, Animation(624), 3), BRONZE(id = 1265, level = 1, animation = 625, pulses = 8),
ADAMANT(1271, 31, Animation(628), 4), ITRON(id = 1267, level = 1, animation = 626, pulses = 7),
MITHRIL(1273, 21, Animation(629), 5), STEEL(id = 1269, level = 1, animation = 627, pulses = 6),
STEEL(1269, 1, Animation(627), 6), MITHRIL(id = 1273, level = 21, animation = 629, pulses = 5),
ITRON(1267, 1, Animation(626), 7), ADAMANT(id = 1271, level = 31, animation = 628, pulses = 4),
BRONZE(1265, 1, Animation(625), 8) 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<Pickaxe> {
return PICKAXES
} }
fun lookupPickaxe(id: Int): Pickaxe? = PICKAXES.find { it.id == id }