diff --git a/Server/data/configs/door_configs.json b/Server/data/configs/door_configs.json index b01e8657a..528a51934 100644 --- a/Server/data/configs/door_configs.json +++ b/Server/data/configs/door_configs.json @@ -73,7 +73,7 @@ }, { "id": "92", - "replaceId": "17317", + "replaceId": "91", "fence": "false", "metal": "false" }, @@ -2689,7 +2689,7 @@ }, { "id": "31815", - "replaceId": "31816", + "replaceId": "31817", "fence": "false", "metal": "false" }, diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index de99f91cc..82149a63c 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -19,6 +19,18 @@ "item_id": "53", "loc_data": "{3,3240,3940,0,300}-{2,3237,3948,0,300}-{3,3235,3949,0,300}" }, + { + "item_id": "83", + "loc_data": "{1,2637,9819,0,30}" + }, + { + "item_id": "84", + "loc_data": "{1,2638,9906,0,30}" + }, + { + "item_id": "85", + "loc_data": "{1,2628,9859,0,30}" + }, { "item_id": "88", "loc_data": "{1,2654,9767,0,4587583}" @@ -177,7 +189,7 @@ }, { "item_id": "687", - "loc_data": "{1,2655,3424,0,6553680}-{1,2665,3424,0,6553680}-{1,2669,3423,0,6553680}-{1,2668,3419,0,6553680}-{1,2671,3420,0,6553680}-{1,2677,3423,0,6553680}-{1,2676,3425,0,6553680}-{1,2676,3422,0,6553680}-{1,2679,3424,0,6553680}-{1,2678,3426,0,6553680}-{1,2679,3423,0,6553680}-{1,2680,3424,0,6553680}-{1,2672,3427,0,6553680}-{1,2676,3430,0,6553680}-{1,2673,3428,0,6553680}-{1,2670,3437,0,6553680}" + "loc_data": "{1,2655,3424,0,6553680}-{1,2665,3424,0,6553680}-{1,2669,3423,0,6553680}-{1,2668,3419,0,6553680}-{1,2671,3420,0,6553680}-{1,2677,3423,0,6553680}-{1,2676,3425,0,6553680}-{1,2676,3422,0,6553680}-{1,2679,3424,0,6553680}-{1,2678,3426,0,6553680}-{1,2679,3423,0,6553680}-{1,2680,3424,0,6553680}-{1,2672,3427,0,6553680}-{1,2676,3430,0,6553680}-{1,2673,3428,0,6553680}-{1,2670,3437,0,6553680}-{1,2649,9854,0,6553680}-{1,2643,9853,0,6553680}-{1,2644,9851,0,6553680}" }, { "item_id": "712", @@ -393,7 +405,7 @@ }, { "item_id": "1925", - "loc_data": "{1,2564,3332,0,100}-{1,2428,3079,0,6553680}-{1,2428,3080,0,6553680}-{1,2371,3128,0,6553680}-{1,2371,3127,0,6553680}-{1,3225,3294,0,6553680}-{1,3121,3359,0,6553660}-{1,3216,9625,0,6553680}-{1,3026,3289,0,6553680}-{1,2958,3510,0,6553680}-{1,3221,3497,1,6553680}-{1,2958,3510,0,6553680}-{1,3222,3491,1,6553680}-{1,3307,3195,0,5898270}-{1,1941,4956,0,5898270}" + "loc_data": "{1,2564,3332,0,100}-{1,2428,3079,0,6553680}-{1,2428,3080,0,6553680}-{1,2371,3128,0,6553680}-{1,2371,3127,0,6553680}-{1,3225,3294,0,6553680}-{1,3121,3359,0,6553660}-{1,3216,9625,0,6553680}-{1,3026,3289,0,6553680}-{1,2958,3510,0,6553680}-{1,3221,3497,1,6553680}-{1,2958,3510,0,6553680}-{1,3222,3491,1,6553680}-{1,3307,3195,0,5898270}-{1,1941,4956,0,5898270}-{1,2633,9908,0,100}" }, { "item_id": "1927", diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json index 51e9209f2..5d1ee7242 100644 --- a/Server/data/configs/item_configs.json +++ b/Server/data/configs/item_configs.json @@ -765,6 +765,13 @@ "bonuses": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,16", "equipment_slot": "13" }, + { + "examine": "A lever to open something perhaps?", + "durability": null, + "name": "Lever", + "archery_ticket_price": "0", + "id": "83" + }, { "destroy_message": "You can reclaim this item from the place you found it.", "examine": "The power in this staff causes it to vibrate gently.", diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index eaafee09d..bfd15fb0b 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -4291,13 +4291,56 @@ "range_level": "36", "attack_level": "27" }, + { + "examine": "He walks with a slight limp.", + "melee_animation": "401", + "range_animation": "0", + "combat_audio": "511,513,512", + "magic_level": "1", + "respawn_delay": "30", + "defence_animation": "404", + "weakness": "", + "magic_animation": "0", + "death_animation": "836", + "name": "Lucien", + "defence_level": "10", + "safespot": null, + "lifepoints": "17", + "strength_level": "11", + "id": "272", + "aggressive": "", + "range_level": "1", + "attack_level": "12" + }, + { + "examine": "He walks with a slight limp.", + "melee_animation": "", + "range_animation": "", + "combat_audio": "", + "defence_animation": "404", + "weakness": "", + "magic_animation": "", + "death_animation": "836", + "name": "Lucien", + "defence_level": "", + "safespot": null, + "lifepoints": "", + "strength_level": "", + "id": "273", + "aggressive": "", + "range_level": "", + "attack_level": "12" + }, { "examine": "A guard who has devoted their life to Armadyl.", "range_animation": "0", + "melee_animation": "401", + "combat_audio": "511,513,512", "respawn_delay": "60", - "defence_animation": "0", + "defence_animation": "404", "weakness": "8", "magic_animation": "0", + "death_animation": "836", "name": "Guardian of Armadyl", "defence_level": "30", "safespot": null, @@ -4310,9 +4353,13 @@ { "examine": "A guard who has devoted their life to Armadyl.", "range_animation": "0", - "defence_animation": "0", + "melee_animation": "401", + "combat_audio": "511,513,512", + "respawn_delay": "60", + "defence_animation": "404", "weakness": "8", "magic_animation": "0", + "death_animation": "836", "name": "Guardian of Armadyl", "defence_level": "30", "safespot": null, @@ -4324,21 +4371,28 @@ }, { "examine": "Intimidating!", + "start_gfx": "99", "combat_style": "2", + "start_height": "96", "melee_animation": "0", "range_animation": "0", + "combat_audio": "511,513,512", + "attack_speed": "8", + "magic_level": "62", + "end_gfx": "101", "respawn_delay": "60", - "defence_animation": "0", + "defence_animation": "425", "weakness": "3", - "magic_animation": "0", + "magic_animation": "711", "death_animation": "836", "name": "Fire Warrior of Lesarkus", - "defence_level": "55", + "defence_level": "78", "safespot": null, - "lifepoints": "78", - "strength_level": "55", + "lifepoints": "59", + "strength_level": "78", "id": "277", "range_level": "1", + "projectile": "127", "attack_level": "55" }, { @@ -49279,10 +49333,10 @@ "range_animation": "0", "attack_speed": "4", "magic_level": "1", + "respawn_delay": "60", "defence_animation": "0", "weakness": "2", "slayer_exp": "93", - "respawn_delay": "60", "magic_animation": "0", "death_animation": "6081", "name": "Cave bug", diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 7916efb60..cd6750499 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -289,11 +289,11 @@ }, { "npc_id": "92", - "loc_data": "{3111,3561,0,1,3}-{3132,9915,0,1,5}-{3095,9909,0,1,3}-{3149,9869,0,1,6}-{3138,9878,0,1,5}-{3137,9869,0,1,3}-{2840,9652,0,1,1}-{2829,9657,0,1,4}-{2819,3288,0,1,1}-{2848,3248,0,1,3}-{2850,3235,0,1,3}-{3117,9671,0,1,1}-{3122,9661,0,1,6}-{3123,9648,0,1,6}-{3005,10362,0,1,1}-{3003,10358,0,1,1}-{3005,10351,0,1,1}-{3003,10345,0,1,5}-{2992,3942,0,1,4}-{2593,9883,0,1,1}-{2590,9885,0,1,4}-{2586,9883,0,1,1}-{2585,9878,0,1,3}-{2537,9845,0,1,1}-{2540,9846,0,1,4}-{2552,9844,0,1,6}-{2556,9846,0,1,4}-{2535,9844,0,1,3}-{2532,9843,0,1,4}-{2530,9845,0,1,3}-{2540,9820,0,1,4}-{2544,9824,0,1,4}-{2980,3763,0,1,0}-{2977,3753,0,1,0}-{3143,3802,0,1,0}-{3145,3779,0,1,0}" + "loc_data": "{3111,3561,0,1,3}-{3132,9915,0,1,5}-{3095,9909,0,1,3}-{3149,9869,0,1,6}-{3138,9878,0,1,5}-{3137,9869,0,1,3}-{2840,9652,0,1,1}-{2829,9657,0,1,4}-{2819,3288,0,1,1}-{2848,3248,0,1,3}-{2850,3235,0,1,3}-{3117,9671,0,1,1}-{3122,9661,0,1,6}-{3123,9648,0,1,6}-{3005,10362,0,1,1}-{3003,10358,0,1,1}-{3005,10351,0,1,1}-{3003,10345,0,1,5}-{2992,3942,0,1,4}-{2593,9883,0,1,1}-{2590,9885,0,1,4}-{2586,9883,0,1,1}-{2585,9878,0,1,3}-{2537,9845,0,1,1}-{2540,9846,0,1,4}-{2552,9844,0,1,6}-{2556,9846,0,1,4}-{2535,9844,0,1,3}-{2532,9843,0,1,4}-{2530,9845,0,1,3}-{2540,9820,0,1,4}-{2544,9824,0,1,4}-{2980,3763,0,1,0}-{2664,9877,0,1,0}-{2977,3753,0,1,0}-{3143,3802,0,1,0}-{3145,3779,0,1,0}" }, { "npc_id": "93", - "loc_data": "{3101,9956,0,1,3}-{3104,9948,0,1,0}-{3104,9955,0,1,4}-{3108,9951,0,1,4}-{3108,9954,0,1,1}-{3111,9954,0,1,6}-{3112,9958,0,1,4}-{2841,9625,0,1,4}-{2845,9628,0,1,3}-{2841,9638,0,1,6}-{2845,9645,0,1,1}-{2655,9824,0,1,1}-{2669,9824,0,1,4}-{2667,9823,0,1,5}-{2658,9830,0,1,6}-{2666,9829,0,1,6}-{3194,5460,0,1,6}-{3192,5466,0,1,7}-{2566,9507,0,1,3}-{2562,9505,0,1,1}-{2568,9509,0,1,3}-{3185,5493,0,1,4}-{3182,5494,0,1,6}-{3185,5486,0,1,7}-{3175,5492,0,1,3}-{3169,5496,0,1,4}-{3170,5492,0,1,3}-{3186,5487,0,1,4}-{3169,5491,0,1,2}-{2571,9509,0,1,1}-{2564,9504,0,1,1}-{2566,9505,0,1,1}-{2544,9841,0,1,1}-{2536,9844,0,1,6}-{2527,9844,0,1,3}-{2530,9842,0,1,4}-{2543,9815,0,1,3}" + "loc_data": "{3101,9956,0,1,3}-{3104,9948,0,1,0}-{3104,9955,0,1,4}-{3108,9951,0,1,4}-{3108,9954,0,1,1}-{3111,9954,0,1,6}-{3112,9958,0,1,4}-{2841,9625,0,1,4}-{2845,9628,0,1,3}-{2841,9638,0,1,6}-{2845,9645,0,1,1}-{2655,9824,0,1,1}-{2669,9824,0,1,4}-{2667,9823,0,1,5}-{2658,9830,0,1,6}-{2666,9829,0,1,6}-{3194,5460,0,1,6}-{3192,5466,0,1,7}-{2566,9507,0,1,3}-{2562,9505,0,1,1}-{2568,9509,0,1,3}-{3185,5493,0,1,4}-{3182,5494,0,1,6}-{3185,5486,0,1,7}-{3175,5492,0,1,3}-{3169,5496,0,1,4}-{3170,5492,0,1,3}-{3186,5487,0,1,4}-{3169,5491,0,1,2}-{2571,9509,0,1,1}-{2564,9504,0,1,1}-{2566,9505,0,1,1}-{2544,9841,0,1,1}-{2536,9844,0,1,6}-{2527,9844,0,1,3}-{2530,9842,0,1,4}-{2543,9815,0,1,3}-{2637,9891,0,1,0}-{2645,9891,0,1,0}-{2653,9892,0,1,0}-{2653,9892,0,1,0}" }, { "npc_id": "94", @@ -795,6 +795,26 @@ "npc_id": "271", "loc_data": "{2608,3158,0,1,3}" }, + { + "npc_id": "272", + "loc_data": "{3127,3485,0,1,1}" + }, + { + "npc_id": "273", + "loc_data": "{2573,3321,0,1,3}" + }, + { + "npc_id": "274", + "loc_data": "{2638,9899,0,1,6}-{2639,9911,0,1,6}-{2648,9901,0,1,6}-{2649,9912,0,1,6}-{2649,9905,0,1,6}-{2650,9897,0,1,6}" + }, + { + "npc_id": "275", + "loc_data": "{2636,9910,0,1,4}-{2637,9897,0,1,4}-{2643,9913,0,1,6}-{2646,9906,0,1,6}" + }, + { + "npc_id": "276", + "loc_data": "{2656,9875,0,1,3}" + }, { "npc_id": "278", "loc_data": "{3209,3215,0,0,0}" @@ -7450,15 +7470,15 @@ }, { "npc_id": "4695", - "loc_data": "{3098,3699,0,1,4}-{3015,3851,0,1,2}-{2839,9565,0,1,3}-{2837,9601,0,1,4}-{2840,3279,0,1,6}" + "loc_data": "{3098,3699,0,1,4}-{3015,3851,0,1,2}-{2839,9565,0,1,3}-{2837,9601,0,1,4}-{2840,3279,0,1,6}-{2631,9880,0,1,1}" }, { "npc_id": "4696", - "loc_data": "{3096,3691,0,1,6}-{2931,9808,0,1,0}-{2930,9799,0,1,0}-{3014,3848,0,1,1}-{2839,9560,0,1,4}-{2846,9613,0,1,6}-{3091,3861,0,1,0}" + "loc_data": "{3096,3691,0,1,6}-{2931,9808,0,1,0}-{2930,9799,0,1,0}-{3014,3848,0,1,1}-{2839,9560,0,1,4}-{2846,9613,0,1,6}-{3091,3861,0,1,0}-{2632,9874,0,1,1}" }, { "npc_id": "4697", - "loc_data": "{3105,3695,0,1,5}-{3324,3856,0,1,2}-{3016,3845,0,1,4}-{2845,9557,0,1,2}-{2839,9624,0,1,6}-{2825,3277,0,1,3}" + "loc_data": "{3105,3695,0,1,5}-{3324,3856,0,1,2}-{3016,3845,0,1,4}-{2845,9557,0,1,2}-{2839,9624,0,1,6}-{2825,3277,0,1,3}-{2630,9867,0,1,1}" }, { "npc_id": "4698", @@ -8074,7 +8094,7 @@ }, { "npc_id": "5341", - "loc_data": "{2840,9633,0,1,1}-{2844,9634,0,1,6}-{2842,9637,0,1,3}" + "loc_data": "{2840,9633,0,1,1}-{2844,9634,0,1,6}-{2842,9637,0,1,3}-{2641,9889,0,1,0}-{2648,9890,0,1,0}-{2657,9894,0,1,0}-{2658,9888,0,1,0}" }, { "npc_id": "5342", diff --git a/Server/data/configs/object_configs.json b/Server/data/configs/object_configs.json index 9a638671d..3fd42b4c7 100644 --- a/Server/data/configs/object_configs.json +++ b/Server/data/configs/object_configs.json @@ -1753,7 +1753,7 @@ }, { "examine": "Danger!", - "ids": "1032,5127,29373" + "ids": "1032,5127" }, { "examine": "This tells you which way is which.", @@ -20295,6 +20295,10 @@ "examine": "Technically a bed.", "ids": "32031" }, + { + "examine": "Now that's what I call slimline!", + "ids": "32072" + }, { "examine": "A really bad portrait of the King.", "ids": "32326" @@ -20623,6 +20627,10 @@ "examine": "Keeps the puppies out of trouble.", "ids": "28341" }, + { + "examine": "Warning! Danger of death.", + "ids": "29373" + }, { "examine": "There are some toolboxes on this table.", "ids": "36573,36580" diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/BridgeAgility.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/BridgeAgility.kt new file mode 100644 index 000000000..f2b9e8341 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/BridgeAgility.kt @@ -0,0 +1,37 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.node.entity.Entity +import core.game.node.entity.combat.ImpactHandler +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.game.world.map.zone.ZoneBorders + +class BridgeAgility: MapArea { + companion object { + private fun checkWeightOrFailBridge(entity: Entity) { + // If player weighs more than 0kg at any point on the bridge, the bridge breaks. + // The boots of lightness may be needed here as it makes the player -4kg lighter. + if (entity is Player && entity.settings.weight > 0) { + entity.impactHandler.manualHit(entity, 20, ImpactHandler.HitsplatType.NORMAL) + sendMessage(entity, "The bridge gives way under your weight!") + sendChat(entity, "Ow! Hot! Hot!") + sendMessage(entity, "Good thing that lava was shallow!") + entity.teleport(Location.create(2647, 9826, 0)) + } + } + } + + override fun defineAreaBorders(): Array { + return arrayOf(ZoneBorders(2648, 9828, 2649, 9829)) + } + override fun areaEnter(entity: Entity) { + checkWeightOrFailBridge(entity) + } + override fun areaLeave(entity: Entity, logout: Boolean) { + checkWeightOrFailBridge(entity) + } + override fun entityStep(entity: Entity, location: Location, lastLocation: Location) { + checkWeightOrFailBridge(entity) + } +} diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusDialogue.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusDialogue.kt new file mode 100644 index 000000000..2272e2efb --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusDialogue.kt @@ -0,0 +1,37 @@ +package content.region.kandarin.quest.templeofikov + +import core.game.dialogue.* +import core.game.node.entity.player.Player +import core.plugin.Initializable +import core.tools.END_DIALOGUE +import core.tools.START_DIALOGUE +import org.rs09.consts.NPCs + +@Initializable +class FireWarriorOfLesarkusDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return FireWarriorOfLesarkusDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + when(stage) { + START_DIALOGUE -> npcl(FacialExpression.ANGRY, "Who dares to enter the Temple of Ikov!").also { stage++ } + 1 -> showTopics( + Topic(FacialExpression.ANGRY, "A mighty hero!", 2), + Topic(FacialExpression.FRIENDLY, "A humble pilgrim.", 4), + ) + 2 -> npcl(FacialExpression.ANGRY, "Pathetic fool! Prepare to die!").also { stage++ } + 3 -> { + npc!!.attack(player) + end() + } + 4 -> npcl(FacialExpression.ANGRY, "I haven't seen a pilgrim for thousands of years!").also { stage++ } + 5 -> npcl(FacialExpression.ANGRY, "Temple is closed!").also { + stage = END_DIALOGUE + } + } + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.FIRE_WARRIOR_OF_LESARKUS_277) + } +} diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusNPC.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusNPC.kt new file mode 100644 index 000000000..0b700a2d3 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/FireWarriorOfLesarkusNPC.kt @@ -0,0 +1,73 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.FacialExpression +import core.game.node.entity.Entity +import core.game.node.entity.combat.BattleState +import core.game.node.entity.combat.CombatStyle +import core.game.node.entity.npc.AbstractNPC +import core.game.node.entity.player.Player +import core.game.system.task.Pulse +import core.game.world.map.Location +import org.rs09.consts.NPCs + +class FireWarriorOfLesarkusNPC(id: Int = 0, val player: Player?, location: Location? = null) : AbstractNPC(id, location) { + var clearTime = 0 + // Technically not constructed this way since this is invoked on load. + override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC { + return FireWarriorOfLesarkusNPC(id, null, location) + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.FIRE_WARRIOR_OF_LESARKUS_277) + } + + override fun handleTickActions() { + super.handleTickActions() + // You have 240 ticks to kill this guy or touch the door again. + if (clearTime++ > 240) { + removeAttribute(player!!, TempleOfIkov.attributeWarriorInstance) + poofClear(this) + } + } + + override fun isAttackable(entity: Entity, style: CombatStyle, message: Boolean): Boolean { + val attackable = super.isAttackable(entity, style, message) + val player = entity.asPlayer() + //attributeWarriorInstance + return attackable + } + + override fun checkImpact(state: BattleState) { + super.checkImpact(state) + val player = state.attacker.asPlayer() + val opponent = this + println(state.ammunition) + if (state.ammunition != null && state.ammunition.itemId == 78) { + // Only ice arrows will damage warrior. + } else { + // If it is the wrong combat or ammunition, deny all damage. + player.properties.combatPulse.stop() + if (state.estimatedHit > -1) { + state.estimatedHit = 0 + } + if (state.secondaryHit > -1) { + state.secondaryHit = 0 + } + runTask(player, 0) { + sendNPCDialogue(player, opponent.id, "Your puny weapons do nothing against me human! Come back when you can give me a real fight!", FacialExpression.ANGRY) + } + } + } + + override fun finalizeDeath(entity: Entity) { + if (entity is Player) { + val player = entity.asPlayer() + removeAttribute(player, TempleOfIkov.attributeWarriorInstance) + if(getQuestStage(player, TempleOfIkov.questName) == 3) { + setQuestStage(player, TempleOfIkov.questName, 4) + } + super.finalizeDeath(player) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylBehavior.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylBehavior.kt new file mode 100644 index 000000000..6101484c1 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylBehavior.kt @@ -0,0 +1,30 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.isQuestComplete +import core.game.node.entity.Entity +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.node.entity.player.Player +import core.game.node.item.Item +import core.tools.RandomFunction +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class GuardianOfArmadylBehavior : NPCBehavior(*guardianOfArmadylIds) { + companion object { + private val guardianOfArmadylIds = intArrayOf( + NPCs.GUARDIAN_OF_ARMADYL_274, + NPCs.GUARDIAN_OF_ARMADYL_275 + ) + } + + override fun onDropTableRolled(self: NPC, killer: Entity, drops: ArrayList) { + super.onDropTableRolled(self, killer, drops) + // Drops Pendant of Armadyl after quest complete when killed. + if (killer is Player && isQuestComplete(killer, TempleOfIkov.questName)) { + if(RandomFunction.roll(4)) { + drops.add(Item(Items.ARMADYL_PENDANT_87)) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylDialogue.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylDialogue.kt new file mode 100644 index 000000000..50a9293e4 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/GuardianOfArmadylDialogue.kt @@ -0,0 +1,163 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.DialogueBuilder +import core.game.dialogue.DialogueBuilderFile +import core.game.dialogue.DialoguePlugin +import core.game.dialogue.FacialExpression +import core.game.node.entity.player.Player +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class GuardianOfArmadylDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return GuardianOfArmadylDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, GuardianOfArmadylDialogueFile(), npc) + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.GUARDIAN_OF_ARMADYL_274, NPCs.GUARDIAN_OF_ARMADYL_275) + } +} + +class GuardianOfArmadylDialogueFile : DialogueBuilderFile() { + override fun create(b: DialogueBuilder) { + b.onPredicate { _ -> true } + .branch { player -> + return@branch if (inEquipment(player, Items.PENDANT_OF_LUCIEN_86)) { 1 } else { 0 } + }.let{ branch -> + // Failure branch + branch.onValue(1) + .npcl("Thou is a foul agent of Lucien! Such an agent must die!") + .endWith { _, player -> + npc!!.attack(player) + } + return@let branch // Return DialogueBranchBuilder instead of DialogueBuilder to forward the success branch. + }.onValue(0) // Success branch + .npcl("Thou hast ventured deep into the tunnels, you have reached the temple of our master. It is many ages since a pilgrim has come here.") + .options() + .let { optionBuilder -> + val returnJoin = b.placeholder() + + optionBuilder.option("I seek the Staff of Armadyl.") + .playerl(FacialExpression.FRIENDLY, "I seek the Staff of Armadyl.") + .npcl(FacialExpression.FRIENDLY, "We are the guardians of the staff, our fathers were guardians and our fathers' fathers before that. Why dost thou seek it?") + .options() + .let { optionBuilder2 -> + optionBuilder2.option_playerl("Lucien will give me a grand reward for it!") + .npcl(FacialExpression.FRIENDLY, "Thou art working for that spawn of evil?! Fool! You must be cleansed to save your soul!") + .goto(returnJoin) + optionBuilder2.option_playerl("Give it to me!") + .npcl(FacialExpression.FRIENDLY, "The staff is sacred! You will not have it!") + .endWith { _, player -> + npc!!.attack(player) + } + optionBuilder2.option_playerl("I collect rare and powerful artefacts.") + .npcl(FacialExpression.FRIENDLY, "Your worldly greed has darkened your soul!") + .endWith { _, player -> + npc!!.attack(player) + } + } + + optionBuilder.option_playerl("Out of my way fool!") + .npcl(FacialExpression.FRIENDLY, "I may be a fool but I will not step aside!") + .options() + .let { optionBuilder2 -> + optionBuilder2.option_playerl("Why not?!") + .npcl(FacialExpression.FRIENDLY, "Only members of our order are allowed to handle the staff.") + .end() + optionBuilder2.option_playerl("Then you must die!") + .endWith { _, player -> + npc!!.attack(player) + } + optionBuilder2.option_playerl("You're right, I will go now.") + .npcl(FacialExpression.FRIENDLY, "That is a wise decision. Stay a while and let your soul be cleansed!") + .end() + } + + optionBuilder.option_playerl("What are your kind and what are you doing here?") + .npcl(FacialExpression.FRIENDLY, "We are the Guardians of Armadyl. We have kept the temple safe for many ages. The evil in the dungeons seek what lies here. The Mahjarrat are the worst.") + .options() + .let { optionBuilder2 -> + optionBuilder2.option_playerl("What is the Armadyl?") + .npcl(FacialExpression.FRIENDLY, "Armadyl is the god we serve. We have been charged with guarding his sacred artifacts until he requires them.") + .options() + .let { optionBuilder3 -> + optionBuilder3.option_playerl("Ah ok, thanks.") + .npcl(FacialExpression.FRIENDLY, "Go in peace.") + .end() + optionBuilder3.option("Someone told me there were only three gods.") + .playerl(FacialExpression.FRIENDLY, "Someone told me there were only three gods. Saradomin, Zamorak and Guthix.") + .npcl(FacialExpression.FRIENDLY, "Saradominists. Bleh. They only acknowledge those three. There are at least twenty gods!") + .end() + } + + optionBuilder2.option_playerl("Who are the Mahjarrat?") + .npcl(FacialExpression.FRIENDLY, "They are ancient and powerful beings! They are very evil! It is said that they once dominated this plane of existence, Zamorak was supposedly of their blood. They are far fewer in number now.") + .npcl(FacialExpression.FRIENDLY, "Some still have presence in this world in their liche forms. Mahjarrat such as Lucien and Azzanadra would become very powerful if they came into possession of the Staff of Armadyl.") + .options() + .let { optionBuilder3 -> + optionBuilder3.option("Did you say Lucien?") + .playerl(FacialExpression.FRIENDLY, "Did you say Lucien? It was Lucien that asked me to get the staff!") + .npcl(FacialExpression.FRIENDLY, "You are a fool to be working for Lucien! Your soul must be cleansed to save you!") + .goto(returnJoin) + optionBuilder3.option_playerl("I hope you're doing a good job then!") + .npcl(FacialExpression.FRIENDLY, "Do not fear! We are devoted to our charge!") + .end() + } + + optionBuilder2.option_playerl("Wow! You must be really old!") + .npcl(FacialExpression.ANGRY, "No! I am not old! My family has guarded the staff for many generations.") + .end() + } + return@let returnJoin.builder() + } // continue the path here for Lucien.options() + .options() + .let { optionBuilder -> + optionBuilder.option("How dare you call me a fool!") + .playerl(FacialExpression.ANGRY, "How dare you call me a fool! I will work for whom I want!") + .npcl(FacialExpression.ANGRY, "We must cleanse the temple!") + .endWith { _, player -> + npc!!.attack(player) + } + optionBuilder.option_playerl("I just thought of something I must do!") + .npcl(FacialExpression.ANGRY, "An agent of evil cannot be allowed to leave!") + .endWith { _, player -> + npc!!.attack(player) + } + optionBuilder.option_playerl("You're right, it's time for my yearly bath.") + .line("The guardian splashes holy water over you.") + .npcl(FacialExpression.FRIENDLY, "You have been cleansed!") + .npcl(FacialExpression.FRIENDLY, "Lucien must not get hold of the staff! He would become too powerful!") + .npcl(FacialExpression.FRIENDLY, "Hast thou come across the undead necromancer? It was he that raised an army of the undead against Varrock a generation ago. If you know where he is you can help us defeat him.") + .options() + .let { optionBuilder2 -> + optionBuilder2.option_playerl("Ok! I'll help!") + .npcl(FacialExpression.FRIENDLY, "So he is close by?") + .playerl(FacialExpression.FRIENDLY, "Yes!") + .npcl(FacialExpression.FRIENDLY, "He must be gaining in power again. If you can defeat him he will be banished from this plane for a while. You will need this pendant to attack him.") + .item(Items.ARMADYL_PENDANT_87, "The guardian has given you a pendant.") + .endWith { _, player -> + setAttribute(player, TempleOfIkov.attributeChosenEnding, 1) + if (getQuestStage(player, TempleOfIkov.questName) == 5) { + setQuestStage(player, TempleOfIkov.questName, 6) + } + addItemOrDrop(player, Items.ARMADYL_PENDANT_87) + } + optionBuilder2.option_playerl("No! I shall not turn against my employer!") + .npcl(FacialExpression.ANGRY, "Fool! You will die for your sins!") + .endWith { _, player -> + npc!!.attack(player) + } + optionBuilder2.option_playerl("I need time to think.") + .npcl(FacialExpression.FRIENDLY, "Linger a while and be at peace.") + .end() + } + } + } + +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/LucienDialogue.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienDialogue.kt new file mode 100644 index 000000000..c6b3c93d2 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienDialogue.kt @@ -0,0 +1,106 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.DialogueBuilder +import core.game.dialogue.DialogueBuilderFile +import core.game.dialogue.DialoguePlugin +import core.game.dialogue.FacialExpression +import core.game.node.entity.player.Player +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class LucienDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return LucienDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, LucienDialogueFile(), npc) + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.LUCIEN_273) + } +} + +class LucienDialogueFile : DialogueBuilderFile() { + override fun create(b: DialogueBuilder) { + b.onQuestStages(TempleOfIkov.questName, 100) + .endWith { _, player -> + sendMessage(player, "You have completed the Temple of Ikov quest.") + } + b.onQuestStages(TempleOfIkov.questName, 1,2,3,4,5,6,7) + .npcl("I told you not to meet me here again!") + .branch { player -> + return@branch if (inInventory(player, Items.PENDANT_OF_LUCIEN_86)) { 1 } else { 0 } + }.let { branch -> + branch.onValue(1) + .playerl("Sorry! Can you remind me of my mission?") + .npcl("My patience grows thin hero!") + .npcl("I need the Staff of Armadyl. It's in the Temple of Ikov, near Hemenster, north east of here.") + .playerl("I'm up for it!") + .end() + branch.onValue(0) + .playerl("I've lost the pendant you gave me.") + .npcl("Imbecile!") + .betweenStage { df, player, _, _ -> + addItemOrDrop(player, Items.PENDANT_OF_LUCIEN_86) + } + .item(Items.PENDANT_OF_LUCIEN_86, "Lucien has given you another pendant!") + .end() + } + + b.onQuestStages(TempleOfIkov.questName, 0) + .npcl("I seek a hero to go on an important mission!") + .options().let { optionBuilder -> + val returnJoin = b.placeholder() + optionBuilder.option("I'm a mighty hero!") + .playerl(FacialExpression.ANGRY, "I'm a mighty hero!") + .goto(returnJoin) + optionBuilder.option_playerl("Yep, lots of heros about these days.") + .npcl("Well, if you see any be sure to point them in my direction.") + .end() + return@let returnJoin.builder() + } + .npcl("I require the Staff of Armadyl. It is in the deserted Temple of Ikov, near Hemenster, north east of here.") + .npcl("Take care hero! There is a dangerous monster somewhere in the temple!") + .let{ builder -> + val returnJoin = b.placeholder() + returnJoin.builder() + .options() + .let { optionBuilder -> + optionBuilder.option_playerl("Why can't you get it yourself?") + .npcl("The guardians of the Staff of Armadyl fear me!") + .npcl("They have set up a magical barrier which even my power cannot overcome!") + .goto(returnJoin) + optionBuilder.option("That sounds like a laugh!") + .playerl(FacialExpression.FRIENDLY, "That sounds like a laugh!") + .npcl("It's not as easy as it sounds. The monster can only be killed with a weapon of ice. There are many other dangers.") + .playerl(FacialExpression.FRIENDLY, "I'm up for it!") + .npcl("Take this pendant. Without it you will not be enter the Chamber of Fear.") + .betweenStage { df, player, _, _ -> + addItemOrDrop(player, Items.PENDANT_OF_LUCIEN_86) + } + .item(Items.PENDANT_OF_LUCIEN_86, "Lucien has given you a pendant!") + .npcl("I cannot stay here much longer. ") + .npcl("I will be west of the Grand Exchange in Varrock. I have a small holding up there.") + .endWith { _, player -> + if(getQuestStage(player, TempleOfIkov.questName) == 0) { + setQuestStage(player, TempleOfIkov.questName, 1) + } + } + optionBuilder.option_playerl("Oh no! Sounds far too dangerous!") + .npcl("Wimp! Call yourself a hero?! My daughter is more a hero than you!") + .end() + optionBuilder.option_playerl("What's the reward?!") + .npcl("I see you are the mercenary type.") + .playerl("It's a living.") + .npcl("I will reward you well if you bring me the staff.") + .goto(returnJoin) + return@let optionBuilder + } + return@let builder.goto(returnJoin) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingDialogue.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingDialogue.kt new file mode 100644 index 000000000..48cf0b890 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingDialogue.kt @@ -0,0 +1,62 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.* +import core.game.node.entity.player.Player +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class LucienEndingDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return LucienEndingDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, LucienEndingDialogueFile(), npc) + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.LUCIEN_272) + } +} + +class LucienEndingDialogueFile : DialogueBuilderFile() { + override fun create(b: DialogueBuilder) { + b.onQuestStages(TempleOfIkov.questName, 100) + .endWith { _, player -> + sendMessage(player, "You have completed the Temple of Ikov quest.") + } + b.onQuestStages(TempleOfIkov.questName, 1,2,3,4,5,6,7) + .npcl(FacialExpression.FRIENDLY, "Have you got the Staff of Armadyl yet?") + .branch { player -> + return@branch if (inInventory(player, Items.STAFF_OF_ARMADYL_84)) { 1 } else { 0 } + }.let { branch -> + branch.onValue(1) + .options() + .let { optionBuilder -> + optionBuilder.option_playerl("Yes! Here it is.") + .betweenStage { _, player, _, _ -> + removeItem(player, Items.STAFF_OF_ARMADYL_84) + } + .iteml(Items.STAFF_OF_ARMADYL_84, "You give Lucien the Staff of Armadyl.") + .npcl(FacialExpression.FRIENDLY, "Muhahahhahahaha!") + .npcl(FacialExpression.FRIENDLY, "I can feel the power of the staff running through me! I will be more powerful and they shall bow down to me!") + .npcl(FacialExpression.FRIENDLY, "I suppose you want your reward? I shall grant you much power!") + .endWith { _, player -> + if(getQuestStage(player, TempleOfIkov.questName) == 6) { + finishQuest(player, TempleOfIkov.questName) + } + } + optionBuilder.option_playerl("No, not yet.") + .end() + } + branch.onValue(0) + .playerl(FacialExpression.FRIENDLY, "No, not yet.") + .end() + } + b.onPredicate { _ -> true } + .npcl("Not here. Meet me at the Flying Horse Inn in East Ardougne.") + .end() + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingNPC.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingNPC.kt new file mode 100644 index 000000000..c4d7a4319 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/LucienEndingNPC.kt @@ -0,0 +1,54 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.DialogueFile +import core.game.node.entity.Entity +import core.game.node.entity.combat.CombatStyle +import core.game.node.entity.npc.AbstractNPC +import core.game.node.entity.npc.NPC +import core.game.node.entity.player.Player +import core.game.world.map.Location +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class LucienEndingNPC(id: Int = 0, location: Location? = null) : AbstractNPC(id, location) { + override fun construct(id: Int, location: Location, vararg objects: Any): AbstractNPC { + return LucienEndingNPC(id, location) + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.LUCIEN_272) + } + + override fun isAttackable(entity: Entity, style: CombatStyle, message: Boolean): Boolean { + val attackable = super.isAttackable(entity, style, message) + val player = entity.asPlayer() + if (inEquipment(player, Items.ARMADYL_PENDANT_87)) { + return attackable + } + sendNPCDialogue(player, this.ids[0], "You don't want to attack me. I am your friend.") + return false + } + + override fun finalizeDeath(entity: Entity) { + if (entity is Player) { + val player = entity.asPlayer() + openDialogue(player, object : DialogueFile(){ + override fun handle(componentID: Int, buttonID: Int) { + when(stage){ + 0 -> npcl("You have defeated me for now! I shall reappear in the North!").also { stage++ } + 1 -> end().also { + if(getQuestStage(player, TempleOfIkov.questName) == 6) { + finishQuest(player, TempleOfIkov.questName) + } + } + } + } + }, NPC(NPCs.LUCIEN_272)) + + super.finalizeDeath(player) + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkov.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkov.kt new file mode 100644 index 000000000..0edb793e8 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkov.kt @@ -0,0 +1,202 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.node.entity.player.link.quest.Quest +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.plugin.Initializable +import org.rs09.consts.Items + +/** + * Temple of Ikov Quest + * + * This is the quest where the journal after completion is a barren wasteland of a useless log. + * One of the worst logs I've ever had the pleasure/pain of doing. + * + * 1 - Talked to Lucien (Lucien pendant) + * 2 - Entered chamber of fear (North Fence) + * 3 - Toggled lever(with disabling trap) + * 4 - Killed fire warrior (comes with trying to open the back door) + * 5 - Winelda given 20 fukkin Limpwurt + * 6 - Good (Armadyl pendant), Bad (Took the Staff of Armadyl) + * 7,100 - Good (Killed Lucien), Bad (Gave Lucien staff) + * + * In parallel (all before 4, log disappears after 4) + * A - Took boots + * B - Cross bridge and found lever + * C - Attached lever to switch near entrance lever + * D - Found ice arrows + */ +@Initializable +class TempleOfIkov : Quest("Temple of Ikov", 121, 120, 1,26, 0, 1, 80 /* 80 or 90 since there's 2 endings */) { + + companion object { + const val questName = "Temple of Ikov" + const val attributeChosenEnding = "/save:quest:templeofikov-chosenending" + + const val attributeDisabledTrap = "/save:quest:templeofikov-disabledtrap" + const val attributeTalkedToWinelda = "/save:quest:templeofikov-talkedtowinelda" + + const val attributeCrossedBridge = "/save:quest:templeofikov-crossedbridge" + const val attributeIceChamberAccess = "/save:quest:templeofikov-icechamberaccess" + const val attributeIceArrows = "/save:quest:templeofikov-icearrows" + + const val attributeRandomChest = "quest:templeofikov-randomChest" + const val attributeWarriorInstance = "quest:templeofikov-warriorInstance" + } + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + var line = 12 + var stage = getStage(player) + + var started = getQuestStage(player, questName) > 0 + + if (!started) { + line(player, "I can start this quest at the !!Flying Horse Inn?? in !!Ardougne??", line++, false) + line(player, "by speaking to !!Lucien??", line++, false) + line++ + line(player, "To start this quest I will need:", line++, false) + line(player, "Level 42 !!Thieving??", line++, hasLevelStat(player, Skills.THIEVING, 42)) + line(player, "Level 40 !!Ranged??", line++, hasLevelStat(player, Skills.RANGE, 40)) + line(player, "Ability to defeat a level 84 enemy with Ranged.", line++, false) + } else { + if (stage >= 2) { + line(player, "Lucien has asked me to retrieve the !!Staff of Armadyl?? from", line++, true) + line(player, "from the !!Temple of Ikov??. The entrance is near !!Hemenster??. He has", line++, true) + line(player, "given me a !!pendant?? so I can enter the !!chamber of fear??.", line++, true) + } else if (stage >= 1) { + line(player, "Lucien has asked me to retrieve the !!Staff of Armadyl?? from", line++, false) + line(player, "from the !!Temple of Ikov??. The entrance is near !!Hemenster??. He has", line++, false) + line(player, "given me a !!pendant?? so I can enter the !!chamber of fear??.", line++, false) + } + + if (stage == 2) { + line(player, "I have entered the chamber of fear.", line++, true) + + } + if (stage == 3) { + line(player, "I have entered the chamber of fear. I found a trap on a", line++, true) + line(player, "lever and have disabled it. I pulled the lever.", line++, true) + } + + // This is a whole side part of retrieving ice arrows that would disappear once you reach stage 4. + if (stage < 4) { + // This is questionable. It's seen in 2014, but seems to be a "side thing". It tracks that you've obtained ice arrows. Derived from RS3. + if (getAttribute(player, attributeIceArrows, false)) { + line(player, "I have found some boots that make me lighter. I made it", line++, true) + line(player, "across the lava bridge and found a lever. I fit the lever", line++, true) + line(player, "into the bracket and pulled the lever. I found arrows", line++, true) + line(player, "made of ice in a chest.", line++, true) + } else if (getAttribute(player, attributeIceChamberAccess, false)) { + line(player, "I have found some boots that make me lighter. I made it", line++, true) + line(player, "across the lava bridge and found a lever. I fit the lever", line++, true) + line(player, "into the bracket and pulled the lever.", line++, true) + } else if (getAttribute(player, attributeCrossedBridge, false)) { + line(player, "I have found some boots that make me lighter. I made it", line++, true) + line(player, "across the lava bridge and found a lever.", line++, true) + } + } + + // Derived. Need sources. + if (stage in 2..3) { + line++ + line(player, "I need to find the entrance to the !!Temple of Ikov??", line++, false) + } + + if (stage == 4) { + line(player, "I have entered the chamber of fear. I found a trap on a", line++, true) + line(player, "lever and have disabled it. I pulled the lever. I went into", line++, true) + line(player, "another chamber and was attacked by a Fire Warrior! I", line++, true) + line(player, "killed it using arrows made of ice and my trusty bow.", line++, true) + } + if (stage == 4 && getAttribute(player, attributeTalkedToWinelda, false) ) { + line++ + // This will never show up crossed. https://www.youtube.com/watch?v=OKYM2oFOUtk 5:18 + line(player, "My path is blocked by lava. !!Winelda?? will teleport me across", line++, false) + line(player, "if I get her !!twenty limpwurt roots??.", line++, false) + } + if (stage == 5) { + line(player, "I have entered the chamber of fear. I found a trap on a", line++, true) + line(player, "lever and have disabled it. I pulled the lever. I went into", line++, true) + line(player, "another chamber and was attacked by a Fire Warrior! I", line++, true) + line(player, "killed it using arrows made of ice and my trusty bow.", line++, true) + } + + if (stage == 6 && getAttribute(player, attributeChosenEnding, 0) == 1 ) { + line(player, "I have entered the chamber of fear. I found a trap on a", line++, true) + line(player, "lever and have disabled it. I pulled the lever. I went into", line++, true) + line(player, "another chamber and was attacked by a Fire Warrior! I", line++, true) + line(player, "killed it using arrows made of ice and my trusty bow.", line++, true) + line++ + line(player, "I agreed to help the !!Guardians of Armadyl??, I will kill !!Lucien??.", line++, false) + line(player, "The guardians gave me a !!pendant?? that I will need to enable", line++, false) + line(player, "me to attack him.", line++, false) + } + + if (stage == 6 && getAttribute(player, attributeChosenEnding, 0) == 2 ) { + line(player, "I have entered the chamber of fear. I found a trap on a", line++, true) + line(player, "lever and have disabled it. I pulled the lever. I went into", line++, true) + line(player, "another chamber and was attacked by a Fire Warrior! I", line++, true) + line(player, "killed it using arrows made of ice and my trusty bow.", line++, true) + line++ + // Derived. Need sources. + line(player, "I recovered the !!Staff of Armadyl?? from the !!Temple of Ikov??.", line++, false) + line(player, "!!Lucien?? is staying at his house west of the !!Grand Exchange??", line++, false) + line(player, "in !!Varrock??.", line++, false) + } + + if (stage >= 100) { + if (getAttribute(player, attributeChosenEnding, 0) == 1) { + //end quest kill lucien https://www.youtube.com/watch?v=cePHhIOqsqg 19:40 + line++ + line(player, "I agreed to help the Guardians of Armadyl, I killed Lucien", line++, true) + line(player, "and banished him from this plane!", line++, true) + } + + if (getAttribute(player, attributeChosenEnding, 0) == 2) { + //end quest helped lucien + line++ + line(player, "I recovered the Staff of Armadyl from the Temple of Ikov.", line++, true) + line(player, "Lucien was staying at his house west of the Grand Exchange", line++, true) + line(player, "in Varrock. He said that the staff had made him more", line++, true) + line(player, "powerful!", line++, true) + } + + line++ + line(player,"QUEST COMPLETE!", line) + } + } + + } + + override fun reset(player: Player) { + removeAttribute(player, attributeChosenEnding) + removeAttribute(player, attributeDisabledTrap) + removeAttribute(player, attributeTalkedToWinelda) + removeAttribute(player, attributeCrossedBridge) + removeAttribute(player, attributeIceArrows) + removeAttribute(player, attributeIceChamberAccess) + } + + override fun finish(player: Player) { + var ln = 10 + super.finish(player) + when (getAttribute(player, attributeChosenEnding, 0)){ + 1 -> player.packetDispatch.sendString("Temple of Ikov Quest completed for Armadyl!", 277, 4) + 2 -> player.packetDispatch.sendString("Temple of Ikov Quest completed for Lucien!", 277, 4) + else -> player.packetDispatch.sendString("Temple of Ikov Quest completed!!", 277, 4) + } + player.packetDispatch.sendItemZoomOnInterface(Items.YEW_LONGBOW_855,230,277,5) + + drawReward(player, "1 Quest Point", ln++) + drawReward(player, "10,500 Ranged XP", ln++) + drawReward(player, "8,000 Fletching XP", ln++) + + rewardXP(player, Skills.RANGE, 10500.0) + rewardXP(player, Skills.FLETCHING, 8000.0) + } + + override fun newInstance(`object`: Any?): Quest { + return this + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkovListeners.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkovListeners.kt new file mode 100644 index 000000000..6a832b230 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/TempleOfIkovListeners.kt @@ -0,0 +1,261 @@ +package content.region.kandarin.quest.templeofikov + +import content.global.ame.events.drilldemon.DrillDemonUtils +import content.global.ame.events.drilldemon.SeargentDamienDialogue +import content.global.skill.agility.AgilityHandler +import core.api.* +import core.game.global.action.DoorActionHandler +import core.game.global.action.PickupHandler +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength +import core.game.node.entity.Entity +import core.game.node.entity.skill.Skills +import core.game.node.item.GroundItem +import core.game.node.item.Item +import core.game.system.task.Pulse +import core.game.world.map.Direction +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation +import org.rs09.consts.Items +import org.rs09.consts.NPCs +import org.rs09.consts.Scenery +import org.rs09.consts.Sounds + +class TempleOfIkovListeners : InteractionListener { + + companion object { + val chestLocations = + arrayOf(Location(2710, 9850, 0), + Location(2719, 9838, 0), + Location(2729, 9850, 0), + Location(2747, 9848, 0), + Location(2738, 9835, 0), + Location(2745, 9821, 0)) + } + + override fun defineDestinationOverrides() { + // B - C (fucking lever is on an angle) + setDest(IntType.SCENERY, intArrayOf(Scenery.LEVER_87), "pull") { _, _ -> + return@setDest Location.create(2671, 9805, 0) + } + } + + override fun defineListeners() { + + // This is the trap door falling area. + addClimbDest(Location.create(2682, 9849, 0), Location.create(2665, 9849, 0)) + + // Shiny key to back of McGrubor's Wood. THIS MUST BE LOCKED UP + on(Scenery.DOOR_99, SCENERY, "open") { player, node -> + if (inInventory(player, Items.SHINY_KEY_85)){ + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendMessage(player, "The door is locked.") + } + return@on true + } + onUseWith(SCENERY, Items.SHINY_KEY_85, Scenery.DOOR_99) { player, used, with -> + DoorActionHandler.handleAutowalkDoor(player, with.asScenery()) + return@onUseWith true + } + + // 1 - 2 Walk past the gate. You must always wear the pendant to get past this gate. + on(intArrayOf(Scenery.GATE_94, Scenery.GATE_95), SCENERY, "open") { player, node -> + if (inEquipment(player, Items.PENDANT_OF_LUCIEN_86)){ + if(getQuestStage(player, TempleOfIkov.questName) == 1) { + setQuestStage(player, TempleOfIkov.questName, 2) + } + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendMessage(player, "As you reach to open the door a great terror overcomes you!") + } + return@on true + } + + // 2: Trapdoor exit + on(Scenery.TRAPDOOR_100, SCENERY, "open") { player, node -> + sendDialogueLines(player, "You try to open the trapdoor but it won't budge! It looks like the", "trapdoor can only be opened from the other side.") + sendMessage(player, "You try to open the trapdoor but it won't budge!") + sendMessage(player, "It looks like the trapdoor can only be opened from the other side.") + return@on true + } + + + // 2 - 3: Lever with trapdoor pull. + on(Scenery.LEVER_91, SCENERY, "pull") { player, node -> + replaceScenery(node.asScenery(), 88, 3) + animate(player, Animation(2140)) + if (getAttribute(player, TempleOfIkov.attributeDisabledTrap, false)) { + if(getQuestStage(player, TempleOfIkov.questName) == 2) { + setQuestStage(player, TempleOfIkov.questName, 3) + } + } else { + AgilityHandler.fail(player, 2, Location.create(2682, 9855, 0), Animation(770), 20, "You slip and fall to the pit below.") + } + return@on true + } + + // 2: Lever with trapdoor search. If you do not have level 42 thieving, you cannot proceed. + on(Scenery.LEVER_91, SCENERY, "Search for traps") { player, node -> + if (getDynLevel(player, Skills.THIEVING) >= 42) { + sendDialogueLines(player, "You find a trap on the lever! You disable the trap.") + setAttribute(player, TempleOfIkov.attributeDisabledTrap, true) + } else { + // This is the best video. It shows that you can start the quest even if you didn't meet reqs. + // It also shows what happens if you tried to disarm without level 42 Thieving. + // https://www.youtube.com/watch?v=I28nZxZAd58 + sendDialogueLines(player, "You find nothing.") + } + return@on true + } + + // A: Obtain boots. + // Note that the room is "dark". There are two areas. + // You switch between them if you have light or not. + // The light lets you see further into the room + // https://www.youtube.com/watch?v=6ZGpJNeGLJ0 + // sendDialogue("Hmm...bit dark down here! I'm not going to venture far!") + + + // B: Attach lever, authentic if you log out, the lever is lost, and you have to do that bridge again + onUseWith(SCENERY, Items.LEVER_83, Scenery.LEVER_BRACKET_86) { player, used, with -> + removeItem(player, used) + replaceScenery(with.asScenery(), Scenery.LEVER_87, 20) + sendDialogue(player, "You fit the lever into the bracket.") + return@onUseWith true + } + + // B to C: Pull down on lever + on(Scenery.LEVER_87, SCENERY, "pull") { player, node -> + face(player, Location.create(2671, 9803, 0)) + animate(player, Animation(2140)) + replaceScenery(node.asScenery(), 88, 3) // Scenery.88 is the downward lever. + setAttribute(player, TempleOfIkov.attributeIceChamberAccess, true) + queueScript(player, 6, QueueStrength.NORMAL) { + replaceScenery(node.asScenery(), Scenery.LEVER_BRACKET_86, -1) + return@queueScript stopExecuting(player) + } + sendDialogue(player, "You hear the clunking of some hidden machinery.") + return@on true + } + + // C: Gate opens after attached lever + on(intArrayOf(Scenery.GATE_89, Scenery.GATE_90), SCENERY, "open") { player, node -> + if (getAttribute(player, TempleOfIkov.attributeIceChamberAccess, false) || getQuestStage(player, TempleOfIkov.questName) >= 4){ + // To be nice, you can "reset" the chest location by opening the gate. + // This is a failsafe if the attribute gets "stuck", although I doubt it will happen. + setAttribute(player, TempleOfIkov.attributeRandomChest, chestLocations.random()) + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendDialogue(player, "The door won't open!") + } + return@on true + } + + // D: Chest open + on(Scenery.CLOSED_CHEST_35122, SCENERY, "open") { player, node -> + animate(player, 536) + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.OPEN_CHEST_35123, -1) + return@on true + } + + // D: Chest shut + on(Scenery.OPEN_CHEST_35123, SCENERY, "shut") { player, node -> + animate(player, 536) + replaceScenery(node as core.game.node.scenery.Scenery, Scenery.CLOSED_CHEST_35122, -1) + return@on true + } + + // D: Chest search. I assure you this is the worst feature of this goddamn quest. + // 1/6 of the chests are randomly chosen to have 1-5 ice arrows, and it REMEMBERS... + // So clicking on the same one doesn't randomize it. Good luck and fuck you. + on(Scenery.OPEN_CHEST_35123, SCENERY, "search") { player, node -> + if (getAttribute(player, TempleOfIkov.attributeRandomChest, null) == null) { + setAttribute(player, TempleOfIkov.attributeRandomChest, chestLocations.random()) + } + if (getAttribute(player, TempleOfIkov.attributeRandomChest, null) == node.location){ + removeAttribute(player, TempleOfIkov.attributeRandomChest) + val randomAmount = (1..5).random() + addItemOrDrop(player, Items.ICE_ARROWS_78, randomAmount) + sendItemDialogue(player, Item(Items.ICE_ARROWS_78, randomAmount), "You found some ice arrows!") + setAttribute(player, TempleOfIkov.attributeIceArrows, true) + } else { + sendMessage(player, "You search the chest, but find nothing.") + } + return@on true + } + + // 3: Allow access to Fire Warrior Door after pulling the lever + on(Scenery.DOOR_92, SCENERY, "open") { player, node -> + removeAttribute(player, TempleOfIkov.attributeWarriorInstance) + if (getQuestStage(player, TempleOfIkov.questName) >= 3){ + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + sendMessage(player, "The door won't open.") + } + return@on true + } + + + // 3 - 4: Calls for the Fire Warrior, allows passing when Fire Warrior is defeated. + on(Scenery.DOOR_93, SCENERY, "open") { player, node -> + if (getQuestStage(player, TempleOfIkov.questName) >= 4){ + DoorActionHandler.handleAutowalkDoor(player, node.asScenery()) + } else { + if (getAttribute(player, TempleOfIkov.attributeWarriorInstance, null) == null) { + val npc = FireWarriorOfLesarkusNPC(NPCs.FIRE_WARRIOR_OF_LESARKUS_277, player, Location(2646, 9866, 0)) + npc.init() + npc.isRespawn = false + npc.isWalks = false + npc.location = Location(2646, 9866, 0) + npc.direction = Direction.NORTH + submitIndividualPulse(player, object : Pulse() { + var counter = 0 + override fun pulse(): Boolean { + when (counter++) { + 0 -> { + sendChat(npc, "You will not pass!") + } + 2 -> { + sendChat(npc, "Amitus! Setitii!") + spawnProjectile(npc, player, 127) // Launch fire projectile + } + 4 -> { + npc.isWalks = true + return true + } + } + return false + } + }) + + setAttribute(player, TempleOfIkov.attributeWarriorInstance, npc) + // This npc doesn't attack you immediately nor is aggressive at the start. + } else { + sendMessage(player, "The door won't open.") + } + } + return@on true + } + + on(Items.STAFF_OF_ARMADYL_84, IntType.GROUNDITEM,"take") { player, node -> + if (getQuestStage(player, TempleOfIkov.questName) >= 6 && getAttribute(player, TempleOfIkov.attributeChosenEnding, 0) == 1){ + sendMessage(player, "You decide not to steal the staff as you have agreed to help the Guardians") + } + val npcs = findLocalNPCs(player, intArrayOf(NPCs.GUARDIAN_OF_ARMADYL_274, NPCs.GUARDIAN_OF_ARMADYL_275), 4) + if (npcs.isNotEmpty()) { + sendChat(npcs[0], "That is not thine to take!") + npcs[0].attack(player) + } else { + if(getQuestStage(player, TempleOfIkov.questName) == 5) { + setQuestStage(player, TempleOfIkov.questName, 6) + setAttribute(player, TempleOfIkov.attributeChosenEnding, 2) + } + PickupHandler.take(player, node as GroundItem) + } + return@on true + } + + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/templeofikov/WineldaDialogue.kt b/Server/src/main/content/region/kandarin/quest/templeofikov/WineldaDialogue.kt new file mode 100644 index 000000000..d525d1eb3 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/templeofikov/WineldaDialogue.kt @@ -0,0 +1,110 @@ +package content.region.kandarin.quest.templeofikov + +import core.api.* +import core.game.dialogue.DialogueBuilder +import core.game.dialogue.DialogueBuilderFile +import core.game.dialogue.DialoguePlugin +import core.game.dialogue.FacialExpression +import core.game.node.entity.player.Player +import core.game.node.item.Item +import core.game.world.map.Location +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +@Initializable +class WineldaDialogue (player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return WineldaDialogue(player) + } + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, WineldaDialogueFile(), npc) + return false + } + override fun getIds(): IntArray { + return intArrayOf(NPCs.WINELDA_276) + } +} + +class WineldaDialogueFile : DialogueBuilderFile() { + override fun create(b: DialogueBuilder) { + b.onQuestStages(TempleOfIkov.questName, 5,6,7,100) + .playerl(FacialExpression.FRIENDLY, "Hi again. Could you do the honours again please?") + .npcl(FacialExpression.FRIENDLY, "Certainly! We helps those that helps poor Winelda!") + .endWith { _, player -> + // There's a cutscene, but I'm lazy man. + teleport(player, Location(2664, 9876, 0)) + } + + b.onPredicate { player -> getAttribute(player, TempleOfIkov.attributeTalkedToWinelda, false) } + .npcl("Have you got roots for poor Winelda?") + .branch { player -> + if (inInventory(player, Items.LIMPWURT_ROOT_225)) { + if (amountInInventory(player, Items.LIMPWURT_ROOT_225) >= 20) { + return@branch 2 + } + return@branch 1 + } + return@branch 0 + }.let{ branch -> + branch.onValue(2) + .playerl(FacialExpression.FRIENDLY, "Yes, I've got them.") + .betweenStage { _, player, _, _ -> + removeItem(player, Item(Items.LIMPWURT_ROOT_225, 20)) + } + .iteml(Items.LIMPWURT_ROOT_225, "You give Winelda the limpwurt roots.") + .npcl(FacialExpression.FRIENDLY, "Good! Good! My potion is nearly ready! Bubble, bubble, toil and trouble!") + .npcl(FacialExpression.FRIENDLY, "Now we shows them ours magic! Hold on tight!") + .endWith { _, player -> + if(getQuestStage(player, TempleOfIkov.questName) == 4) { + setQuestStage(player, TempleOfIkov.questName, 5) + } + // There's a cutscene, but I'm lazy man. + teleport(player, Location(2664, 9876, 0)) + } + branch.onValue(1) + .playerl(FacialExpression.FRIENDLY, "I've got some limpwurt roots!") + .npcl(FacialExpression.FRIENDLY, "We needs 20 rooteses!") + .end() + branch.onValue(0) + .playerl(FacialExpression.FRIENDLY, "How many did you need again?") + .npcl(FacialExpression.FRIENDLY, "We needs 20 Limpwurt roots for pot.") + .end() + } + + b.onPredicate { _ -> true } + .npcl(FacialExpression.FRIENDLY, "Hehe! We see you're in a pickle!") + .npcl("Wants to be getting over the nasty lava do we?") + .options() + .let { optionBuilder -> + optionBuilder.option_playerl("Nah, not bothered!") + .npcl(FacialExpression.FRIENDLY, "Hehe! Ye'll come back! They always come back!") + .end() + optionBuilder.option_playerl("Yes we do!") + .npcl(FacialExpression.FRIENDLY, "Mocking us are we? Clever one aren't we?") + .npcl(FacialExpression.FRIENDLY, "I'm knowing some magic trickesses! I could get over easy as that!") + .npcl(FacialExpression.FRIENDLY, "Don't tell them! They always come! They pester poor Winelda!") + .playerl(FacialExpression.FRIENDLY, "If you're such a great witch, get me over!") + .npcl(FacialExpression.FRIENDLY, "See! They pester Winelda!") + .playerl(FacialExpression.FRIENDLY, "I can do something for you!") + .npcl(FacialExpression.FRIENDLY, "Good! Don't pester! Help!") + .npcl(FacialExpression.FRIENDLY, "Get Winelda 20 limpwurt roots for my pot.") + .npcl(FacialExpression.FRIENDLY, "Then we shows them some magic!") + .endWith { _, player -> + setAttribute(player, TempleOfIkov.attributeTalkedToWinelda, true) + } + optionBuilder.option_playerl("Yes I do!") + .npcl(FacialExpression.FRIENDLY, "I'm knowing some magic trickesses! I could get over easy as that!") + .npcl(FacialExpression.FRIENDLY, "Don't tell them! They always come! They pester poor Winelda!") + .playerl(FacialExpression.FRIENDLY, "If you're such a great witch, get me over!") + .npcl(FacialExpression.FRIENDLY, "See! They pester Winelda!") + .playerl(FacialExpression.FRIENDLY, "I can do something for you!") + .npcl(FacialExpression.FRIENDLY, "Good! Don't pester! Help!") + .npcl(FacialExpression.FRIENDLY, "Get Winelda 20 limpwurt roots for my pot.") + .npcl(FacialExpression.FRIENDLY, "Then we shows them some magic!") + .endWith { _, player -> + setAttribute(player, TempleOfIkov.attributeTalkedToWinelda, true) + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/whileguthixsleeps/WhileGuthixSleeps.kt b/Server/src/main/content/region/kandarin/quest/whileguthixsleeps/WhileGuthixSleeps.kt new file mode 100644 index 000000000..ca348787d --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/whileguthixsleeps/WhileGuthixSleeps.kt @@ -0,0 +1,85 @@ +package content.region.kandarin.quest.whileguthixsleeps + +import core.api.getQuestStage +import core.api.hasLevelStat +import core.api.isQuestComplete +import core.api.rewardXP +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.quest.Quest +import core.game.node.entity.skill.Skills +import core.plugin.Initializable +import org.rs09.consts.Items + +/** + * While Guthix Sleeps Quest + * + * Not completed. Here is the quest journal in color. https://www.youtube.com/watch?v=lOwoy45ywwA + * Uncomment the @Initializable when it's done. + * + */ +//@Initializable +class WhileGuthixSleeps : Quest("While Guthix Sleeps", 161, 160, 5,5491, 0, 1, 900) { + + companion object { + const val questName = "While Guthix Sleeps" + } + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + var line = 12 + var stage = getStage(player) + + var started = getQuestStage(player, questName) > 0 + + if (!started) { + line(player, "I can start this quest by speaking to !!Radimus Erkle?? in the", line++, false) + line(player, "!!Legends' Guild??, which is located in the !!north-east?? of", line++, false) + line(player, "!!Ardougne??", line++, false) + line++ + line(player, "To complete this quest, I need:", line++, false) + line(player, "!!Level 65 Defence??", line++, hasLevelStat(player, Skills.DEFENCE, 65)) + line(player, "!!Level 75 Magic??", line++, hasLevelStat(player, Skills.MAGIC, 75)) + line(player, "!!Level 65 Herblore??", line++, hasLevelStat(player, Skills.HERBLORE, 65)) + line(player, "!!Level 60 Thieving??", line++, hasLevelStat(player, Skills.THIEVING, 60)) + line(player, "!!Level 55 Hunter??", line++, hasLevelStat(player, Skills.HUNTER, 55)) + line(player, "!!Level 65 Farming??", line++, hasLevelStat(player, Skills.FARMING, 65)) + line(player, "!!Level 23 Summoning??", line++, hasLevelStat(player, Skills.SUMMONING, 23)) + line(player, "I also need to have completed the following quests:", line++, false) + line(player, "!!Recipe for Disaster??", line++, isQuestComplete(player, "Recipe for Disaster")) + line(player, "!!Mourning's Ends Part II - The Temple of Light??", line++, isQuestComplete(player, "Mourning's End Part II")) + line(player, "!!Swan Song??", line++, isQuestComplete(player, "Swan Song")) + line(player, "!!Zogre Flesh Eaters??", line++, isQuestComplete(player, "Zogre Flesh Eaters")) + line(player, "!!Path of Glouphrie??", line++, isQuestComplete(player, "Path of Glouphrie")) + line(player, "!!Summer's End??", line++, isQuestComplete(player, "Summer's End")) + line(player, "!!Legends' Quest??", line++, isQuestComplete(player, "Legends' Quest")) + line(player, "!!Dream Mentor??", line++, isQuestComplete(player, "Dream Mentor")) + line(player, "!!Hand in the Sand??", line++, isQuestComplete(player, "The Hand in the Sand")) + line(player, "!!Tears of Guthix??", line++, isQuestComplete(player, "Tears of Guthix")) + line(player, "!!King's Ransom??", line++, isQuestComplete(player, "King's Ransom")) + line(player, "!!Defender of Varrock??", line++, isQuestComplete(player, "Defender of Varrock")) + line(player, "!!Be eligible for entry to the Warriors' Guild??", line++) + line(player, "!!Defeated Bork in the Chaos Tunnels??", line++) + line(player, "!!And gain a total of 270 quest points.??", line++) + line(player, "I have all the !!stats?? and !!requirements?? needed to start and", line++) + line(player, "complete this quest.", line++) + } + } + + override fun finish(player: Player) { + var ln = 10 + super.finish(player) + player.packetDispatch.sendString("You have completed While Guthix Sleeps!", 277, 4) + player.packetDispatch.sendItemZoomOnInterface(Items.LONGBOW_839,230,277,5) + + drawReward(player, "5 Quest Points", ln++) + drawReward(player, "Lump of dragon metal.", ln++) + drawReward(player, "5000 coins.", ln++) + drawReward(player, "Talk to Idria to receive 4 x", ln++) + drawReward(player, "100,000 XP.", ln++) + drawReward(player, "Opportunity to loot Movario's", ln++) + drawReward(player, "base", ln++) + } + + override fun newInstance(`object`: Any?): Quest { + return this + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/morytania/quest/creatureoffenkenstrain/CreatureOfFenkenstrain.kt b/Server/src/main/content/region/morytania/quest/creatureoffenkenstrain/CreatureOfFenkenstrain.kt index 246e8db0c..3e3b3137b 100644 --- a/Server/src/main/content/region/morytania/quest/creatureoffenkenstrain/CreatureOfFenkenstrain.kt +++ b/Server/src/main/content/region/morytania/quest/creatureoffenkenstrain/CreatureOfFenkenstrain.kt @@ -1,6 +1,5 @@ package content.region.morytania.quest.creatureoffenkenstrain -import content.region.desert.quest.thegolem.TheGolemListeners import core.api.* import core.game.node.entity.player.link.quest.Quest import core.game.node.entity.player.Player