diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index c11106cb1..4be6a19b0 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -477,7 +477,7 @@ }, { "item_id": "1939", - "loc_data": "{1,3193,3181,0,150}-{1,3194,3168,0,150}-{1,3191,3162,0,150}-{1,3189,3163,0,150}-{1,3185,3161,0,150}-{1,3182,3165,0,150}-{1,3172,3166,0,150}-{1,3170,3167,0,150}-{1,3164,3169,0,150}-{1,3171,3177,0,150}-{1,3173,3178,0,150}-{1,3164,3180,0,150}-{1,3165,3187,0,150}-{1,3171,3191,0,150}-{1,3178,3190,0,150}-{1,3181,3193,0,150}-{1,3182,3181,0,150}-{1,3493,3408,0,30}-{1,3494,3402,0,30}-{1,3494,3396,0,30}-{1,3499,3401,0,30}-" + "loc_data": "{1,3193,3181,0,150}-{1,3194,3168,0,150}-{1,3191,3162,0,150}-{1,3189,3163,0,150}-{1,3185,3161,0,150}-{1,3182,3165,0,150}-{1,3172,3166,0,150}-{1,3170,3167,0,150}-{1,3164,3169,0,150}-{1,3171,3177,0,150}-{1,3173,3178,0,150}-{1,3164,3180,0,150}-{1,3165,3187,0,150}-{1,3171,3191,0,150}-{1,3178,3190,0,150}-{1,3181,3193,0,150}-{1,3182,3181,0,150}-{1,3428,3322,0,45}-{1,3436,3311,0,45}-{1,3437,3298,0,45}-{1,3428,3293,0,45}-{1,3422,3286,0,45}-{1,3451,3320,0,45}-{1,3434,3277,0,45}-{1,3446,3281,0,45}-{1,3447,3269,0,45}-{1,3450,3359,0,45}-{1,3451,3359,0,45}-{1,3452,3379,0,45}-{1,3452,3380,0,45}-{1,3438,3379,0,45}-{1,3440,3377,0,45}-{1,3414,3367,0,45}-{1,3409,3363,0,45}-{1,3452,3390,0,45}-{1,3452,3391,0,45}-{1,3466,3377,0,45}-{1,3460,3374,0,45}-{1,3459,3370,0,45}-{1,3469,3363,0,45}-{1,3476,3365,0,45}-{1,3460,3353,0,45}-{1,3462,3349,0,45}-{1,3472,3344,0,45}-{1,3493,3408,0,30}-{1,3494,3402,0,30}-{1,3494,3396,0,30}-{1,3499,3401,0,30}-{1,3464,3432,0,45}-{1,3469,3434,0,45}-{1,3473,3435,0,45}-{1,3471,3430,0,45}-{1,3478,3440,0,45}-{1,3477,3444,0,45}-{1,3472,3447,0,45}-{1,3458,3418,0,45}-{1,3460,3414,0,45}-{1,3467,3417,0,45}-{1,3472,3419,0,45}-{1,3474,3415,0,45}-{1,3480,3419,0,45}-{1,3481,3427,0,45}-{1,3460,3406,0,45}-{1,3471,3403,0,45}-{1,3428,3437,0,45}-{1,3434,3433,0,45}-{1,3435,3425,0,45}-{1,3441,3438,0,45}-{1,3445,3435,0,45}-{1,3449,3434,0,45}-{1,3448,3430,0,45}-{1,3454,3441,0,45}-{1,3441,3415,0,45}-{1,3442,3414,0,45}-{1,3436,3403,0,45}-{1,3432,3402,0,45}-{1,3450,3416,0,45}-{1,3445,3405,0,45}-{1,3453,3402,0,45}-" }, { "item_id": "1944", diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index fb9c4b564..8e1f93407 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -3389,7 +3389,7 @@ }, { "npc_id": "1227", - "loc_data": "{3424,3318,0,1,0}-{3423,3312,0,1,4}-{3494,3388,0,1,0}-{3507,3435,0,1,4}-{3511,3455,0,1,0}-{3508,3420,0,1,3}-{3508,3420,0,1,4}-{3506,3402,0,1,7}-{3502,3392,0,1,3}-{3484,3456,0,1,0}-{3486,3458,0,1,4}-" + "loc_data": "{3424,3318,0,1,0}-{3423,3312,0,1,4}-{3426,3381,0,1,0}-{3418,3375,0,1,0}-{3414,3363,0,1,0}-{3411,3358,0,1,0}-{3441,3356,0,1,0}-{3424,3426,0,1,0}-{3414,3413,0,1,0}-{3421,3408,0,1,0}-{3422,3408,0,1,0}-{3440,3406,0,1,0}-{3412,3392,0,1,0}-{3494,3388,0,1,0}-{3467,3346,0,1,0}-{3465,3347,0,1,0}-{3507,3435,0,1,4}-{3511,3455,0,1,0}-{3508,3420,0,1,3}-{3508,3420,0,1,4}-{3506,3402,0,1,7}-{3502,3392,0,1,3}-{3481,3446,0,1,0}-{3480,3445,0,1,0}-{3479,3443,0,1,0}-{3471,3433,0,1,0}-{3459,3432,0,1,0}-{3459,3426,0,1,0}-{3459,3418,0,1,0}-{3456,3415,0,1,0}-{3484,3456,0,1,0}-{3486,3458,0,1,4}-{3563,3441,0,1,0}-{3544,3430,0,1,0}-{3540,3413,0,1,0}-{3529,3441,0,1,0}-" }, { "npc_id": "1228", @@ -3397,11 +3397,11 @@ }, { "npc_id": "1229", - "loc_data": "{3421,3302,0,1,4}-{3417,3291,0,1,4}-{3423,3288,0,1,4}-{3418,3284,0,1,6}-{3427,3298,0,1,3}-{3431,3303,0,1,1}-{3432,3311,0,1,1}-{3502,3455,0,1,2}-{3516,3415,0,1,4}-{3511,3401,0,1,1}-{3492,3457,0,1,1}-" + "loc_data": "{3421,3302,0,1,4}-{3417,3291,0,1,4}-{3423,3288,0,1,4}-{3418,3284,0,1,6}-{3427,3298,0,1,3}-{3431,3303,0,1,1}-{3432,3311,0,1,1}-{3427,3376,0,1,0}-{3420,3407,0,1,0}-{3425,3403,0,1,0}-{3438,3399,0,1,0}-{3446,3406,0,1,0}-{3420,3426,0,1,0}-{3477,3368,0,1,0}-{3479,3367,0,1,0}-{3502,3455,0,1,2}-{3516,3415,0,1,4}-{3511,3401,0,1,1}-{3484,3443,0,1,0}-{3483,3442,0,1,0}-{3457,3416,0,1,0}-{3469,3402,0,1,0}-{3471,3401,0,1,0}-{3492,3457,0,1,1}-" }, { "npc_id": "1230", - "loc_data": "{3419,3280,0,1,4}-{3421,3277,0,1,4}-{3431,3275,0,1,3}-{3428,3314,0,1,1}-{3436,3318,0,1,5}-{3434,3322,0,1,6}-{3496,3447,0,1,7}-{3520,3437,0,1,4}-" + "loc_data": "{3419,3280,0,1,4}-{3421,3277,0,1,4}-{3431,3275,0,1,3}-{3428,3314,0,1,1}-{3436,3318,0,1,5}-{3434,3322,0,1,6}-{3476,3350,0,1,0}-{3496,3447,0,1,7}-{3481,3442,0,1,0}-{3520,3437,0,1,4}-" }, { "npc_id": "1231", @@ -3409,7 +3409,7 @@ }, { "npc_id": "1232", - "loc_data": "{3441,3265,0,1,5}-{3438,3277,0,1,7}-{3438,3283,0,1,4}-{3439,3315,0,1,3}-{3439,3310,0,1,1}-{3435,3302,0,1,3}-{3508,3420,0,1,1}-{3514,3415,0,1,7}-{3525,3417,0,1,3}-" + "loc_data": "{3441,3265,0,1,5}-{3438,3277,0,1,7}-{3438,3283,0,1,4}-{3439,3315,0,1,3}-{3439,3310,0,1,1}-{3435,3302,0,1,3}-{3411,3362,0,1,0}-{3415,3365,0,1,0}-{3415,3371,0,1,0}-{3413,3373,0,1,0}-{3431,3383,0,1,0}-{3508,3420,0,1,1}-{3514,3415,0,1,7}-{3470,3400,0,1,0}-{3464,3405,0,1,0}-{3474,3417,0,1,0}-{3474,3419,0,1,0}-{3477,3419,0,1,0}-{3480,3441,0,1,0}-{3525,3417,0,1,3}-" }, { "npc_id": "1233", @@ -3417,7 +3417,7 @@ }, { "npc_id": "1234", - "loc_data": "{3446,3282,0,1,1}-{3446,3298,0,1,3}-{3449,3304,0,1,1}-{3513,3383,0,1,0}-{3491,3388,0,1,3}-{3493,3454,0,1,2}-{3493,3454,0,1,0}-{3518,3454,0,1,2}-{3519,3441,0,1,7}-{3506,3417,0,1,5}-{3519,3401,0,1,2}-{3499,3420,0,1,3}-{3516,3410,0,1,7}-{3520,3412,0,1,0}-" + "loc_data": "{3446,3282,0,1,1}-{3446,3298,0,1,3}-{3449,3304,0,1,1}-{3409,3387,0,1,0}-{3424,3377,0,1,0}-{3438,3351,0,1,0}-{3513,3383,0,1,0}-{3491,3388,0,1,3}-{3461,3355,0,1,0}-{3473,3348,0,1,0}-{3477,3367,0,1,0}-{3493,3454,0,1,2}-{3493,3454,0,1,0}-{3518,3454,0,1,2}-{3519,3441,0,1,7}-{3506,3417,0,1,5}-{3519,3401,0,1,2}-{3499,3420,0,1,3}-{3516,3410,0,1,7}-{3483,3444,0,1,0}-{3479,3423,0,1,0}-{3466,3408,0,1,0}-{3466,3407,0,1,0}-{3520,3412,0,1,0}-" }, { "npc_id": "1235", diff --git a/Server/src/main/content/global/ame/KidnapHelper.kt b/Server/src/main/content/global/ame/KidnapHelper.kt index 716fb6277..39406108f 100644 --- a/Server/src/main/content/global/ame/KidnapHelper.kt +++ b/Server/src/main/content/global/ame/KidnapHelper.kt @@ -11,6 +11,7 @@ import core.game.world.update.flag.context.Graphics import org.rs09.consts.Sounds fun kidnapPlayer(npc: NPC, player: Player, dest: Location, playerLine: String? = null, callback: (player: Player, npc: NPC) -> Unit) { + clearScripts(player) val lockDuration = if (playerLine != null) 4 else 6 lock(player, lockDuration) queueScript(player, 1, QueueStrength.SOFT) { stage: Int -> diff --git a/Server/src/main/content/global/handlers/item/withnpc/CiderOnForester.kt b/Server/src/main/content/global/handlers/item/withnpc/CiderOnForester.kt index 31cb87218..ab0018b8d 100644 --- a/Server/src/main/content/global/handlers/item/withnpc/CiderOnForester.kt +++ b/Server/src/main/content/global/handlers/item/withnpc/CiderOnForester.kt @@ -43,7 +43,7 @@ class CiderOnForesterDialogue : DialogueFile() { end() } else if(player!!.getAttribute("seersCiderPub",-1) !in 0..3 && !player!!.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE,0,6)){ - player!!.setAttribute("seersCiderPub",0) + player!!.setAttribute("seersCiderPub", 1) end() }else if(player!!.getAttribute("seersCiderPub",-1) in 0..3){ player!!.incrementAttribute("seersCiderPub",1) diff --git a/Server/src/main/content/global/skill/crafting/SnelmCraftPlugin.java b/Server/src/main/content/global/skill/crafting/SnelmCraftPlugin.java index 1b1335c1c..f23d50b5f 100644 --- a/Server/src/main/content/global/skill/crafting/SnelmCraftPlugin.java +++ b/Server/src/main/content/global/skill/crafting/SnelmCraftPlugin.java @@ -20,7 +20,7 @@ public class SnelmCraftPlugin extends UseWithHandler { * The snelm data. */ private static final int[][] DATA = new int[][] { { 3345, 3327 }, { 3355, 3337 },// blamish - { 3349, 3341 }, { 3341, 3359 },// ochre + { 3349, 3331 }, { 3359, 3341 },// ochre { 3347, 3329 }, { 3357, 3339 },// blood { 3351, 3333 }, { 3361, 3343 },// blue { 3353, 3335 },// bark diff --git a/Server/src/main/content/global/skill/farming/LeprechaunNoter.kt b/Server/src/main/content/global/skill/farming/LeprechaunNoter.kt index 3a3d47bbf..8cf6eff81 100644 --- a/Server/src/main/content/global/skill/farming/LeprechaunNoter.kt +++ b/Server/src/main/content/global/skill/farming/LeprechaunNoter.kt @@ -12,26 +12,29 @@ class LeprechaunNoter : InteractionListener { val LEPRECHAUNS = intArrayOf(NPCs.TOOL_LEPRECHAUN_3021,NPCs.GOTH_LEPRECHAUN_8000,NPCs.TOOL_LEPRECHAUN_4965,NPCs.TECLYN_2861) override fun defineListeners() { - onUseWith(IntType.NPC,CROPS,*LEPRECHAUNS){ player, used, with -> + onUseAnyWith(IntType.NPC,*LEPRECHAUNS) { player, used, with -> val usedItem = used.asItem() val npc = with.asNpc() val expr = when(npc.id){ - 3021 -> core.game.dialogue.FacialExpression.OLD_NORMAL + NPCs.TOOL_LEPRECHAUN_3021 -> core.game.dialogue.FacialExpression.OLD_NORMAL else -> core.game.dialogue.FacialExpression.FRIENDLY } - - if(usedItem.noteChange != usedItem.id){ - val amt = player.inventory.getAmount(usedItem.id) - if(player.inventory.remove(Item(usedItem.id,amt))){ - player.inventory.add(Item(usedItem.noteChange,amt)) + when { + (!usedItem.definition.isUnnoted) -> { // If the item is a banknote + player.dialogueInterpreter.sendDialogues(npc.id,expr,"That IS a banknote!") + } + (usedItem.id !in CROPS || usedItem.definition.noteId < 0) -> { // If the item is not a crop or cannot be noted + player.dialogueInterpreter.sendDialogues(npc.id,expr,"Nay, I can't turn that into a banknote.") + } + else -> { // Note the item + val amt = amountInInventory(player, usedItem.id) + if (removeItem(player, Item(usedItem.id, amt))) { + addItem(player, usedItem.noteChange, amt) + } + sendItemDialogue(player, usedItem.id, "The leprechaun exchanges your items for banknotes.") } - sendItemDialogue(player,usedItem.id,"The leprechaun exchanges your items for banknotes.") - } else { - // Unsure why the line below no longer functions, despite only changing the line above to be more correct. Using your note(NOT CROP) on the leprechaun no longer functions because of this. - Crash - player.dialogueInterpreter.sendDialogues(npc.id,expr,"That IS a banknote!") } - - return@onUseWith true + return@onUseAnyWith true } } } \ No newline at end of file diff --git a/Server/src/main/content/global/skill/farming/Patch.kt b/Server/src/main/content/global/skill/farming/Patch.kt index eacc91bde..7e8070681 100644 --- a/Server/src/main/content/global/skill/farming/Patch.kt +++ b/Server/src/main/content/global/skill/farming/Patch.kt @@ -209,7 +209,15 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl PatchType.HERB_PATCH -> { if(isDead) setVisualState(getHerbDeathValue()) else if(isDiseased && !isDead) setVisualState(getHerbDiseaseValue()) - else setVisualState((plantable?.value ?: 0) + currentGrowthStage) + else { + var state = (plantable?.value ?: 0) + currentGrowthStage + // Spirit Weed contains states with bits 0x40 and 0x80 set, which the disease-free patch scenery interprets as watered/dead + // Visually transmogrifies Spirit Weed (204-208) into Guam (4-8) while it's planted in the disease-free patch + if (patch == FarmingPatch.TROLL_STRONGHOLD_HERB && plantable == Plantable.SPIRIT_WEED_SEED) { + state = 4 + currentGrowthStage + } + setVisualState(state) + } } PatchType.MUSHROOM_PATCH -> { if(isDead) setVisualState(getMushroomDeathValue()) diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt index 6b1be0ab0..28cfc2c86 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt @@ -50,7 +50,7 @@ class WoodcuttingListener : InteractionListener { defineInteraction( IntType.SCENERY, ids = WoodcuttingNode.values().map { it.id }.toIntArray(), - "chop-down", "chop", "chop down", "cut down", + "chop-down", "chop", "chop down", "cut down", "cut-branch", persistent = true, allowedDistance = 1, handler = ::handleWoodcutting @@ -74,10 +74,10 @@ class WoodcuttingListener : InteractionListener { if (clockReady(player, Clocks.SKILLING)) { animateWoodcutting(player) - if (resource == WoodcuttingNode.DRAMEN_TREE) { + if (resource in arrayOf(WoodcuttingNode.DRAMEN_TREE, WoodcuttingNode.SWAYING_TREE)) { // Reward after one chop and then abort chopping (this is authentic) queueScript(player, 1, QueueStrength.STRONG) { - sendMessage(player, "You cut a branch from the Dramen tree.") + sendMessage(player, "You cut a branch from the ${if (resource == WoodcuttingNode.DRAMEN_TREE) "Dramen" else "strangely musical"} tree.") addItem(player, resource.getReward()) return@queueScript clearScripts(player) } diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.java b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.java deleted file mode 100644 index 98721c62f..000000000 --- a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.java +++ /dev/null @@ -1,81 +0,0 @@ -package content.global.skill.summoning.familiar; - -import core.game.dialogue.DialoguePlugin; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.TeleportManager.TeleportType; -import core.game.world.map.Location; -import core.plugin.Initializable; -import core.game.world.map.zone.impl.WildernessZone; - -/** - * Represents the spirit graahk's dialogue - * @author Splinter - * @version 1.0 - */ -@Initializable -public final class SpiritGraahkDialogue extends DialoguePlugin { - - /** - * Constructs a new {@code GertrudesCatDialogue} {@code Object}. - */ - public SpiritGraahkDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code GertrudesCatDialogue} {@code Object}. - * @param player the player. - */ - public SpiritGraahkDialogue(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new SpiritGraahkDialogue(player); - } - - @Override - public boolean open(Object... args) { - npc = (NPC) args[0]; - if (!(npc instanceof Familiar)) { - return false; - } - final Familiar fam = (Familiar) npc; - if (fam.getOwner() != player) { - player.getPacketDispatch().sendMessage("This is not your familiar."); - return true; - } else { - interpreter.sendOptions("Select an Option", "Chat", "Teleport"); - } - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (buttonId) { - case 1: - player.sendMessage("The Graahk does not feel like talking now."); - end(); - break; - case 2: - if (!WildernessZone.checkTeleport(player, 20)) { - player.sendMessage("You cannot teleport with the Graahk above level 20 wilderness."); - end(); - } else { - player.getTeleporter().send(new Location(2786, 3002), TeleportType.NORMAL); - end(); - } - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[] { 7353, 7364 }; - } -} diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.kt b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.kt new file mode 100644 index 000000000..4a0c23c9e --- /dev/null +++ b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkDialogue.kt @@ -0,0 +1,115 @@ +package content.global.skill.summoning.familiar + +import core.api.openDialogue +import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialoguePlugin +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.TeleportManager.TeleportType +import core.game.node.entity.skill.Skills +import core.game.world.map.Location +import core.game.world.map.zone.impl.WildernessZone +import core.plugin.Initializable +import core.tools.RandomFunction +import org.rs09.consts.NPCs + +/** + * Represents the spirit graahk's dialogue + * @author Splinter & Bishop + * @version 2.0 + */ +@Initializable +class SpiritGraahkDialogue : DialoguePlugin { + constructor() + constructor(player: Player?) : super(player) + + override fun newInstance(player: Player?): DialoguePlugin { + return SpiritGraahkDialogue(player) + } + + override fun open(vararg args: Any?): Boolean { + npc = args[0] as NPC? + if (npc !is Familiar) { + return false + } + val fam = npc as Familiar + if (fam.getOwner() !== player) { + player.packetDispatch.sendMessage("This is not your familiar.") + return true + } else { + interpreter.sendOptions("Select an Option", "Chat", "Teleport") + } + return true + } + + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + when (buttonId) { + 1 -> if (player.skills.getStaticLevel(Skills.SUMMONING) >= 67) { + openDialogue(player, SpiritGraahkDialogueFile(), npc) + } else { + player.sendMessage("The Graahk does not feel like talking now.") //This message is likely inauthentic, but I cannot source the correct one so I'm keeping the default here -Bishop + end() + } + + 2 -> if (!WildernessZone.checkTeleport(player, 20)) { + player.sendMessage("You cannot teleport with the Graahk above level 20 wilderness.") + end() + } else { + player.teleporter.send(Location(2786, 3002), TeleportType.NORMAL) + end() + } + } + return true + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.SPIRIT_GRAAHK_7363, NPCs.SPIRIT_GRAAHK_7364) + } +} + +class SpiritGraahkDialogueFile : DialogueLabeller() { + override fun addConversation() { + exec { player, npc -> + val spiritGraahkRandomConversation = RandomFunction.random(4) + when (spiritGraahkRandomConversation) { + 0 -> loadLabel(player, "spiky spikes") + 1 -> loadLabel(player, "pet the spikes") + 2 -> loadLabel(player, "therapeutic spikes") + 3 -> loadLabel(player, "inspect the spikes") + } + } + + label("spiky spikes") + player(ChatAnim.NEUTRAL, "Your spikes are looking particularly spiky today.") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Graaaaahk raaaawr?", "(Really, you think so?)") + player(ChatAnim.HAPPY, "Yes. Most pointy, indeed.") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Raaaawr...", "(That's really kind of you to say. I was going to spike", "you but I won't now...)") + player(ChatAnim.HAPPY, "Thanks?") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "...Grrrrr ark.", "(...I'll do it later instead.)") + player(ChatAnim.HAPPY, "*Sigh!*") + + label("pet the spikes") + npc(ChatAnim.GHRAAK_SHAKE_MILD, "Graahk grrrrowl?", "(My spikes hurt, could you pet them for me?)") + player(ChatAnim.HAPPY, "Aww, of course I can I'll just... Oww! I think you drew", "blood that time.") + + label("therapeutic spikes") + npc(ChatAnim.GHRAAK_SHAKE_MILD, "Graahk!", "(Hi!)") //? + player(ChatAnim.SUSPICIOUS, "Hello. Are you going to spike me again?") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Grar rawr howl!", "(No, I got a present to apologise for last time.)") + player(ChatAnim.HAPPY, "That's really sweet, thank you.") + npc(ChatAnim.GRAAHK_NOD, "Howl graaahk rawr.", "(Here you go, it's a special cushion to make you", "comfortable.)") + player(ChatAnim.ANGRY, "It's made of spikes!") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Howl graaahk rawr.", "(Yes, but they're therapeutic spikes.)") + player(ChatAnim.ANGRY, "...") + + label("inspect the spikes") + player(ChatAnim.HAPPY, "How's your day going?") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Graaahk. Grak grak!", "(It's great! Actually I've got something to show you!)") + player(ChatAnim.HALF_ASKING, "Oh? What's that?") + npc(ChatAnim.GRAAHK_NOD, "Grrrrrk hiss graaaaa!", "(You'll need to get closer!)") + player(ChatAnim.HALF_ASKING, "I can't see anything...") + npc(ChatAnim.GHRAAK_SHAKE_VIGOROUS, "Grah grr aaaaahk grahk.", "(It's really small - even closer.)") + player(ChatAnim.ANGRY, "Oww! I'm going to have your spikes trimmed!") + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.java b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.java deleted file mode 100644 index dd6b48975..000000000 --- a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.java +++ /dev/null @@ -1,52 +0,0 @@ -package content.global.skill.summoning.familiar; - -import core.game.node.entity.skill.SkillBonus; -import core.game.node.entity.skill.Skills; -import core.game.node.entity.combat.equipment.WeaponInterface; -import core.plugin.Initializable; -import core.game.node.entity.player.Player; - -/** - * Represents the Spirit Graahk familiar. - * @author Aero - */ -@Initializable -public class SpiritGraahkNPC extends Familiar { - - /** - * Constructs a new {@code SpiritGraahkNPC} {@code Object}. - */ - public SpiritGraahkNPC() { - this(null, 7363); - } - - /** - * Constructs a new {@code SpiritGraahkNPC} {@code Object}. - * @param owner The owner. - * @param id The id. - */ - public SpiritGraahkNPC(Player owner, int id) { - super(owner, id, 4900, 12810, 3, WeaponInterface.STYLE_AGGRESSIVE); - boosts.add(new SkillBonus(Skills.HUNTER, 5)); - } - - @Override - public Familiar construct(Player owner, int id) { - return new SpiritGraahkNPC(owner, id); - } - - @Override - protected boolean specialMove(FamiliarSpecial special) { - if (!super.isOwnerAttackable()) { - return false; - } - call(); - return true; - } - - @Override - public int[] getIds() { - return new int[] { 7363, 7364 }; - } - -} diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.kt b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.kt new file mode 100644 index 000000000..af84870d7 --- /dev/null +++ b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkNPC.kt @@ -0,0 +1,51 @@ +package content.global.skill.summoning.familiar + +import core.game.node.entity.Entity +import core.game.node.entity.combat.equipment.WeaponInterface +import core.game.node.entity.player.Player +import core.game.node.entity.skill.SkillBonus +import core.game.node.entity.skill.Skills +import core.game.world.update.flag.context.Animation +import core.game.world.update.flag.context.Graphics +import core.plugin.Initializable +import core.tools.RandomFunction +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +/** + * Represents the Spirit Graahk familiar. + * @author Aero & Bishop + */ +@Initializable +class SpiritGraahkNPC @JvmOverloads constructor(owner: Player? = null, id: Int = NPCs.SPIRIT_GRAAHK_7363) : + Familiar(owner, id, 4900, Items.SPIRIT_GRAAHK_POUCH_12810, 3, WeaponInterface.STYLE_AGGRESSIVE) { + + init { + boosts.add(SkillBonus(Skills.HUNTER, 5.0)) + } + + override fun construct(owner: Player?, id: Int): Familiar { + return SpiritGraahkNPC(owner, id) + } + + override fun specialMove(special: FamiliarSpecial): Boolean { + val target: Entity = special.target ?: return false + if (!canCombatSpecial(target)) { + return false + } + properties.combatPulse.attack(target) + return true + } + + override fun visualizeSpecialMove() { + owner.visualize(Animation.create(7660), Graphics.create(1316)) + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.SPIRIT_GRAAHK_7363, NPCs.SPIRIT_GRAAHK_7364) + } + + override fun getText(): String { + return if (RandomFunction.random(2) == 0) "Howl!" else "Rowr!" + } +} diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.java b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.java deleted file mode 100644 index 44c4678a9..000000000 --- a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.java +++ /dev/null @@ -1,29 +0,0 @@ -package content.global.skill.summoning.familiar; - -import core.cache.def.impl.NPCDefinition; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -import core.game.node.entity.player.Player; -import core.plugin.Initializable; -import core.plugin.Plugin; - -/** - * Represents the plugin used to handle the spirit graahk familiar - * @author Splinter - */ -@Initializable -public final class SpiritGraahkOptionPlugin extends OptionHandler { - - @Override - public Plugin newInstance(Object arg) throws Throwable { - NPCDefinition.forId(7363).getHandlers().put("option:interact", this); - return this; - } - - @Override - public boolean handle(final Player player, Node node, String option) { - player.getDialogueInterpreter().open(7353, node.asNpc()); - return true; - } - -} diff --git a/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.kt b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.kt new file mode 100644 index 000000000..d3b3b1e97 --- /dev/null +++ b/Server/src/main/content/global/skill/summoning/familiar/SpiritGraahkOptionPlugin.kt @@ -0,0 +1,27 @@ +package content.global.skill.summoning.familiar + +import core.cache.def.impl.NPCDefinition +import core.game.interaction.OptionHandler +import core.game.node.Node +import core.game.node.entity.player.Player +import core.plugin.Initializable +import core.plugin.Plugin +import org.rs09.consts.NPCs; + +/** + * Represents the plugin used to handle the spirit graahk familiar + * @author Splinter + */ +@Initializable +class SpiritGraahkOptionPlugin : OptionHandler() { + @Throws(Throwable::class) + override fun newInstance(arg: Any?): Plugin { + NPCDefinition.forId(NPCs.SPIRIT_GRAAHK_7363).getHandlers()["option:interact"] = this + return this + } + + override fun handle(player: Player, node: Node, option: String?): Boolean { + player.dialogueInterpreter.open(NPCs.SPIRIT_GRAAHK_7364, node.asNpc()) + return true + } +} diff --git a/Server/src/main/content/region/desert/quest/deserttreasure/DiamondOfIceListeners.kt b/Server/src/main/content/region/desert/quest/deserttreasure/DiamondOfIceListeners.kt index 9ee2c5ba9..c6a8de304 100644 --- a/Server/src/main/content/region/desert/quest/deserttreasure/DiamondOfIceListeners.kt +++ b/Server/src/main/content/region/desert/quest/deserttreasure/DiamondOfIceListeners.kt @@ -84,7 +84,7 @@ class DiamondOfIceListeners : InteractionListener { on(Scenery.ICE_LEDGE_6455, SCENERY, "use") { player, node -> if ((getQuestStage(player, DesertTreasure.questName) == 9 && - DesertTreasure.getSubStage(player, DesertTreasure.attributeIceStage) >= 3) || + DesertTreasure.getSubStage(player, DesertTreasure.attributeIceStage) >= 3) || getQuestStage(player, DesertTreasure.questName) >= 10) { if (inEquipment(player, Items.SPIKED_BOOTS_3107)) { teleport(player, Location(2838, 3803, 1)) diff --git a/Server/src/main/content/region/desert/quest/deserttreasure/KamilBehavior.kt b/Server/src/main/content/region/desert/quest/deserttreasure/KamilBehavior.kt index c5de39024..f52c0d414 100644 --- a/Server/src/main/content/region/desert/quest/deserttreasure/KamilBehavior.kt +++ b/Server/src/main/content/region/desert/quest/deserttreasure/KamilBehavior.kt @@ -67,8 +67,8 @@ class KamilCombatHandler: MultiSwingHandler( // I can't be bothered to fix fucking frozen. The player can hit through frozen. What the fuck is frozen for then, to glue his fucking legs??? if (RandomFunction.roll(3) && !hasTimerActive(victim, "frozen") && !hasTimerActive(victim, "frozen:immunity")) { sendChat(entity as NPC, "Sallamakar Ro!") // Salad maker roll. - impact(victim, 5) - impact(victim, 5) + impact(victim, if (victim.hasProtectionPrayer(CombatStyle.MAGIC)) 0 else 5) + impact(victim, if (victim.hasProtectionPrayer(CombatStyle.RANGE)) 0 else 5) registerTimer(victim, spawnTimer("frozen", 7, true)) sendMessage(victim, "You've been frozen!") // FIXME: before the below vfx hits, there should be another one that looks kinda like a wind wave exploding at the player's feet. Hope somebody finds the id. diff --git a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt index db98b2314..e7b48f9d3 100644 --- a/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt +++ b/Server/src/main/content/region/fremennik/rellekka/quest/thefremenniktrials/TFTInteractionListeners.kt @@ -260,11 +260,6 @@ class TFTInteractionListeners : InteractionListener { return@on true } - on(SWAYING_TREE, IntType.SCENERY, "cut-branch"){ player, node -> - player.pulseManager.run(WoodcuttingSkillPulse(player, node as Scenery)) - return@on true - } - on(SHOPNPCS, IntType.NPC, "Trade") { player, npc -> if(isQuestComplete(player, Quests.THE_FREMENNIK_TRIALS)){ npc.asNpc().openShop(player) diff --git a/Server/src/main/content/region/wilderness/handlers/WildernessAreaZone.java b/Server/src/main/content/region/wilderness/handlers/WildernessAreaZone.java deleted file mode 100644 index acf3727c6..000000000 --- a/Server/src/main/content/region/wilderness/handlers/WildernessAreaZone.java +++ /dev/null @@ -1,575 +0,0 @@ -package content.region.wilderness.handlers; - -import core.game.dialogue.DialogueAction; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.global.action.DoorActionHandler; -import core.game.node.entity.skill.SkillPulse; -import core.game.node.entity.skill.Skills; -import content.global.skill.gather.SkillingResource; -import content.data.skill.SkillingTool; -import core.game.interaction.NodeUsageEvent; -import core.game.interaction.Option; -import core.game.interaction.UseWithHandler; -import core.game.node.Node; -import core.game.node.entity.Entity; -import core.game.node.entity.combat.BattleState; -import core.game.node.entity.npc.AbstractNPC; -import core.game.node.entity.npc.NPC; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.world.GameWorld; -import core.game.world.map.Location; -import core.game.world.map.zone.MapZone; -import core.game.world.map.zone.ZoneBorders; -import core.game.world.map.zone.ZoneBuilder; -import core.plugin.Initializable; -import core.plugin.Plugin; -import core.plugin.ClassScanner; - -import java.util.ArrayList; -import java.util.List; - -/** - * Handles the Wilderness Area Zone. - * @author Empathy - * @author Vexia - * - */ -@Initializable -public class WildernessAreaZone extends MapZone implements Plugin { - - /** - * The list of players in the arena. - */ - private final List players = new ArrayList<>(20); - - /** - * Constructs a new {@code WildernessAreaZone} {@code Object} - */ - public WildernessAreaZone() { - super("Wilderness Area Zone", true); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ZoneBuilder.configure(this); - ClassScanner.definePlugins(new MandrithDialoguePlugin(), new PilesDialoguePlugin(), new PilesItemHandler(), new RuniteGolemNPC()); - return this; - } - - @Override - public boolean interact(Entity e, final Node node, Option option) { - if (e instanceof Player) { - Player player = e.asPlayer(); - switch (node.getId()) { - case 42044: - switch (option.getName()) { - case "Open": - if (player.getLocation().equals(Location.create(3184, 3945, 0))) { - if (player.getInventory().contains(995, 7500)) { - player.getDialogueInterpreter().sendOptions("Pay 7500 coins?", "Yes", "No"); - player.getDialogueInterpreter().addAction(new DialogueAction() { - - @Override - public void handle(Player player, int buttonId) { - switch (buttonId) { - case 2: - if (player.getInventory().remove(new Item(995, 7500))) { - DoorActionHandler.handleDoor(player, node.asScenery()); - player.sendMessage("You pay 7500 coins and enter the resource arena."); - } - break; - } - } - - }); - return true; - } - player.sendMessage("You do not have enough coins to enter the Arena."); - return true; - } - DoorActionHandler.handleDoor(player, node.asScenery()); - return true; - case "Players-inside": - if (player.getLocation().getY() < 3495) { - player.sendMessage("All you see is the barren wasteland of the Wilderness."); - return true; - } - String message = "You peek inside the gate and see no adventurers inside the arena."; - if (players.size() > 0) { - message = players.size() == 1 ? "You peek inside the gate and see 1 adventurer inside the arena." : "You peek inside the gate and see " + players.size() + " inside the arena."; - } - player.getDialogueInterpreter().sendDialogue(message); - break; - } - break; - case 8666: - switch (option.getName()) { - case "Mine": - player.getPulseManager().run(new RuniteGolemMinePulse(player, node.asNpc())); - return true; - case "Prospect": - player.sendMessages("You examine the rock for ores...", "This rock contains runite ore."); - return true; - } - break; - } - } - return super.interact(e, node, option); - } - - @Override - public Object fireEvent(String identifier, Object... args) { - return null; - } - - @Override - public void configure() { - register(new ZoneBorders(3174, 3924, 3196, 3945)); - } - - @Override - public boolean enter(Entity e) { - if (e instanceof Player) { - Player p = e.asPlayer(); - players.add(p); - } - return super.enter(e); - } - - @SuppressWarnings("deprecation") - @Override - public boolean leave(Entity e, boolean logout) { - if (e instanceof Player) { - Player p = e.asPlayer(); - players.remove(p); - if (logout && p.getLocation().getY() <= 3944) { - p.setLocation(Location.create(3184, 3945, 0)); - return true; - } - } - return super.leave(e, logout); - } - - /** - * The mining of a runite golem. - * @author Vexia - * - */ - public class RuniteGolemMinePulse extends SkillPulse { - - /** - * The skilling tool used. - */ - private SkillingTool tool; - - /** - * The ticks. - */ - private int ticks; - - /** - * Constructs a new @{Code RuniteGolemMinePulse} object. - * @param player The player. - * @param node The node. - */ - public RuniteGolemMinePulse(Player player, NPC node) { - super(player, node); - } - - @Override - public void start() { - resource = SkillingResource.RUNITE_ORE_0; - if (node.getId() != 8666) { - player.getPacketDispatch().sendMessage("This rock contains no ore."); - return; - } - if (resource == null) { - return; - } - super.start(); - } - - - @Override - public boolean checkRequirements() { - if (node.getId() != 8666) { - return false; - } - if (player.getSkills().getLevel(resource.getSkillId()) < resource.getLevel()) { - player.getPacketDispatch().sendMessage("You need a " + Skills.SKILL_NAME[resource.getSkillId()] + " level of " + resource.getLevel() + " to mine this rock."); - return false; - } - if ((tool = SkillingTool.getPickaxe(player)) == null) { - player.getPacketDispatch().sendMessage("You do not have a pickaxe to use."); - return false; - } - if (player.getInventory().freeSlots() < 1) { - player.getDialogueInterpreter().sendDialogue("Your inventory is too full to hold any more runite ore."); - return false; - } - return true; - } - - @Override - public void animate() { - if (tool != null) { - player.animate(tool.getAnimation()); - } - } - - @Override - public boolean reward() { - if (++ticks % 4 != 0) { - return false; - } - if (!checkReward()) { - return false; - } - node.transform(8667); - node.setAttribute("reward-tick", GameWorld.getTicks() + resource.getRespawnDuration()); - final Item item = new Item(resource.getReward()); - player.getInventory().add(item); - player.getSkills().addExperience(resource.getSkillId(), resource.getExperience(), true); - return true; - } - - /** - * Checks if the player gets rewarded. - * @return {@code True} if so. - */ - private boolean checkReward() { - int skill = Skills.MINING; - int level = 1 + player.getSkills().getLevel(skill) + player.getFamiliarManager().getBoost(skill); - double hostRatio = Math.random() * (100.0 * resource.getRate()); - double clientRatio = Math.random() * ((level - resource.getLevel()) * (1.0 + tool.getRatio())); - return hostRatio < clientRatio; - } - } - - /** - * Handles the runite golem npc. - * @author Vexia - * - */ - public class RuniteGolemNPC extends AbstractNPC { - - /** - * The respawn time. - */ - private int respawn = -1; - - /** - * Constructs a new @{Code RuniteGolemNPC} object. - * @param id The npc id. - * @param location The location. - */ - public RuniteGolemNPC(int id, Location location) { - super(id, location); - } - - /** - * Constructs a new @{Code RuniteGolemNPC} object. - */ - public RuniteGolemNPC() { - super(-1, null); - } - - @Override - public AbstractNPC construct(int id, Location location, Object... objects) { - return new RuniteGolemNPC(id, location); - } - - @Override - public void init() { - super.init(); - setAggressive(false); - } - - @Override - public void sendImpact(BattleState state) { - super.sendImpact(state); - if (state.getEstimatedHit() > 16) { - state.setEstimatedHit(16); - } - } - - @Override - public void handleTickActions() { - super.handleTickActions(); - if (isAggressive()) { - setAggressive(false); - } - if (respawn != -1 && respawn < GameWorld.getTicks() && getId() > 8664) { - transform(8664); - unlock(); - } - if (getId() == 8667) { - int rewardTick = getAttribute("reward-tick", -1); - if (rewardTick != -1 && rewardTick < GameWorld.getTicks()) { - transform(8666); - } - } - } - - @Override - public void finalizeDeath(Entity killer) { - respawn = GameWorld.getTicks() + 500; - fullRestore(); - getProperties().setTeleportLocation(getLocation()); - setRespawnTick(0); - setInvisible(false); - transform(8666); - lock(); - faceLocation(null); - face(null); - } - - @Override - public int[] getIds() { - return new int[] {8664}; - } - - - } - - /** - * Handles the item on piles interaction. - * @author Vexia - * - */ - public static class PilesItemHandler extends UseWithHandler { - - /** - * The allowed items for piles. - */ - private static final int[] ALLOWED = new int[] {14937, 14939, 449, 447, 440, 444, 453, 451, 1515, 1513, 2349, 9467,2351,2355,2353,2357,2359,2361,2363}; - - /** - * Constructs a new @{Code PilesItemHandler} object. - */ - public PilesItemHandler() { - super(); - } - - @Override - public Plugin newInstance(Object arg) throws Throwable { - addHandler(8663, NPC_TYPE, this); - return this; - } - - @Override - public boolean handle(final NodeUsageEvent event) { - final Player player = event.getPlayer(); - for (int itemId : ALLOWED) { - if (event.getUsedItem().getId() == itemId) { - final int amount = player.getInventory().getAmount(itemId); - final int price = 50 * amount; - if (!player.getInventory().contains(995, price)) { - player.getDialogueInterpreter().sendDialogues(8663, FacialExpression.OLD_NORMAL, "I'll need 50 coins per item."); - return true; - } - player.getDialogueInterpreter().sendOptions("Banknote " + amount + " x " + event.getUsedItem().getName() + "?", "Yes - " + price + " gp", "Cancel"); - player.getDialogueInterpreter().addAction((player1, buttonId) -> { - if (player1.getInventory().remove(new Item(995, price)) && player1.getInventory().remove(new Item(event.getUsedItem().getId(), amount))) { - player1.getInventory().add(new Item(event.getUsedItem().getNoteChange(), amount)); - player1.getDialogueInterpreter().sendItemMessage(event.getUsedItem().getId(), "Piles converts your items to banknotes."); - } - }); - return true; - } - } - player.getDialogueInterpreter().sendDialogues(8663, FacialExpression.OLD_NORMAL, "Sorry, I wasn't expecting anyone to want to convert", "that sort of item, so I haven't any banknotes for it."); - return true; - } - - @Override - public boolean isDynamic() { - return true; - } - } - - /** - * Handles the Piles dialogue. - * @author Vexia - * - */ - public class PilesDialoguePlugin extends DialoguePlugin { - - /** - * Constructs a new @{Code PilesDialoguePlugin} object. - */ - public PilesDialoguePlugin() { - /* - * empty. - */ - } - - /** - * Constructs a new @{Code PilesDialoguePlugin} object. - * @param player The player. - */ - public PilesDialoguePlugin(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new PilesDialoguePlugin(player); - } - - @Override - public boolean open(Object... args) { - npc("Hello. I can convert items to banknotes, for 50 coins", "per item. Just hand me the items you'd like me to", "convert."); - stage = 0; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 0: - options("Who are you?", "Thanks."); - stage++; - break; - case 1: - switch (buttonId) { - case 1: - player("Who are you?"); - stage = 10; - break; - case 2: - player("Thanks."); - stage = 2; - break; - } - break; - case 2: - end(); - break; - case 10: - npc("I'm Piles. I lived in Draynor Village when I was", "young, where I saw three men working in the market,", "converting items to banknotes."); - stage++; - break; - case 11: - npc("Their names were Niles, Miles and Giles. I'm trying to", "be like them, so I've changed my name and started this", "business here."); - stage++; - break; - case 12: - player("Thanks."); - stage = 2; - break; - } - return true; - } - - @Override - public int[] getIds() { - return new int[] {8663}; - } - - } - - /** - * Handles the Mandrith dialogue. - * @author Empathy - * - */ - public class MandrithDialoguePlugin extends DialoguePlugin { - - /** - * - * Constructs a new @{Code MandrithDialoguePlugin} object. - */ - public MandrithDialoguePlugin() { - /* - * empty - */ - } - - /** - * - * Constructs a new @{Code MandrithDialoguePlugin} object. - * @param player - */ - public MandrithDialoguePlugin(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new MandrithDialoguePlugin(player); - } - - @Override - public boolean open(Object... args) { - player("Who are you and what is this place?" ); - stage = 1; - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 1: - npc("My name is Mandrith." ); - stage = 2; - break; - case 2: - npc("I collect valuable resources and pawn off access to them", "to foolish adventurers, like yourself" ); - stage = 3; - break; - case 3: - npc("You should take a look inside my arena. There's an", "abundance of valuable resources inside." ); - stage = 4; - break; - case 4: - player("And I can take whatever I want?" ); - stage = 5; - break; - case 5: - npc("It's all yours. All I ask is that you pay the upfront fee." ); - stage = 6; - break; - case 6: - player("Will others be able to kill me inside?" ); - stage = 7; - break; - case 7: - npc("Yes. These walls will only hold them back for so long." ); - stage = 8; - break; - case 8: - player("You'll stop them though, right?" ); - stage = 9; - break; - case 9: - npc("Haha! For the right price, I won't deny anyone access", "to my arena. Even if their intention is to kill you." ); - stage = 10; - break; - case 10: - player("Right..." ); - stage = 11; - break; - case 11: - npc("My arena holds many treasure that I've acquired at", "great expense, adventurer. Their bounty can come at a", "price." ); - stage = 12; - break; - case 12: - npc("One day, adventurer, I will boast ownership of a much", "larger, much more dangerous arena than this. Take", "advantage of this offer while it lasts." ); - stage = 13; - break; - case 13: - end(); - break; - } - return false; - } - - @Override - public int[] getIds() { - return new int[] { 8662 }; - } - } -} diff --git a/Server/src/main/core/game/container/impl/EquipmentContainer.java b/Server/src/main/core/game/container/impl/EquipmentContainer.java index 8e01c91cc..d398d9f3b 100644 --- a/Server/src/main/core/game/container/impl/EquipmentContainer.java +++ b/Server/src/main/core/game/container/impl/EquipmentContainer.java @@ -212,7 +212,7 @@ public final class EquipmentContainer extends Container { for(Item currentItem : currentItems) { Plugin plugin = currentItem.getDefinition().getConfiguration("equipment", null); if (plugin != null) { - Object object = plugin.fireEvent("unequip", player, currentItem, newItem); + Object object = plugin.fireEvent("unequip", player, currentItem); if (object != null && !((Boolean) object)) { canContinue = false; break; diff --git a/Server/src/main/core/game/dialogue/FacialExpression.java b/Server/src/main/core/game/dialogue/FacialExpression.java index 6d415cf0f..8b4f2eb8c 100644 --- a/Server/src/main/core/game/dialogue/FacialExpression.java +++ b/Server/src/main/core/game/dialogue/FacialExpression.java @@ -104,13 +104,19 @@ public enum FacialExpression { CHILD_SUSPICIOUS(7179), CHILD_SURPRISED(7180), + //Familiar Chatheads + GRAAHK_NOD(6551), + GHRAAK_SHAKE_MILD(6553), + GHRAAK_SHAKE_VIGOROUS(6555), + + ; //TODO: More? /* * From some sources: here's a potential list of chatheads. * // 667 * Chat animation group: 1540; linked animations: [7, 8, 9, 6824] - * Chat animation group: 1489; linked animations: [225, 6550, 6551, 6552, 6553, 6555, 8372, 8373, 8374, 8375, 8581, 8582, 9178, 9179, 9180, 9181, 9183, 9187, 9189, 9190, 9192, 9202] + * Chat animation group: 1489; potentially all familiars; linked animations: [225, 6550, 6551, 6552, 6553, 6555, 8372, 8373, 8374, 8375, 8581, 8582, 9178, 9179, 9180, 9181, 9183, 9187, 9189, 9190, 9192, 9202] * Chat animation group: 82; linked animations: [554, 555, 556, 557, 562, 563, 564, 565, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 610, 611, 612, 613, 614, 615, 616, 617] * Chat animation group: 84; linked animations: [558, 559, 560, 561] * Chat animation group: 80; linked animations: [584, 585, 586, 587] diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 30d32e9f2..a4dc0b4bc 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -3,6 +3,7 @@ package core.game.node.entity.player; import content.global.handlers.item.equipment.BarrowsEquipment; import content.global.handlers.item.equipment.special.SalamanderSwingHandler; import content.global.skill.runecrafting.PouchManager; +import content.global.skill.slayer.SlayerEquipmentFlags; import core.api.ContentAPIKt; import core.game.component.Component; import core.game.container.Container; @@ -638,7 +639,7 @@ public class Player extends Entity { if (i == null) continue; InteractionListeners.run(i.getId(), this, i, false); Plugin equipPlugin = i.getDefinition().getConfiguration("equipment", null); - if (equipPlugin != null) equipPlugin.fireEvent("unequip"); + if (equipPlugin != null) equipPlugin.fireEvent("unequip", this, i); } boolean canCreateGrave = GraveController.allowGenerate(this); @@ -669,9 +670,9 @@ public class Player extends Entity { } if (BarrowsEquipment.isBarrowsItem(item.getId())) { if (!BarrowsEquipment.isBroken(item.getId())) { - int brokenItemId = Objects.requireNonNull(BarrowsEquipment.getDefinition(item.getId())).getBrokenId(); - item = new Item(brokenItemId, item.getAmount()); - } + int brokenItemId = Objects.requireNonNull(BarrowsEquipment.getDefinition(item.getId())).getBrokenId(); + item = new Item(brokenItemId, item.getAmount()); + } } else { item = GraveController.checkTransform(item); } @@ -687,6 +688,7 @@ public class Player extends Entity { } equipment.clear(); + SlayerEquipmentFlags.updateFlags(this); inventory.clear(); inventory.addAll(c[0]); familiarManager.dismiss(); diff --git a/Server/src/main/core/game/shops/Shop.kt b/Server/src/main/core/game/shops/Shop.kt index 1d041cf8a..9d8425993 100644 --- a/Server/src/main/core/game/shops/Shop.kt +++ b/Server/src/main/core/game/shops/Shop.kt @@ -62,17 +62,18 @@ class Shop(val title: String, val stock: Array, val general: Boolean = fun showTab(player: Player, main: Boolean) { - val cont = if (main) getAttribute(player, "shop-cont", null) ?: return else playerStock + val mainCont = getAttribute(player, "shop-cont", null) ?: return + val cont = if (main) mainCont else playerStock if(!main) { - cont.listeners.remove(listenerInstances[player.details.uid]) + mainCont.listeners.remove(listenerInstances[player.details.uid]) playerStock.listeners.add(listenerInstances[player.details.uid]) } else { playerStock.listeners.remove(listenerInstances[player.details.uid]) - cont.listeners.add(listenerInstances[player.details.uid]) + mainCont.listeners.add(listenerInstances[player.details.uid]) } val settings = IfaceSettingsBuilder() diff --git a/Server/src/main/core/game/system/command/Command.kt b/Server/src/main/core/game/system/command/Command.kt index 8fc40e222..c76e42a61 100644 --- a/Server/src/main/core/game/system/command/Command.kt +++ b/Server/src/main/core/game/system/command/Command.kt @@ -2,13 +2,14 @@ package core.game.system.command import core.game.node.entity.player.Player import core.ServerConstants +import core.api.sendChat import core.game.node.entity.player.info.Rights import core.game.world.GameWorld import kotlin.collections.ArrayList /** * Base class for Commands in the new system. Can pass a lambda as part of the constructor or after the constructor. - * @author Ceikry + * @author Ceikry, Player Name */ class Command(val name: String, val privilege: Privilege, val usage: String = "UNDOCUMENTED", val description: String = "UNDOCUMENTED", val handle: (Player, Array) -> Unit) { fun attemptHandling(player: Player, args: Array?){ @@ -18,6 +19,11 @@ class Command(val name: String, val privilege: Privilege, val usage: String = "U val isCheater = ServerConstants.I_AM_A_CHEATER if (hasRights || isDev || isCheater) { handle(player,args) + } else if (ServerConstants.PLAYER_COMMANDS || args[0] == "bank") { + // Authentically, if you attempt to use a command you shouldn't have access to, the game is supposed to say the below line. + // We do this for all our custom commands if they are enabled (in which case this will only trigger for commands above your privilege level), + // otherwise we only do it for the one command we have evidence existed authentically, "bank" (https://www.reddit.com/r/2007scape/comments/3n1c4d/hey_everyone_i_just_tried_to_do_something_very/) + sendChat(player, "Hey, everyone, I just tried to do something very silly!") } } }