From 9986fb5b616c29282dfbe6b07a26cf61eb8c7b98 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Tue, 22 Jun 2021 10:27:28 -0500 Subject: [PATCH] ContentAPI improvements, ported some more content to using ContentAPI --- Server/src/main/kotlin/api/Container.kt | 7 + Server/src/main/kotlin/api/ContentAPI.kt | 153 ++++++++++++++++-- .../game/interaction/InteractionListeners.kt | 2 + .../interaction/item/BraceletOfClayPlugin.kt | 5 +- .../game/interaction/item/CulChestItems.kt | 15 +- .../interaction/item/GrandSeedPodHandler.kt | 50 +++--- .../interaction/object/DemonTauntHandler.kt | 16 +- 7 files changed, 188 insertions(+), 60 deletions(-) create mode 100644 Server/src/main/kotlin/api/Container.kt diff --git a/Server/src/main/kotlin/api/Container.kt b/Server/src/main/kotlin/api/Container.kt new file mode 100644 index 000000000..83b92e3a3 --- /dev/null +++ b/Server/src/main/kotlin/api/Container.kt @@ -0,0 +1,7 @@ +package api + +enum class Container { + INVENTORY, + BANK, + EQUIPMENT +} \ No newline at end of file diff --git a/Server/src/main/kotlin/api/ContentAPI.kt b/Server/src/main/kotlin/api/ContentAPI.kt index 74a27fcf4..1859bd6e0 100644 --- a/Server/src/main/kotlin/api/ContentAPI.kt +++ b/Server/src/main/kotlin/api/ContentAPI.kt @@ -11,9 +11,9 @@ import core.game.node.entity.impl.Animator import core.game.node.entity.impl.Projectile import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player +import core.game.node.entity.player.link.TeleportManager import core.game.node.entity.player.link.audio.Audio import core.game.node.entity.player.link.emote.Emotes -import core.game.node.entity.skill.Skills import core.game.node.entity.skill.gather.SkillingTool import core.game.node.item.GroundItem import core.game.node.item.GroundItemManager @@ -23,7 +23,7 @@ import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.map.path.Pathfinder import core.game.world.update.flag.context.Animation -import rs09.ServerConstants +import core.game.world.update.flag.context.Graphics import rs09.game.content.dialogue.DialogueFile import rs09.game.system.SystemLogger import rs09.game.world.GameWorld @@ -115,14 +115,21 @@ object ContentAPI { * Remove an item from a player's inventory * @param player the player whose inventory to remove the item from * @param item the ID or Item object to remove from the player's inventory + * @param container the Container to remove the items from. An enum exists for this in the api package called Container. Ex: api.Container.BANK */ @JvmStatic - fun removeItem(player: Player, item: T): Boolean { + fun removeItem(player: Player, item: T, container: Container): Boolean { item ?: return false - when (item) { - is Item -> return player.inventory.remove(item) - is Int -> return player.inventory.remove(Item(item)) - else -> SystemLogger.logErr("Attempted to pass a non-item and non-int to removeItem") + val it = when (item) { + is Item -> item + is Int -> Item(item) + else -> throw IllegalStateException("Invalid value passed for item") + } + + when(container){ + Container.INVENTORY -> player.inventory.remove(it) + Container.BANK -> player.bank.remove(it) + Container.EQUIPMENT -> player.equipment.remove(it) } return false } @@ -426,15 +433,21 @@ object ContentAPI { /** * Plays an animation on the entity * @param entity the entity to animate - * @param anim the animation to play + * @param anim the animation to play, can be an ID or an Animation object. * @param forced whether or not to force the animation (usually not necessary) */ @JvmStatic - fun animate(entity: Entity, anim: Animation, forced: Boolean = false) { + fun animate(entity: Entity, anim: T, forced: Boolean = false) { + val animation = when(anim){ + is Int -> Animation(anim) + is Animation -> anim + else -> throw IllegalStateException("Invalid value passed for anim") + } + if (forced) { - entity.animator.forceAnimation(anim) + entity.animator.forceAnimation(animation) } else { - entity.animator.animate(anim) + entity.animator.animate(animation) } } @@ -702,4 +715,122 @@ object ContentAPI { else -> SystemLogger.logErr("Attempt to set the charge of invalid type: ${node.javaClass.simpleName}") } } + + /** + * Gets the used option in the context of an interaction. + * @param player the player to get the used option for. + * @return the option the player used + */ + @JvmStatic + fun getUsedOption(player: Player): String { + return player.getAttribute("interact:option","INVALID") + } + + /** + * Used to play both an Animation and Graphics object simultaneously. + * @param entity the entity to perform this on + * @param anim the Animation object to use, can also be an ID. + * @param gfx the Graphics object to use, can also be an ID. + */ + @JvmStatic + fun visualize(entity: Entity, anim: A, gfx: G){ + val animation = when(anim){ + is Int -> Animation(anim) + is Animation -> anim + else -> throw IllegalStateException("Invalid parameter passed for animation.") + } + + val graphics = when(gfx){ + is Int -> Graphics(gfx) + is Graphics -> gfx + else -> throw IllegalStateException("Invalid parameter passed for graphics.") + } + + entity.visualize(animation,graphics) + } + + /** + * Used to submit a pulse to the GameWorld's Pulser. + * @param pulse the Pulse object to submit + */ + @JvmStatic + fun submitWorldPulse(pulse: Pulse){ + GameWorld.Pulser.submit(pulse) + } + + /** + * Teleports or "instantly moves" an entity to a given Location object. + * @param entity the entity to move + * @param loc the Location object to move them to + * @param type the teleport type to use (defaults to instant). An enum exists as TeleportManager.TeleportType. + */ + @JvmStatic + fun teleport(entity: Entity, loc: Location, type: TeleportManager.TeleportType = TeleportManager.TeleportType.INSTANT){ + entity.teleporter.send(loc,type) + } + + /** + * Sets the dynamic or "temporary" (restores) level of a skill. + * @param entity the entity to set the level for + * @param skill the Skill to set. A Skills enum exists that can be used. Ex: Skills.STRENGTH + * @param level the level to set the skill to + */ + @JvmStatic + fun setTempLevel(entity: Entity, skill: Int, level: Int){ + entity.skills.setLevel(skill, level) + } + + /** + * Gets the static (unchanging/max) level of an entity's skill + * @param entity the entity to get the level for + * @param skill the Skill to get the level of. A Skills enum exists that can be used. Ex: Skills.STRENGTH + * @return the static level of the skill + */ + @JvmStatic + fun getStatLevel(entity: Entity, skill: Int): Int { + return entity.skills.getStaticLevel(skill) + } + + /** + * Gets the dynamic (boostable/debuffable/restoring) level of an entity's skill + * @param entity the entity to get the level for + * @param skill the Skill to get the level of. A Skills enum exists that can be used. Ex: Skills.STRENGTH + * @return the dynamic level of the skill + */ + @JvmStatic + fun getDynLevel(entity: Entity, skill: Int): Int { + return entity.skills.getLevel(skill) + } + + /** + * Adjusts (buffs/debuffs) the given Skill by the amount given. + * @param entity the entity to adjust the skill for + * @param skill the Skill to adjust. A Skills enum exists that can be used. Ex: Skills.STRENGTH + * @param amount the amount to adjust the skill by. Ex-Buff: 5, Ex-Debuff: -5 + */ + @JvmStatic + fun adjustLevel(entity: Entity, skill: Int, amount: Int){ + entity.skills.setLevel(skill, entity.skills.getStaticLevel(skill) + amount) + } + + /** + * Remove all of a given item from the given container + * @param player the player to remove the item from + * @param item the item to remove. Can be an Item object or an ID. + * @param container the Container to remove the item from. An enum exists for this called Container. Ex: Container.BANK + */ + @JvmStatic + fun removeAll(player: Player, item: T, container: Container){ + val it = when(item){ + is Item -> item.id + is Int -> item + else -> throw IllegalStateException("Invalid value passed as item") + } + + when(container){ + Container.EQUIPMENT -> player.equipment.remove(Item(it, amountInEquipment(player, it))) + Container.BANK -> player.bank.remove(Item(it, amountInBank(player, it))) + Container.INVENTORY -> player.inventory.remove(Item(it, amountInInventory(player, it))) + } + } } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/interaction/InteractionListeners.kt b/Server/src/main/kotlin/rs09/game/interaction/InteractionListeners.kt index 7ad902126..4e2f5b1c4 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/InteractionListeners.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/InteractionListeners.kt @@ -176,6 +176,8 @@ object InteractionListeners { val method = get(id,type,option) ?: get(option,type) ?: return false val destOverride = getOverride(type, id, option) ?: getOverride(type,node.id) ?: getOverride(type,option.toLowerCase()) + player.setAttribute("interact:option", option) + if(type != 0) { if(player.locks.isMovementLocked) return false player.pulseManager.run(object : MovementPulse(player, node, flag, destOverride) { diff --git a/Server/src/main/kotlin/rs09/game/interaction/item/BraceletOfClayPlugin.kt b/Server/src/main/kotlin/rs09/game/interaction/item/BraceletOfClayPlugin.kt index 5998ad504..ab0107422 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/item/BraceletOfClayPlugin.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/item/BraceletOfClayPlugin.kt @@ -1,5 +1,6 @@ package rs09.game.interaction.item +import api.ContentAPI import rs09.game.interaction.InteractionListener /** @@ -13,8 +14,8 @@ class BraceletOfClayPlugin : InteractionListener() { override fun defineListeners() { on(BRACELET,ITEM,"operate"){player,node -> - var charge = node.asItem().charge - if (charge > 28) charge = 28 + var charge = ContentAPI.getCharge(node) + if (charge > 28) ContentAPI.setCharge(node, 28).also { charge = 28 } player.sendMessage("You have $charge uses left.") return@on true } diff --git a/Server/src/main/kotlin/rs09/game/interaction/item/CulChestItems.kt b/Server/src/main/kotlin/rs09/game/interaction/item/CulChestItems.kt index c2c94ce54..7ced37e7f 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/item/CulChestItems.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/item/CulChestItems.kt @@ -1,5 +1,6 @@ package rs09.game.interaction.item +import api.ContentAPI import core.game.node.Node import core.game.node.entity.player.Player import core.game.node.item.GroundItemManager @@ -42,15 +43,13 @@ class CulChestItems: InteractionListener() { } fun alchemize(player: Player, node: Node){ - val amount = player.inventory.getAmount(node.id) + player.equipment.getAmount(node.id) - val coins = amount * node.asItem().definition.value + val amount = ContentAPI.amountInInventory(player, node.id) + ContentAPI.amountInEquipment(player, node.id) + val coins = amount * ContentAPI.itemDefinition(node.id).value - player.inventory.remove(Item(node.id,player.inventory.getAmount(node.id))) - player.equipment.remove(Item(node.id)) - if(!player.inventory.add(Item(995,coins))){ - GroundItemManager.create(Item(995,coins),player) - } + ContentAPI.removeAll(player, node.id, api.Container.INVENTORY) + ContentAPI.removeItem(player, node.id, api.Container.EQUIPMENT) + ContentAPI.addItemOrDrop(player, 995, coins) - player.dialogueInterpreter.sendDialogue("The item instantly alchemized itself!") + ContentAPI.sendDialogue(player, "The item instantly alchemized itself!") } } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/interaction/item/GrandSeedPodHandler.kt b/Server/src/main/kotlin/rs09/game/interaction/item/GrandSeedPodHandler.kt index d26092bb1..a18df4a01 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/item/GrandSeedPodHandler.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/item/GrandSeedPodHandler.kt @@ -1,5 +1,6 @@ package rs09.game.interaction.item +import api.ContentAPI import core.cache.def.impl.ItemDefinition import core.game.content.global.travel.glider.GliderPulse import core.game.content.global.travel.glider.Gliders @@ -15,6 +16,7 @@ import core.game.world.update.flag.context.Graphics import core.plugin.Initializable import core.plugin.Plugin import org.rs09.consts.Items +import rs09.game.interaction.InteractionListener import rs09.game.world.GameWorld private const val SQUASH_GRAPHICS_BEGIN = 767 @@ -29,39 +31,27 @@ private const val LAUNCH_ANIMATION = 4547 * @author Ceikry */ @Initializable -class GrandSeedPodHandler : OptionHandler() { - override fun newInstance(arg: Any?): Plugin { - val def = ItemDefinition.forId(Items.GRAND_SEED_POD_9469) - def.handlers["option:squash"] = this - def.handlers["option:launch"] = this - return this - } +class GrandSeedPodHandler : InteractionListener() { - override fun handle(player: Player?, node: Node?, option: String?): Boolean { - player ?: return false - node ?: return false - option ?: return false - when(option){ - "squash" -> { - GameWorld.Pulser.submit(SquashPulse(player)) + override fun defineListeners() { + on(Items.GRAND_SEED_POD_9469, ITEM, "squash", "launch"){player, _ -> + when(ContentAPI.getUsedOption(player)){ + "launch" -> ContentAPI.submitWorldPulse(LaunchPulse(player)) + "squash" -> ContentAPI.submitWorldPulse(SquashPulse(player)) } - "launch" -> { - GameWorld.Pulser.submit(LaunchPulse(player)) - } - + ContentAPI.removeItem(player, Items.GRAND_SEED_POD_9469, api.Container.INVENTORY) + ContentAPI.lock(player, 50) + return@on true } - player.inventory.remove(Item(node.id,1)) - player.lock() - return true } class LaunchPulse(val player: Player): Pulse(){ var counter = 0 override fun pulse(): Boolean { when(counter++){ - 1 -> player.visualize(Animation(LAUNCH_ANIMATION),Graphics(LAUNCH_GRAPHICS)) - 3 -> player.skills.addExperience(Skills.FARMING,100.0) - 4 -> GameWorld.Pulser.submit(GliderPulse(2,player,Gliders.TA_QUIR_PRIW)).also { return true } + 1 -> ContentAPI.visualize(player, LAUNCH_ANIMATION, LAUNCH_GRAPHICS) + 3 -> ContentAPI.rewardXP(player, Skills.FARMING, 100.0) + 4 -> ContentAPI.submitWorldPulse(GliderPulse(2,player,Gliders.TA_QUIR_PRIW)).also { return true } } return false } @@ -71,12 +61,12 @@ class GrandSeedPodHandler : OptionHandler() { var counter = 0 override fun pulse(): Boolean { when(counter++){ - 1 -> player.visualize(Animation(SQUASH_ANIM_BEGIN), Graphics(SQUASH_GRAPHICS_BEGIN)) - 4 -> player.animator.forceAnimation(Animation(1241)) - 5 -> player.properties.teleportLocation = Location.create(2464, 3494, 0) - 6 -> player.visualize(Animation(1241),Graphics(SQUASH_GRAPHICS_END)) - 8 -> player.animator.forceAnimation(Animation(SQUASH_ANIM_END)).also { player.skills.setLevel(Skills.FARMING,player.skills.getStaticLevel(Skills.FARMING) - 5) } - 9 -> player.unlock().also { return true } + 1 -> ContentAPI.visualize(player, SQUASH_ANIM_BEGIN, SQUASH_GRAPHICS_BEGIN) + 4 -> ContentAPI.animate(player, 1241, true) + 5 -> ContentAPI.teleport(player, Location.create(2464, 3494, 0)) + 6 -> ContentAPI.visualize(player, anim = 1241, gfx = SQUASH_GRAPHICS_END) + 8 -> ContentAPI.animate(player, SQUASH_ANIM_END, true).also { ContentAPI.adjustLevel(player, Skills.FARMING, -5) } + 9 -> ContentAPI.unlock(player).also { return true } } return false } diff --git a/Server/src/main/kotlin/rs09/game/interaction/object/DemonTauntHandler.kt b/Server/src/main/kotlin/rs09/game/interaction/object/DemonTauntHandler.kt index e52a99e38..9776e512d 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/object/DemonTauntHandler.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/object/DemonTauntHandler.kt @@ -1,8 +1,10 @@ package rs09.game.interaction.`object` +import api.ContentAPI import core.game.node.entity.player.link.diary.DiaryType import core.game.node.entity.player.link.emote.Emotes import core.game.world.map.RegionManager +import org.rs09.consts.NPCs import rs09.game.interaction.InteractionListener /** @@ -14,15 +16,11 @@ class DemonTauntHandler : InteractionListener(){ override fun defineListeners() { on(BARS,OBJECT,"taunt-through"){player,_ -> - player.packetDispatch.sendMessage("You taunt the demon, making it growl.") - val localNpcs = RegionManager.getLocalNpcs(player) - player.animator.animate(Emotes.RASPBERRY.animation) - for (npc in localNpcs) { - if (npc.id == 82) { - npc.sendChat("Graaaagh!", 1) - player.faceLocation(npc.location) - } - } + ContentAPI.sendMessage(player, "You taunt the demon, making it growl.") + val demon = ContentAPI.findLocalNPC(player, NPCs.LESSER_DEMON_82) ?: return@on true + ContentAPI.sendChat(demon, "Graaagh!") + ContentAPI.face(demon, player, 3) + ContentAPI.emote(player, Emotes.RASPBERRY) player.achievementDiaryManager.finishTask(player, DiaryType.LUMBRIDGE, 1, 13) return@on true }