diff --git a/game/plugin/skill/firemaking/build.gradle b/game/plugin/skill/firemaking/build.gradle new file mode 100644 index 000000000..64570b914 --- /dev/null +++ b/game/plugin/skill/firemaking/build.gradle @@ -0,0 +1,11 @@ +plugin { + name = "firemaking_skill" + packageName = "org.apollo.game.plugin.skills.firemaking" + authors = [ + "tlf30", + "lare96" + ] + dependencies = [ + "util:lookup", + ] +} diff --git a/game/plugin/skill/firemaking/meta.toml b/game/plugin/skill/firemaking/meta.toml new file mode 100644 index 000000000..7ce607e9e --- /dev/null +++ b/game/plugin/skill/firemaking/meta.toml @@ -0,0 +1,11 @@ +name = "firemaking_skill" +package = "org.apollo.game.plugin.skill.firemaking" +authors = [ + "tlf30", + "lare96" + ] +dependencies = [ "entity_lookup" ] + +[config] +srcDir = "src/" +testDir = "test/" \ No newline at end of file diff --git a/game/plugin/skill/firemaking/src/fireamaking_data.kt b/game/plugin/skill/firemaking/src/fireamaking_data.kt new file mode 100644 index 000000000..01bb8bd6b --- /dev/null +++ b/game/plugin/skill/firemaking/src/fireamaking_data.kt @@ -0,0 +1,22 @@ +import org.apollo.game.model.Animation + +enum class Log(val id: Int, val level: Int, val xp: Double) { + NORMAL(1511, 1, 40.0), + ACHEY(2862, 1, 40.0), + OAK(1521, 15, 60.0), + WILLOW(1519, 30, 90.0), + TEAK(6333, 35, 105.0), + MAPLE(1517, 45, 135.0), + MAHOGANY(6332, 50, 157.5), + YEW(1515, 60, 202.5), + MAGIC(1513, 75, 303.8) +} + +val TINDER_BOX = 590 +val FIRE_OBJ = 2732 +val ASH = 592 +val LIGHT_ANIMATION = Animation(733) + +val LOGS = Log.values() + +fun lookupLog(id: Int): Log? = LOGS.find { it.id == id } \ No newline at end of file diff --git a/game/plugin/skill/firemaking/src/firemaking.plugin.kts b/game/plugin/skill/firemaking/src/firemaking.plugin.kts new file mode 100644 index 000000000..914e7e844 --- /dev/null +++ b/game/plugin/skill/firemaking/src/firemaking.plugin.kts @@ -0,0 +1,138 @@ +import org.apollo.game.action.Action +import org.apollo.game.message.impl.ItemOnItemMessage +import org.apollo.game.model.Direction +import org.apollo.game.model.Item +import org.apollo.game.model.Position +import org.apollo.game.model.entity.* +import org.apollo.game.model.entity.obj.DynamicGameObject +import org.apollo.game.scheduling.ScheduledTask +import java.util.* +import kotlin.properties.Delegates + + +class FiremakingAction(val player: Player, val log: Log):Action(DELAY, true, player) { + + private var started = false + private var groundLog: GroundItem by Delegates.notNull() + val rand = Random() + + companion object { + private val DELAY = 0 + } + + override fun execute() { + mob.walkingQueue.clear() + //Check log level + if (log.level > player.skillSet.getSkill(Skill.FIREMAKING).currentLevel) { + player.sendMessage("You need a Firemaking level of " + log.level + " to light this log.") + stop() + return + } + + //check if we have a tinderbox + if (!player.inventory.contains(TINDER_BOX)) { + player.sendMessage("You need a tinderbox in your inventory in order to light fires.") + stop() + return + } + + if (!started) { + val region = player.world.regionRepository.fromPosition(player.position) + player.sendMessage("You attempt to light the logs.") + if (region.getEntities(player.position, EntityType.DYNAMIC_OBJECT, EntityType.STATIC_OBJECT).isEmpty()) { + player.inventory.remove(log.id) + groundLog = GroundItem.dropped(player.world, player.position, Item(log.id), player) + player.world.spawn(groundLog) + } else { + player.sendMessage("You cannot light a fire here.") + stop() + return + } + started = true + } + + //light the fire + player.playAnimation(LIGHT_ANIMATION) + + if (successfulLight()) { + if (lightFire(Direction.WEST) || + lightFire(Direction.EAST) || + lightFire(Direction.NORTH) || + lightFire(Direction.SOUTH) || + lightFire(Direction.NONE) + ) { + player.sendMessage("The fire catches and the logs begin to burn.") + player.skillSet.addExperience(Skill.FIREMAKING, log.xp) + } else { + player.sendMessage("You cannot light a fire here.") + } + stop() + } + } + + override fun stop() { + super.stop() + player.stopAnimation() + } + + fun successfulLight(): Boolean { + //TODO: This is from lare96, as he mentioned, we need to find the actual chance + val playerLevel = player.skillSet.getSkill(Skill.FIREMAKING).currentLevel + val lowChance = playerLevel - log.level + 5 + if (lowChance > 30) { + return 30 > rand.nextInt(40) + } else { + return lowChance > rand.nextInt(40) + } + } + + + fun lightFire(direction: Direction): Boolean { + if (canLight(direction)) { + val fire = DynamicGameObject.createPublic(player.world, FIRE_OBJ, player.position, 10, 0) + player.walkingQueue.addFirstStep(player.position.step(1, direction)) + val region = player.world.regionRepository.fromPosition(player.position) + region.removeEntity(groundLog) + player.world.spawn(fire) + + //TODO: burn time = log level * 5 + rand(30). I think this is right can someone verify? + + val burnTime = (log.level * 5 + rand.nextInt(30) * 1000) / 600 //convert to pulses + player.world.schedule(object: ScheduledTask(burnTime, false) { + override fun execute() { + region.removeEntity(fire) + player.world.spawn(GroundItem.create(player.world, fire.position, Item(ASH))) + this.stop() + } + + }) + return true + } + return false + } + + fun canLight(direction: Direction): Boolean { + val region = player.world.regionRepository.fromPosition(player.position) + if (direction == Direction.NONE) { + return true + } + if (region.traversable(player.position, EntityType.PLAYER, direction)) { + return true + } + return false + } + +} + + +on { ItemOnItemMessage::class } + .where { (id == TINDER_BOX && lookupLog(targetId) != null) || (targetId == TINDER_BOX && lookupLog(id) != null) } + .then { + if (id == TINDER_BOX) { + it.startAction(FiremakingAction(it, lookupLog(targetId)!!)) + terminate() + } else { + it.startAction(FiremakingAction(it, lookupLog(id)!!)) + terminate() + } + } \ No newline at end of file