diff --git a/game/plugin/skills/runecrafting/build.gradle b/game/plugin/skills/runecrafting/build.gradle new file mode 100644 index 000000000..595add781 --- /dev/null +++ b/game/plugin/skills/runecrafting/build.gradle @@ -0,0 +1,11 @@ +plugin { + name = "runecrafting-skill" + packageName = "org.apollo.game.plugin.skills.runecrafting" + authors = [ + "Major", + "BugCrusher", + "tlf30" + ] + + dependencies = ["util:lookup", "api"] +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/action.kt b/game/plugin/skills/runecrafting/src/action.kt new file mode 100644 index 000000000..6beb45704 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/action.kt @@ -0,0 +1,75 @@ +import org.apollo.game.action.ActionBlock +import org.apollo.game.action.AsyncDistancedAction +import org.apollo.game.action.DistancedAction +import org.apollo.game.model.Animation +import org.apollo.game.model.Graphic +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player +import org.apollo.game.plugin.api.Definitions +import org.apollo.game.plugin.api.runecraft +import org.apollo.util.LanguageUtil + +private val blankTiaraId = 5525 +private val runecraftingAnimation = Animation(791) +private val runecraftingGraphic = Graphic(186, 0, 100) +private val runeEssenceId = 1436 + +class TeleportAction(val player: Player, val start: Position, val distance: Int, val end: Position) : DistancedAction(0, true, player, start, distance) { + override fun executeAction() { + player.teleport(end) + stop() + } +} + +class CreateTiaraAction(val player: Player, val position: Position, val tiara: Tiara, val altar: Altar) : DistancedAction(0, true, player, position, 2) { + override fun executeAction() { + if (tiara.altar != altar) { + player.sendMessage("You can't use that talisman on this altar.") + stop() + return + } + + if (player.inventory.contains(blankTiaraId)) { + player.inventory.remove(blankTiaraId) + player.inventory.add(tiara.id) + player.runecraft.experience += tiara.xp + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + stop() + } + } +} + +class RunecraftingAction(val player: Player, val rune: Rune, altar: Altar) : AsyncDistancedAction(0, true, player, altar.center, 3) { + override fun action(): ActionBlock = { + if (player.runecraft.current < rune.level) { + player.sendMessage("You need a runecrafting level of ${rune.level} to craft this rune.") + stop() + } + + if (!player.inventory.contains(runeEssenceId)) { + player.sendMessage("You need rune essence to craft runes.") + stop() + } + + player.turnTo(position) + player.playAnimation(runecraftingAnimation) + player.playGraphic(runecraftingGraphic) + + wait(1) + + val name = Definitions.item(rune.id)?.name; + val nameArticle = LanguageUtil.getIndefiniteArticle(name) + val essenceAmount = player.inventory.removeAll(runeEssenceId) + val runeAmount = essenceAmount * rune.getBonus() + val runesDescription = if (runeAmount > 1) "some ${name}s" else "$nameArticle $name" + + player.sendMessage("You craft the rune essence into $runesDescription") + player.inventory.add(rune.id, runeAmount.toInt()) + player.runecraft.experience += rune.xp + stop() + } + +} + + diff --git a/game/plugin/skills/runecrafting/src/altar.kt b/game/plugin/skills/runecrafting/src/altar.kt new file mode 100644 index 000000000..3895a26aa --- /dev/null +++ b/game/plugin/skills/runecrafting/src/altar.kt @@ -0,0 +1,23 @@ +import org.apollo.game.model.Position + +enum class Altar(val entranceId: Int, val craftingId: Int, val portalId: Int, val entrance: Position, val exit: Position, val center: Position) { + AIR_ALTAR(2452, 2478, 2465, Position(2841, 4829), Position(2983, 3292), Position(2844, 4834)), + MIND_ALTAR(2453, 2479, 2466, Position(2793, 4828), Position(2980, 3514), Position(2786, 4841)), + WATER_ALTAR(2454, 2480, 2467, Position(2726, 4832), Position(3187, 3166), Position(2716, 4836)), + EARTH_ALTAR(2455, 2481, 2468, Position(2655, 4830), Position(3304, 3474), Position(2658, 4841)), + FIRE_ALTAR(2456, 2482, 2469, Position(2574, 4849), Position(3311, 3256), Position(2585, 4838)), + BODY_ALTAR(2457, 2483, 2470, Position(2524, 4825), Position(3051, 3445), Position(2525, 4832)), + COSMIC_ALTAR(2458, 2484, 2471, Position(2142, 4813), Position(2408, 4379), Position(2142, 4833)), + LAW_ALTAR(2459, 2485, 2472, Position(2464, 4818), Position(2858, 3379), Position(2464, 4832)), + NATURE_ALTAR(2460, 2486, 2473, Position(2400, 4835), Position(2867, 3019), Position(2400, 4841)), + CHAOS_ALTAR(2461, 2487, 2474, Position(2268, 4842), Position(3058, 3591), Position(2271, 4842)), + DEATH_ALTAR(2462, 2488, 2475, Position(2208, 4830), Position(3222, 3222), Position(2205, 4836)); + + companion object { + private val ALTARS = Altar.values() + + fun findByEntranceId(id: Int): Altar? = ALTARS.find { Altar -> Altar.entranceId == id } + fun findByPortalId(id: Int): Altar? = ALTARS.find { Altar -> Altar.portalId == id } + fun findByCraftingId(id: Int): Altar? = ALTARS.find { Altar -> Altar.craftingId == id } + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/rune.kt b/game/plugin/skills/runecrafting/src/rune.kt new file mode 100644 index 000000000..bc94e94a3 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/rune.kt @@ -0,0 +1,36 @@ +import Altar.* + +enum class Rune(val id: Int, val altar: Altar, val level: Int, val xp: Double) { + AIR_RUNE(556, AIR_ALTAR, 1, 5.0), + MIND_RUNE(558, MIND_ALTAR, 1, 5.5), + WATER_RUNE(555, WATER_ALTAR, 5, 6.0), + EARTH_RUNE(557, EARTH_ALTAR, 9, 6.5), + FIRE_RUNE(554, FIRE_ALTAR, 14, 7.0), + BODY_RUNE(559, BODY_ALTAR, 20, 7.5), + COSMIC_RUNE(564, COSMIC_ALTAR, 27, 8.0), + CHAOS_RUNE(562, CHAOS_ALTAR, 35, 8.5), + NATURE_RUNE(561, NATURE_ALTAR, 44, 9.0), + LAW_RUNE(563, LAW_ALTAR, 54, 9.5), + DEATH_RUNE(560, DEATH_ALTAR, 65, 10.0); + + companion object { + private val RUNES = Rune.values() + + fun findById(id: Int): Rune? = RUNES.find { rune -> rune.id == id } + fun findByAltarId(id: Int): Rune? = RUNES.find { rune -> rune.altar.craftingId == id } + } + + fun getBonus(): Double = when (this) { + Rune.AIR_RUNE -> (Math.floor((level / 11.0)) + 1) + Rune.MIND_RUNE -> (Math.floor((level / 14.0)) + 1) + Rune.WATER_RUNE -> (Math.floor((level / 19.0)) + 1) + Rune.EARTH_RUNE -> (Math.floor((level / 26.0)) + 1) + Rune.FIRE_RUNE -> (Math.floor((level / 35.0)) + 1) + Rune.BODY_RUNE -> (Math.floor((level / 46.0)) + 1) + Rune.COSMIC_RUNE -> (Math.floor((level / 59.0)) + 1) + Rune.CHAOS_RUNE -> (Math.floor((level / 74.0)) + 1) + Rune.NATURE_RUNE -> (Math.floor((level / 91.0)) + 1) + Rune.LAW_RUNE -> 1.0 + Rune.DEATH_RUNE -> 1.0 + } +} diff --git a/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts b/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts new file mode 100644 index 000000000..ece21c98f --- /dev/null +++ b/game/plugin/skills/runecrafting/src/runecrafting.plugin.kts @@ -0,0 +1,81 @@ +import org.apollo.game.message.impl.* +import org.apollo.game.model.entity.EquipmentConstants +import org.apollo.game.model.event.impl.LoginEvent + +private val changeAltarObjectConfigId = 491 + +on_player_event { LoginEvent::class } + .then { + val equippedHat = player.equipment.get(EquipmentConstants.HAT) + val equippedTiaraConfig = equippedHat?.let { item -> Tiara.findById(item.id)?.configId } ?: 0 + val configValue = 1 shl equippedTiaraConfig + + player.send(ConfigMessage(changeAltarObjectConfigId, configValue)) + } + +on { ObjectActionMessage::class } + .where { option == 2 } + .then { + val tiara = Tiara.findByAltarId(id) ?: return@then + val hat = it.equipment.get(EquipmentConstants.HAT) ?: return@then + + if (hat.id == tiara.id && tiara.altar.entranceId == id) { + it.startAction(TeleportAction(it, position, 2, tiara.altar.entrance)) + terminate() + } + } + +on { ItemActionMessage::class } + .where { option == 1 } + .then { player -> + Tiara.findById(id)?.let { + player.send(ConfigMessage(changeAltarObjectConfigId, 0)) + terminate() + } + } + +on { ItemOnObjectMessage::class } + .then { + val tiara = Tiara.findByTalismanId(id) ?: return@then + val altar = Altar.findByCraftingId(objectId) ?: return@then + + it.startAction(CreateTiaraAction(it, position, tiara, altar)) + terminate() + } + +on { ItemOptionMessage::class } + .where { option == 4 } + .then { + val talisman = Talisman.findById(id) ?: return@then + + talisman.sendProximityMessageTo(it) + terminate() + } + +on { ItemOnObjectMessage::class } + .then { + val talisman = Talisman.findById(id) ?: return@then + val altar = Altar.findByEntranceId(objectId) ?: return@then + + it.startAction(TeleportAction(it, position, 2, altar.entrance)) + terminate() + } + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val altar = Altar.findByPortalId(id) ?: return@then + + it.startAction(TeleportAction(it, altar.entrance, 1, altar.exit)) + terminate() + } + +on { ObjectActionMessage::class } + .where { option == 1 } + .then { + val rune = Rune.findByAltarId(id) ?: return@then + val craftingAltar = Altar.findByCraftingId(id) ?: return@then + + it.startAction(RunecraftingAction(it, rune, craftingAltar)) + terminate() + } \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/talisman.kt b/game/plugin/skills/runecrafting/src/talisman.kt new file mode 100644 index 000000000..db81d9dc6 --- /dev/null +++ b/game/plugin/skills/runecrafting/src/talisman.kt @@ -0,0 +1,34 @@ +import org.apollo.game.model.Position +import org.apollo.game.model.entity.Player + +enum class Talisman(val id: Int, val altar: Position) { + AIR_TALISMAN(1438, Position(2985, 3292)), + EARTH_TALISMAN(1440, Position(3306, 3474)), + FIRE_TALISMAN(1442, Position(3313, 3255)), + WATER_TALISMAN(1444, Position(3185, 3165)), + BODY_TALISMAN(1446, Position(3053, 3445)), + MIND_TALISMAN(1448, Position(2982, 3514)), + CHAOS_TALISMAN(1452, Position(3059, 3590)), + COSMIC_TALISMAN(1454, Position(2408, 4377)), + DEATH_TALISMAN(1456, Position(0, 0)), + LAW_TALISMAN(1458, Position(2858, 3381)), + NATURE_TALISMAN(1462, Position(2869, 3019)); + + companion object { + private val TALISMANS = Talisman.values() + + fun findById(id: Int): Talisman? = TALISMANS.find { talisman -> talisman.id == id } + } + + fun sendProximityMessageTo(player: Player) { + if (altar.isWithinDistance(player.position, 10)) { + player.sendMessage("Your talisman glows brightly."); + return + } + + var direction = if (player.position.y > altar.y) "North" else "South"; + direction += if (player.position.x > altar.x) "-East" else "-West"; + + player.sendMessage("The talisman pulls toward the $direction"); + } +} \ No newline at end of file diff --git a/game/plugin/skills/runecrafting/src/tiara.kt b/game/plugin/skills/runecrafting/src/tiara.kt new file mode 100644 index 000000000..549fe76be --- /dev/null +++ b/game/plugin/skills/runecrafting/src/tiara.kt @@ -0,0 +1,24 @@ +import Altar.* +import Talisman.* + +enum class Tiara(val id: Int, val altar: Altar, val talisman: Talisman, val configId: Int, val xp: Double) { + AIR_TIARA(5527, AIR_ALTAR, AIR_TALISMAN, 0, 25.0), + MIND_TIARA(5529, MIND_ALTAR, MIND_TALISMAN, 1, 27.5), + WATER_TIARA(5531, WATER_ALTAR, WATER_TALISMAN, 2, 30.0), + BODY_TIARA(5533, BODY_ALTAR, BODY_TALISMAN, 5, 37.5), + EARTH_TIARA(5535, EARTH_ALTAR, EARTH_TALISMAN, 3, 32.5), + FIRE_TIARA(5537, FIRE_ALTAR, FIRE_TALISMAN, 4, 35.0), + COSMIC_TIARA(5539, COSMIC_ALTAR, COSMIC_TALISMAN, 6, 40.0), + NATURE_TIARA(5541, NATURE_ALTAR, NATURE_TALISMAN, 8, 45.0), + CHAOS_TIARA(5543, CHAOS_ALTAR, CHAOS_TALISMAN, 9, 42.5), + LAW_TIARA(5545, LAW_ALTAR, LAW_TALISMAN, 7, 47.5), + DEATH_TIARA(5548, DEATH_ALTAR, DEATH_TALISMAN, 10, 50.0); + + companion object { + private val TIARAS = Tiara.values() + + fun findById(id: Int): Tiara? = TIARAS.find { tiara -> tiara.id == id } + fun findByAltarId(id: Int): Tiara? = TIARAS.find { tiara -> tiara.altar.entranceId == id } + fun findByTalismanId(id: Int): Tiara? = TIARAS.find { tiara -> tiara.talisman.id == id } + } +} \ No newline at end of file diff --git a/game/src/main/java/org/apollo/game/model/inv/Inventory.java b/game/src/main/java/org/apollo/game/model/inv/Inventory.java index c4ff61769..ae8f081e5 100644 --- a/game/src/main/java/org/apollo/game/model/inv/Inventory.java +++ b/game/src/main/java/org/apollo/game/model/inv/Inventory.java @@ -1,15 +1,14 @@ package org.apollo.game.model.inv; +import com.google.common.base.Preconditions; +import org.apollo.cache.def.ItemDefinition; +import org.apollo.game.model.Item; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; -import org.apollo.cache.def.ItemDefinition; -import org.apollo.game.model.Item; - -import com.google.common.base.Preconditions; - /** * Represents an inventory - a collection of {@link Item}s. * @@ -518,6 +517,15 @@ public int remove(Item item) { return remove(item.getId(), item.getAmount()); } + /** + * Remove all items with the given {@code id} and return the number of + * items removed. + * + * @param id The id of items to remove. + * @return The amount that was removed. + */ + public int removeAll(int id) { return remove(id, getAmount(id)); } + /** * Removes all the listeners. */