Files
apollo/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts
T
2018-03-28 17:39:46 +01:00

114 lines
3.8 KiB
Kotlin

import org.apollo.game.GameConstants
import org.apollo.game.action.ActionBlock
import org.apollo.game.action.AsyncDistancedAction
import org.apollo.game.message.impl.ObjectActionMessage
import org.apollo.game.model.Position
import org.apollo.game.model.World
import org.apollo.game.model.entity.Player
import org.apollo.game.model.entity.obj.GameObject
import org.apollo.game.plugin.api.Definitions
import org.apollo.game.plugin.api.expireObject
import org.apollo.game.plugin.api.findObject
import org.apollo.game.plugin.api.rand
import org.apollo.game.plugin.api.woodcutting
import org.apollo.game.plugin.skills.woodcutting.Axe
import org.apollo.game.plugin.skills.woodcutting.Tree
import java.util.concurrent.TimeUnit
// TODO Accurate chopping rates, e.g. https://twitter.com/JagexKieren/status/713403124464107520
on { ObjectActionMessage::class }
.where { option == 1 }
.then { player ->
Tree.lookup(id)?.let { WoodcuttingAction.start(this, player, it) }
}
class WoodcuttingTarget(private val objectId: Int, val position: Position, val tree: Tree) {
/**
* Get the tree object in the world
*/
fun getObject(world: World): GameObject? {
val region = world.regionRepository.fromPosition(position)
return region.findObject(position, objectId).orElse(null)
}
/**
* Returns whether or not the tree was cut down.
*/
fun isCutDown(): Boolean = rand(100) <= tree.chance * 100
}
class WoodcuttingAction(
player: Player,
private val tool: Axe,
private val target: WoodcuttingTarget
) : AsyncDistancedAction<Player>(DELAY, true, player, target.position, TREE_SIZE) {
companion object {
private const val DELAY = 0
private const val TREE_SIZE = 2
private const val MINIMUM_RESPAWN_TIME = 30L // In seconds
/**
* Starts a [WoodcuttingAction] for the specified [Player], terminating the [ObjectActionMessage] that triggered
* it.
*/
fun start(message: ObjectActionMessage, player: Player, wood: Tree) {
val axe = Axe.bestFor(player)
if (axe != null) {
if (player.inventory.freeSlots() == 0) {
player.inventory.forceCapacityExceeded()
return
}
val action = WoodcuttingAction(player, axe, WoodcuttingTarget(message.id, message.position, wood))
player.startAction(action)
} else {
player.sendMessage("You do not have an axe for which you have the level to use.")
}
message.terminate()
}
}
override fun action(): ActionBlock = {
mob.turnTo(position)
val level = mob.woodcutting.current
if (level < target.tree.level) {
mob.sendMessage("You do not have the required level to cut down this tree.")
stop()
}
while (isRunning) {
mob.sendMessage("You swing your axe at the tree.")
mob.playAnimation(tool.animation)
wait(tool.pulses)
// Check that the object exists in the world
val obj = target.getObject(mob.world)
if (obj == null) {
stop()
}
if (mob.inventory.add(target.tree.id)) {
val logName = Definitions.item(target.tree.id)!!.name.toLowerCase()
mob.sendMessage("You managed to cut some $logName.")
mob.woodcutting.experience += target.tree.exp
}
if (target.isCutDown()) {
// respawn time: http://runescape.wikia.com/wiki/Trees
val respawn = TimeUnit.SECONDS.toMillis(MINIMUM_RESPAWN_TIME + rand(150)) / GameConstants.PULSE_DELAY
mob.world.expireObject(obj!!, target.tree.stump, respawn.toInt())
stop()
}
}
}
}