From 6deadc6f903cc3ea4a13ab0498aa80b22a122c78 Mon Sep 17 00:00:00 2001 From: Player Name Date: Wed, 17 Apr 2024 07:34:12 +0000 Subject: [PATCH] Fixed an off-by-one error that made cooking brawlers unobtainable Reworked the ::npc admin command to take an optional amount argument. Usage: ::npc id [amount] [shouldWalk] Summoning points now no longer regenerate automatically Rewrote the ring of life Reverting a slayer ring to an enchanted gem no longer destroys the item if inventory is full The inauthentic mounted glory in a POH now respects teleblock Fixed revenents infinite healing Winkins' farm exit message is now split correctly Added egg spawn in front of the chicken shrine in Zanaris and added its authentic use handler to the shrine --- Server/data/configs/ground_spawns.json | 2 +- .../main/content/data/EnchantedJewellery.kt | 93 ++++++++++++------- .../item/EnchantedJewelleryListener.kt | 9 +- .../decoration/questhall/MountedGlory.kt | 7 +- .../minigame/vinesweeper/Vinesweeper.kt | 6 +- .../handlers/EvilChickenLairListener.kt | 4 + .../handlers/revenants/RevenantNPC.java | 32 ++++--- .../node/entity/combat/ImpactHandler.java | 12 ++- .../system/command/sets/SpawnCommandSet.kt | 41 ++++++-- .../game/system/timer/impl/SkillRestore.kt | 2 +- .../core/game/world/map/zone/ZoneMonitor.java | 17 ++-- .../world/map/zone/impl/WildernessZone.java | 2 +- 12 files changed, 149 insertions(+), 78 deletions(-) diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index 506e0ddec..6b94f4807 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -461,7 +461,7 @@ }, { "item_id": "1944", - "loc_data": "{1,3191,3276,0,35}-{1,3229,3299,0,35}-{1,3226,3301,0,35}-{1,3015,3295,0,30}-{1,3016,3295,0,30}-{1,2853,3370,0,35}-{1,2852,3369,0,35}-{1,2851,3372,0,35}-" + "loc_data": "{1,3191,3276,0,35}-{1,3229,3299,0,35}-{1,3226,3301,0,35}-{1,3015,3295,0,30}-{1,3016,3295,0,30}-{1,2853,3370,0,35}-{1,2852,3369,0,35}-{1,2851,3372,0,35}-{1,2453,4476,0,1}-" }, { "item_id": "1955", diff --git a/Server/src/main/content/data/EnchantedJewellery.kt b/Server/src/main/content/data/EnchantedJewellery.kt index b21ab7e01..d5b300e93 100644 --- a/Server/src/main/content/data/EnchantedJewellery.kt +++ b/Server/src/main/content/data/EnchantedJewellery.kt @@ -2,8 +2,10 @@ package content.data import content.global.skill.magic.TeleportMethod import content.global.skill.slayer.SlayerManager.Companion.getInstance +import core.ServerConstants import core.api.* import core.game.event.TeleportEvent +import core.game.interaction.QueueStrength import core.game.node.entity.player.Player import core.game.node.entity.player.link.TeleportManager import core.game.node.item.Item @@ -18,7 +20,7 @@ import java.util.* /** * Represents an enchanted jewellery. - * @author Vexia & downthecrop + * @author Vexia, downthecrop, Player Name */ enum class EnchantedJewellery( @@ -186,6 +188,13 @@ enum class EnchantedJewellery( Items.RING_OF_WEALTH2_14642, Items.RING_OF_WEALTH1_14640, Items.RING_OF_WEALTH_14638 + ), + RING_OF_LIFE(arrayOf(), + arrayOf( + Location.create(ServerConstants.HOME_LOCATION) + ), + true, + Items.RING_OF_LIFE_2570 ); val isCrumble: Boolean = crumble @@ -199,7 +208,7 @@ enum class EnchantedJewellery( constructor(options: Array, locations: Array, vararg ids: Int) : this(options, locations, false, *ids) /** - * Method used to teleport the player to the desired location. + * Method used when the player "Use"s the jewellery piece. * @param player the player. * @param item the used jewellery item. * @param buttonID the button id. @@ -212,39 +221,52 @@ enum class EnchantedJewellery( } return } + attemptTeleport(player, item, buttonID, isEquipped) + } + + /** + * Method used to actually teleport the player to the desired location. + * @param player the player. + * @param item the used jewellery item. + * @param buttonID the button id. + * @param isEquipped If the player is operating. + */ + fun attemptTeleport(player: Player, item: Item, buttonID: Int, isEquipped: Boolean): Boolean { val itemIndex = getItemIndex(item) val nextJewellery = Item(getNext(itemIndex)) - if (canTeleport(player, nextJewellery)) { - Pulser.submit(object : Pulse(0) { - private var count = 0 - private var location = getLocation(buttonID) - override fun pulse(): Boolean { - when (count) { - 0 -> { - lock(player,4) - visualize(player, ANIMATION, GRAPHICS) - playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200) - player.impactHandler.disabledTicks = 4 - closeInterface(player) - } - 3 -> { - teleport(player,location) - resetAnimator(player) - if (isLastItemIndex(itemIndex)) { - if (isCrumble) crumbleJewellery(player, item, isEquipped) - } else { - replaceJewellery(player, item, nextJewellery, isEquipped) - } - unlock(player) - player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location)) - return true - } - } - count += 1 - return false - } - }) + if (!canTeleport(player, nextJewellery)) { + return false } + Pulser.submit(object : Pulse(0) { + private var count = 0 + private var location = getLocation(buttonID) + override fun pulse(): Boolean { + when (count) { + 0 -> { + lock(player,4) + visualize(player, ANIMATION, GRAPHICS) + playGlobalAudio(player.location, Sounds.TELEPORT_ALL_200) + player.impactHandler.disabledTicks = 4 + closeInterface(player) + } + 3 -> { + teleport(player,location) + resetAnimator(player) + if (isLastItemIndex(itemIndex)) { + if (isCrumble) crumbleJewellery(player, item, isEquipped) + } else { + replaceJewellery(player, item, nextJewellery, isEquipped) + } + unlock(player) + player.dispatch(TeleportEvent(TeleportManager.TeleportType.NORMAL, TeleportMethod.JEWELRY, item, location)) + return true + } + } + count += 1 + return false + } + }) + return true } private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) { @@ -262,8 +284,11 @@ enum class EnchantedJewellery( removeItem(player, item) } if (isSlayerRing(item)) { - addItem(player, Items.ENCHANTED_GEM_4155) - sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.") + queueScript(player, 1, QueueStrength.SOFT) { + addItemOrDrop(player, Items.ENCHANTED_GEM_4155) + sendMessage(player, "Your Ring of Slaying reverts back into a regular enchanted gem.") + return@queueScript stopExecuting(player) + } } } diff --git a/Server/src/main/content/global/handlers/item/EnchantedJewelleryListener.kt b/Server/src/main/content/global/handlers/item/EnchantedJewelleryListener.kt index 47947ec57..2878628ac 100644 --- a/Server/src/main/content/global/handlers/item/EnchantedJewelleryListener.kt +++ b/Server/src/main/content/global/handlers/item/EnchantedJewelleryListener.kt @@ -11,10 +11,11 @@ import content.data.EnchantedJewellery import core.game.interaction.InteractionListener import core.game.interaction.IntType import core.tools.START_DIALOGUE +import org.rs09.consts.Items /** * Listener for enchanted jewellery options - * @author Ceikry & downthecrop + * @author Ceikry, downthecrop, Player Name */ class EnchantedJewelleryListener : InteractionListener { @@ -33,6 +34,10 @@ class EnchantedJewelleryListener : InteractionListener { private fun handle(player: Player, node: Node, isEquipped: Boolean) { player.pulseManager.clear(PulseType.STANDARD) val item = node.asItem() + if (item.id == Items.RING_OF_LIFE_2570) { + sendMessage(player, "You can't operate that.") + return + } val jewellery = EnchantedJewellery.idMap[item.id] if (jewellery != null) { if (jewellery.isLastItemIndex(jewellery.getItemIndex(item)) && !jewellery.isCrumble) { @@ -60,4 +65,4 @@ class EnchantedJewelleryListener : InteractionListener { } } } -} \ No newline at end of file +} diff --git a/Server/src/main/content/global/skill/construction/decoration/questhall/MountedGlory.kt b/Server/src/main/content/global/skill/construction/decoration/questhall/MountedGlory.kt index 44c9750a9..4f7ddb15b 100644 --- a/Server/src/main/content/global/skill/construction/decoration/questhall/MountedGlory.kt +++ b/Server/src/main/content/global/skill/construction/decoration/questhall/MountedGlory.kt @@ -5,10 +5,12 @@ import core.api.teleport import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.node.entity.player.Player +import core.game.node.item.Item import core.game.system.task.Pulse import core.game.world.map.Location import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Graphics +import org.rs09.consts.Items import org.rs09.consts.Sounds import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -46,6 +48,9 @@ class MountedGlory : InteractionListener { } } private fun mountedGloryTeleport(player : Player, int : Int) { + if (!player.zoneMonitor.teleport(1, Item(Items.AMULET_OF_GLORY_1704))) { + return + } Executors.newSingleThreadScheduledExecutor().schedule({ player.pulseManager.run(object : Pulse() { var counter = 0 @@ -63,4 +68,4 @@ class MountedGlory : InteractionListener { }) }, 0, TimeUnit.SECONDS) } -} \ No newline at end of file +} diff --git a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt index 787e1fc5c..39f1378ec 100644 --- a/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt +++ b/Server/src/main/content/minigame/vinesweeper/Vinesweeper.kt @@ -60,9 +60,9 @@ class Vinesweeper : InteractionListener, InterfaceListener, MapArea { if(entity is Player) { entity.interfaceManager.closeOverlay() if(!logout) { - entity.sendMessage("Winkin's Farm thanks you for your visit.") - entity.sendMessage("Leftover ogleroots and flags have been returned to the establishment.") - entity.sendMessage("You have been reimbursed at a rate of 10gp per ogleroot and the flags have been collected.") + sendMessage(entity, "Winkin's Farm thanks you for your visit.") + sendMessage(entity, "Leftover ogleroots and flags have been returned to the establishment.") + sendMessage(entity, "You have been reimbursed at a rate of 10gp per ogleroot and the flags have been collected.") val flags = entity.inventory.getAmount(Item(Items.FLAG_12625)) if(flags > 0) { entity.setAttribute("/save:vinesweeper:stored-flags", flags) diff --git a/Server/src/main/content/region/misc/zanaris/handlers/EvilChickenLairListener.kt b/Server/src/main/content/region/misc/zanaris/handlers/EvilChickenLairListener.kt index a023e5b30..319fcb7ca 100644 --- a/Server/src/main/content/region/misc/zanaris/handlers/EvilChickenLairListener.kt +++ b/Server/src/main/content/region/misc/zanaris/handlers/EvilChickenLairListener.kt @@ -33,6 +33,10 @@ class EvilChickenLairListener: InteractionListener { } return@onUseWith true } + onUseWith(IntType.SCENERY, Items.EGG_1944, Scenery.CHICKEN_SHRINE_12093) { player, _, _ -> + sendMessage(player, "Nice idea, but nothing interesting happens.") + return@onUseWith true + } onUseWith(IntType.SCENERY, Items.ROPE_954, Scenery.TUNNEL_ENTRANCE_12253) { player, _, node -> if(removeItem(player, Item(Items.ROPE_954))) replaceScenery(node as core.game.node.scenery.Scenery, Scenery.TUNNEL_ENTRANCE_12254, 100) diff --git a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java index c63797294..6e0d0e6fb 100644 --- a/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java +++ b/Server/src/main/content/region/wilderness/handlers/revenants/RevenantNPC.java @@ -26,7 +26,7 @@ import static core.api.ContentAPIKt.playGlobalAudio; /** * Handles a revenant NPC. - * @author Ceikry-ish (mostly Vexia code still) + * @author Ceikry-ish (mostly Vexia code still), Player Name */ @Initializable public class RevenantNPC extends AbstractNPC { @@ -88,6 +88,7 @@ public class RevenantNPC extends AbstractNPC { configureBonuses(); super.configure(); this.swingHandler = new RevenantCombatHandler(getProperties().getAttackAnimation(), getProperties().getMagicAnimation(), getProperties().getRangeAnimation()); + setAttribute("food-items", 20); } @Override @@ -116,16 +117,23 @@ public class RevenantNPC extends AbstractNPC { public void tick() { skills.pulse(); getWalkingQueue().update(); - if (this.getViewport().getRegion().isActive()) + if (this.getViewport().getRegion().isActive()) { getUpdateMasks().prepare(this); - if (!DeathTask.isDead(this) && getSkills().getLifepoints() <= (getSkills().getStaticLevel(Skills.HITPOINTS) / 2) && getAttribute("eat-delay", 0) < GameWorld.getTicks()) { - lock(3); - getProperties().getCombatPulse().delayNextAttack(3); - getSkills().heal(10); - for (Player p : RegionManager.getLocalPlayers(this)) { - playAudio(p, Sounds.EAT_2393); + } + if (!DeathTask.isDead(this)) { + int curhp = getSkills().getLifepoints(); + int maxhp = getSkills().getStaticLevel(Skills.HITPOINTS); + int fooditems = getAttribute("food-items", 0); + if (curhp < maxhp / 2 && fooditems > 0 && getAttribute("eat-delay", 0) < GameWorld.getTicks()) { + lock(3); + getProperties().getCombatPulse().delayNextAttack(3); + getSkills().heal(maxhp / 6); + for (Player p : RegionManager.getLocalPlayers(this)) { + playAudio(p, Sounds.EAT_2393); + } + setAttribute("eat-delay", GameWorld.getTicks() + 6); + setAttribute("food-items", fooditems - 1); } - setAttribute("eat-delay", GameWorld.getTicks() + 6); } behavior.tick(this); if (aggressiveHandler != null && aggressiveHandler.selectTarget()) { @@ -196,9 +204,9 @@ public class RevenantNPC extends AbstractNPC { public boolean isAttackable(Entity entity, CombatStyle style, boolean message) { if (entity instanceof Player) { if (!hasAcceptableCombatLevel(entity.asPlayer()) && !entity.asPlayer().isAdmin()) { - if(message) { - entity.asPlayer().sendMessage("The level difference between you and your opponent is too great."); - } + if (message) { + entity.asPlayer().sendMessage("The level difference between you and your opponent is too great."); + } return false; } } diff --git a/Server/src/main/core/game/node/entity/combat/ImpactHandler.java b/Server/src/main/core/game/node/entity/combat/ImpactHandler.java index af9f3794c..648f30661 100644 --- a/Server/src/main/core/game/node/entity/combat/ImpactHandler.java +++ b/Server/src/main/core/game/node/entity/combat/ImpactHandler.java @@ -1,6 +1,6 @@ package core.game.node.entity.combat; -import core.ServerConstants; +import content.data.EnchantedJewellery; import core.game.container.impl.EquipmentContainer; import core.game.node.entity.skill.Skills; import content.global.skill.summoning.familiar.Familiar; @@ -14,6 +14,7 @@ import core.game.system.task.Pulse; import core.game.bots.AIPlayer; import core.game.world.GameWorld; import core.game.world.map.zone.ZoneType; +import org.rs09.consts.Items; import java.util.HashMap; import java.util.LinkedList; @@ -200,12 +201,13 @@ public final class ImpactHandler { impactQueue.add(impact); if (entity instanceof Player && !dead) { final Player p = entity.asPlayer(); - if (p.getZoneMonitor().getType() != ZoneType.SAFE.getId() && p.getSkullManager().getLevel() <= 30 && (p.getEquipment().contains(2570, 1))) { + if (p.getZoneMonitor().getType() != ZoneType.SAFE.getId() && (p.getEquipment().contains(Items.RING_OF_LIFE_2570, 1))) { int percentage = (int) (entity.getSkills().getStaticLevel(Skills.HITPOINTS) * 0.10); if (p.getSkills().getLifepoints() <= percentage) { - p.getEquipment().remove(new Item(2570)); - p.sendMessage("Your ring of life saves you and in the process is destroyed."); - p.teleport(ServerConstants.HOME_LOCATION); + Item rolItem = new Item(Items.RING_OF_LIFE_2570); + if (EnchantedJewellery.RING_OF_LIFE.attemptTeleport(p, rolItem, 0, true)) { + p.sendMessage("Your ring of life saves you and in the process is destroyed."); + } } } } diff --git a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt index 4189fb575..331ecdbb4 100644 --- a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt @@ -1,12 +1,12 @@ package core.game.system.command.sets import core.api.log +import core.api.sendMessage import core.cache.Cache import core.game.node.scenery.Scenery import core.game.node.scenery.SceneryBuilder import core.game.node.entity.npc.NPC import core.game.node.item.Item -import core.tools.SystemLogger import core.game.system.command.CommandPlugin import core.plugin.Initializable import core.game.system.command.Privilege @@ -22,19 +22,40 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ */ define("npc"){player,args -> if (args.size < 2) { - reject(player,"syntax error: id (optional) direction") + reject(player, "syntax: id (required) amount (optional) isWalks (optional)") return@define } - val npc = NPC.create(CommandPlugin.toInteger(args[1]!!), player!!.location) - npc.setAttribute("spawned:npc", true) - npc.isRespawn = false - npc.direction = player.direction - npc.init() - npc.isWalks = args.size > 2 - val npcString = "{" + npc.location.x + "," + npc.location.y + "," + npc.location.z + "," + (if (npc.isWalks) "1" else "0") + "," + npc.direction.ordinal + "}" + val amount = if (args.size > 2) CommandPlugin.toInteger(args[2]) else 1 + if (amount < 1) { + reject(player, "Invalid amount") + return@define + } + if (amount > 900) { + reject(player, "Based on experience, spawning that many NPCs at once is a bad idea") + return@define + } + var isWalks = false + if (args.size > 3) { + if (args[3] == "true") { + isWalks = true + } else if (args[3] != "" && args[3] != "false") { + reject(player, "The \"isWalks\" argument only accepts \"true\" and \"false\"") + return@define + } + } + var npcString = "" + for (i in 1..amount) { + val npc = NPC.create(CommandPlugin.toInteger(args[1]), player.location) + npc.setAttribute("spawned:npc", true) + npc.isRespawn = false + npc.direction = player.direction + npc.init() + npc.isWalks = isWalks + npcString = "{" + npc.location.x + "," + npc.location.y + "," + npc.location.z + "," + (if (npc.isWalks) "1" else "0") + "," + npc.direction.ordinal + "}" + println(npcString) + } val clpbrd = Toolkit.getDefaultToolkit().systemClipboard clpbrd.setContents(StringSelection(npcString), null) - println(npcString) } /** diff --git a/Server/src/main/core/game/system/timer/impl/SkillRestore.kt b/Server/src/main/core/game/system/timer/impl/SkillRestore.kt index 7f1a8bcac..b6b456618 100644 --- a/Server/src/main/core/game/system/timer/impl/SkillRestore.kt +++ b/Server/src/main/core/game/system/timer/impl/SkillRestore.kt @@ -19,7 +19,7 @@ class SkillRestore : RSTimer (1, "skillrestore", isAuto = true, isSoft = true) { var skills = entity.skills for (i in 0 until 24) { - if (i == Skills.PRAYER) continue + if (i == Skills.PRAYER || i == Skills.SUMMONING) continue if (ticksSinceLastRestore[i]++ >= restoreTicks[i]) { if (i == Skills.HITPOINTS && entity.skills.lifepoints < entity.skills.maximumLifepoints) { skills.heal (getHealAmount(entity)) diff --git a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java index c592b398c..472bbd8f0 100644 --- a/Server/src/main/core/game/world/map/zone/ZoneMonitor.java +++ b/Server/src/main/core/game/world/map/zone/ZoneMonitor.java @@ -24,12 +24,12 @@ import org.rs09.consts.Items; public final class ZoneMonitor { /** - * The set of dragonstone teleport jewellery, which allow teleporting from up to and including level 30 wildy. - * Used to check if a player can teleport from 20 < level <= 30 wildy, see canTeleportByDragonstoneJewellery. + * The set of jewellery which allow teleporting from up to and including level 30 wildy. + * Used to check if a player can teleport from 20 < level <= 30 wildy, see canTeleportByJewellery. * Note: the check is based on the nextJewellery (see EnchantedJewellery.kt), so this list should not contain the (4) items, and should contain the empty ones. * @author Player Name */ - static final Set DRAGONSTONE_TELEPORT_JEWELLERY = Set.of( + static final Set MID_WILDY_TELEPORT_JEWELLERY = Set.of( Items.AMULET_OF_GLORY_1704, Items.AMULET_OF_GLORY1_1706, Items.AMULET_OF_GLORY2_1708, @@ -49,7 +49,8 @@ public final class ZoneMonitor { Items.RING_OF_WEALTH_14638, Items.RING_OF_WEALTH1_14640, Items.RING_OF_WEALTH2_14642, - Items.RING_OF_WEALTH3_14644 + Items.RING_OF_WEALTH3_14644, + Items.RING_OF_LIFE_2570 ); /** @@ -235,7 +236,7 @@ public final class ZoneMonitor { * @return {@code True} if so. */ public boolean teleport(int type, Node node) { - if (type != -1 && entity.isTeleBlocked() && !canTeleportByDragonstoneJewellery(type, node)) { + if (type != -1 && entity.isTeleBlocked() && !canTeleportByJewellery(type, node)) { if (entity.isPlayer()) { entity.asPlayer().sendMessage("A magical force has stopped you from teleporting."); } @@ -250,11 +251,11 @@ public final class ZoneMonitor { } /** - * Checks if a player can teleport with a dragonstone jewellery piece in >= 1 <= 30 wilderness level + * Checks if a player can teleport with a jewellery piece in >= 1 <= 30 wilderness level * @return {@code True} if so. */ - private boolean canTeleportByDragonstoneJewellery(int type, Node node) { - if (type != 1 || !DRAGONSTONE_TELEPORT_JEWELLERY.contains(node.asItem().getId())) { + private boolean canTeleportByJewellery(int type, Node node) { + if (type != 1 || !MID_WILDY_TELEPORT_JEWELLERY.contains(node.asItem().getId())) { return false; } if (entity.timers.getTimer("teleblock") != null) diff --git a/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java b/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java index 6b1f27270..1eaf60bb1 100644 --- a/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/WildernessZone.java @@ -113,7 +113,7 @@ public final class WildernessZone extends MapZone { int normalGloveRate = isDeepWildy && isRevOrCele ? 100 : (int)((1.0/(1.0-Math.pow(1.0 - (1.0/(double)pvpGearRate), 16.0))) * 5.0 / 6.0); if (RandomFunction.roll(e.getId() == NPCs.CHAOS_ELEMENTAL_3200 ? cEleGloveRate : normalGloveRate)) { - byte glove = (byte) RandomFunction.random(1, 13); + byte glove = (byte) RandomFunction.random(1, 14); Item reward = new Item(BrawlingGloves.forIndicator(glove).getId()); GroundItemManager.create(reward, e.asNpc().getDropLocation(), killer.asPlayer()); Repository.sendNews(killer.getUsername() + " has received " + reward.getName().toLowerCase() + " from a " + e.asNpc().getName() + "!");