diff --git a/game/plugin/skills/woodcutting/build.gradle b/game/plugin/skills/woodcutting/build.gradle new file mode 100644 index 00000000..886112d7 --- /dev/null +++ b/game/plugin/skills/woodcutting/build.gradle @@ -0,0 +1,7 @@ +plugin { + name = "woodcutting_skill" + packageName = "org.apollo.game.plugin.skills.woodcutting" + authors = [ + "tlf30" + ] +} \ No newline at end of file diff --git a/game/plugin/skills/woodcutting/meta.toml b/game/plugin/skills/woodcutting/meta.toml new file mode 100644 index 00000000..c490c711 --- /dev/null +++ b/game/plugin/skills/woodcutting/meta.toml @@ -0,0 +1,9 @@ +name = "woodcutting-skill" +package = "org.apollo.game.plugin.skills.woodcutting" +authors = [ + "tlf30" + ] + +[config] +srcDir = "src/" +testDir = "test/" diff --git a/game/plugin/skills/woodcutting/src/axe.kt b/game/plugin/skills/woodcutting/src/axe.kt new file mode 100644 index 00000000..ae3e11a7 --- /dev/null +++ b/game/plugin/skills/woodcutting/src/axe.kt @@ -0,0 +1,23 @@ +package org.apollo.game.plugin.skills.mining + +import org.apollo.game.model.Animation; + +//Animation IDs: https://www.rune-server.ee/runescape-development/rs2-client/configuration/272373-emote-gfx-id-list.html +enum class Axe(val id: Int, val level: Int, val animation: Animation, val pulses: Int) { + RUNE(1359, 41, Animation(867), 3), + ADAMANT(1357, 31, Animation(869), 4), + MITHRIL(1355, 21, Animation(871), 5), + BLACK(1361, 11, Animation(873), 6), + STEEL(1353, 6, Animation(875), 6), + IRON(1349, 1, Animation(877), 7), + BRONZE(1351, 1, Animation(879), 8) +} + +val AXES = Axe.values() + +fun getAxes(): Array { + return AXES +} + +fun lookupPickaxe(id: Int): Axe? = AXES.find { it.id == id } + diff --git a/game/plugin/skills/woodcutting/src/wood.kt b/game/plugin/skills/woodcutting/src/wood.kt new file mode 100644 index 00000000..6201d8cd --- /dev/null +++ b/game/plugin/skills/woodcutting/src/wood.kt @@ -0,0 +1,85 @@ +package org.apollo.game.plugin.skills.mining + + +/** + * values thanks to: http://oldschoolrunescape.wikia.com/wiki/Woodcutting + */ +enum class Wood(val id: Int, val objects: IntArray, val stump: Int, val level: Int, val exp: Double, val chance: Double) { + NORMAL(1511, NORMAL_OBJECTS, NORMAL_STUMP, 1, 25.0, 100.0), + ACHEY(2862, ACHEY_OBJECTS, ACHEY_STUMP, 1, 25.0, 100.0), + OAK(1521, OAK_OBJECTS, OAK_STUMP, 15, 37.5, 0.125), + WILLOW(1519, WILLOW_OBJECTS, WILLOW_STUMP, 30, 67.5, 0.125), + TEAK(6333, TEAK_OBJECTS, TEAK_STUMP, 35, 85.0, 0.125), + MAPLE(1517, MAPLE_OBJECTS, MAPLE_STUMP, 45, 100.0, 0.125), + MAHOGANY(6332, MAHOGANY_OBJECTS, MAHOGANY_STUMP, 50, 125.0,0.125), + YEW(1515, YEW_OBJECTS, YEW_STUMP, 60, 175.0, 0.125), + MAGIC(1513, MAGIC_OBJECTS, MAGIC_STUMP, 75, 250.0, 0.125), +} + +val WOOD = Wood.values() + +fun lookupWood(id: Int): Wood? =WOOD.find { it.id == id } + +fun lookupTree(id: Int): Wood? { + for (wood in WOOD) { + for (tree in wood.objects) { + if (tree == id) { + return wood + } + } + } + return null +} + +val NORMAL_STUMP = 1342 +val ACHEY_STUMP = 3371 +val OAK_STUMP = 1342 +val WILLOW_STUMP = 1342 +val TEAK_STUMP = 1342 +val MAPLE_STUMP = 1342 +val MAHOGANY_STUMP = 1342 +val YEW_STUMP = 1342 +val MAGIC_STUMP = 1324 + +val NORMAL_OBJECTS = intArrayOf( + 1276, 1277, 1278, 1279, 1280, 1282, 1283, 1284, 1285, 1285, 1286, 1289, 1290, 1291, 1315, + 1316, 1318, 1330, 1331, 1332, 1365, 1383, 1384, 2409, 3033, 3034, 3035, 3036, 3881, 3882, + 3883, 5902, 5903, 5904, 10041 +) + +val ACHEY_OBJECTS = intArrayOf( + 2023 +) + +val OAK_OBJECTS = intArrayOf( + 1281, 3037 +) + +val WILLOW_OBJECTS = intArrayOf( + 5551, 5552, 5553 +) + +val TEAK_OBJECTS = intArrayOf( + 9036 +) + + +val MAPLE_OBJECTS = intArrayOf( + 1307, 4674 +) + +val MAHOGANY_OBJECTS = intArrayOf( + 9034 +) + + +val YEW_OBJECTS = intArrayOf( + 1309 +) + +val MAGIC_OBJECTS = intArrayOf( + 1292, 1306 +) + + + diff --git a/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts new file mode 100644 index 00000000..8b5d0a48 --- /dev/null +++ b/game/plugin/skills/woodcutting/src/woodcutting.plugin.kts @@ -0,0 +1,163 @@ +import org.apollo.cache.def.ItemDefinition +import org.apollo.game.action.DistancedAction +import org.apollo.game.message.impl.ObjectActionMessage +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 java.util.* + +class WoodcuttingAction(val player: Player, val objectID: Int, val p: Position, val wood: Wood) : DistancedAction(PULSES, true, player, p, TREE_SIZE) { + + companion object { + private val PULSES = 0 + private val TREE_SIZE = 1; + } + + private var counter: Int = 0 + private var started: Boolean = false + private val rand: Random = Random() + + override fun executeAction() { + System.out.println("Cutting " + wood.id + " @ " + p) + val level = mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel + val axe = findAxe() + + + //check that our pick can mine the wood + if (axe == null || level < axe.level) { + mob.sendMessage("You do not have a axe for which you have the level to use.") + stop() + return + } + + //check that we can mine the wood + if (level < wood.level) { + mob.sendMessage("You do not have the required level to mine this rock.") + stop() + return + } + + //start the process of cutting + if (started) { + if (counter == 0) { + //Check inv capacity + if (mob.inventory.freeSlots() == 0) { + mob.inventory.forceCapacityExceeded() + stop() + return + } + if (mob.inventory.add(wood.id)) { + //TODO: Use lookup from utils once it has a lookup function for IDs + val woodName = ItemDefinition.lookup(wood.id).name.toLowerCase(); + mob.sendMessage("You managed to cut some " + woodName + ".") + mob.skillSet.addExperience(Skill.WOODCUTTING, wood.exp) + + } else { + System.out.println("Failed to add wood to inv"); + stop(); + return; + } + + if (!cuttingSuccessful(wood.chance)) { + System.out.println("Chopping...") + cut(axe) + return //We did not cut down the tree... Keep going + } else { + //We cut down the tree + var treeEntity: StaticGameObject? = null + val region = mob.world.regionRepository.fromPosition(position) + val entities = region.getEntities(position) + for (entity: Entity in entities) { + if (entity is StaticGameObject) { + System.out.println("Entity at cutting location: " + entity.id + " with type: " + entity.entityType) + if (entity.id == objectID) { + treeEntity = entity + } + } + } + if (treeEntity == null) { //tree entity not found at location... + System.out.println("WARNING: Invalid cutting condition on tree"); + stop() + return + } + //Get ID of exipred wood + val expiredObjectID = wood.stump; + val expiredRockEntity = StaticGameObject(mob.world, expiredObjectID!!, position, treeEntity!!.type, treeEntity!!.orientation) + //Remove normal wood and replace with expired + System.out.println("Removing " + objectID + " addding " + expiredObjectID) + System.out.println("Adding tasks") + //add task to remove normal wood and replace with depleted + mob.world.schedule(object: ScheduledTask(0, true) { + override fun execute() { + System.out.println("running deplete task") + //Replace normal wood with expired wood + region.removeEntity(treeEntity); + region.addEntity(expiredRockEntity) + this.stop() //Makes task run once + } + }) + //add task to respawn normal wood + //respawn time: http://runescape.wikia.com/wiki/Trees + val respawn = ((30 * 1000) / 600) + ((rand.nextInt(150) * 1000) / 600) // between 30 sec and 3 min respawm + mob.world.schedule(object: ScheduledTask(respawn, false) { + override fun execute() { + System.out.println("running wood task") + //Replace expired wood with normal wood + region.removeEntity(expiredRockEntity) + region.addEntity(treeEntity); + this.stop() //Makes task run once + } + }) + stop() + return + } + } + counter -= 1 + } else { + started = true + cut(axe) + } + } + + private fun findAxe(): Axe? { + for (axe in getAxes()) { + if (axe!!.level > mob.skillSet.getSkill(Skill.WOODCUTTING).currentLevel) { + continue; + } + val weponSlot = mob.equipment.get(EquipmentConstants.WEAPON) + if (weponSlot != null && weponSlot.id == axe.id) { + return axe; + } else if (mob.inventory.contains(axe.id)) { + return axe; + } + } + return null; + } + + private fun cut(axe: Axe) { + mob.sendMessage("You swing your axe at the tree.") + mob.playAnimation(axe.animation) + counter = axe.pulses + mob.turnTo(position) + } + + private fun cuttingSuccessful(woodChance: Double): Boolean { + return rand.nextInt(100) <= woodChance * 100; + } +} + + +on {ObjectActionMessage::class} + .where {option == 1} + .then { + if (lookupTree(id) != null) { + it.startAction(WoodcuttingAction(it, id, this.position, lookupTree(id)!!)) + } else { + System.out.println("Unknown wood: " + id) + } + }